General Description

Note: boilerplate text, used here and elsewhere (excluding images) is all in "links1.doc" and is used for scrollback, SOSLIB, EXLIB, Num, String. There's no need to update on open.

A-Shell is a middleware tool that allows applications written in AlphaBASIC for the Alpha Micro Operating System (AMOS) to run in Windows, UNIX and Linux environments. A-Shell attempts to precisely replicate the AMOS environment on these alternate hardware platforms and provide total compatibility with AMOS programs. Additionally, A-Shell provides a variety of extensions and enhancements that are not part of the original AMOS environment and which may optionally be used by A-Shell programmers.

A-Shell is a continually evolving product and is under active development.

Data File Compatibility

Both random data files and ISAM 1.0 files (.IDA and .IDX) are 100% compatible between A-Shell and AMOS. It is possible to transfer them as direct binary images between machines.

Sequential files are compatible, but stored in the local operating system format. For AMOS, this means each end of line is marked with a Carriage return/Linefeed pair. This is true also of Windows, although sequential files can sometimes terminate with a ^Z end-of-file marker. Under UNIX, new lines are indicated with a single character, \n (linefeed). A-Shell is capable of reading both AMOS-format and host-system-format sequential files. All newly created files are normally written in the current host-system-format.

You can force A-Shell to use CRLF terminators in sequential output under UNIX by setting OPTIONS=CRNL in the miame.ini file; see Configuration for details.

Despite the minor format differences between sequential files on the various platforms, you can generally just transfer them between systems with no conversion, since all of the major A-Shell utilities (VUE, COMPIL, BASIC INPUT, etc.) will accept either format.

VUE will accept files with either style of line terminator and always write them back in the native format, providing another way to convert source programs if necessary. You can override the terminators used by VUE with the CRLF=<Boolean> entry in the INI.VUE file. Note that you should not save UNIX configuration files and scripts with CRLF terminators, and this may render them undecipherable to UNIX. If you are using the native operating system executable version of VUE for such, you can prevent this by creating an /etc/ini.vue file which contains CRLF=FALSE.

ISAM 2.0 or ISAM Plus files are implemented using C-ISAM by Informix or D-ISAM by Byte Designs. Because of this, the format of the data and indices are not compatible, and the files must be transferred by first dumping them with the AMOS version of ISMUTL.LIT, and then reloading them with the A-Shell version of ISMUTL.LIT.

For those who object to this procedure as being too slow, due to the need to manually run ISMUTL to generate the new files and especially due to the time it takes to dump the old files on some slower machines, we have developed a pair of utilities which speed up and simplify this process; see the SOSLIB.

Program Compatibility

The A-Shell runtime interpreter (RUN.LIT) is compatible with programs compiled under most versions of AMOS using either the 1.3 (OCMPIL.LIT) or 1.4 (COMPIL.LIT) compiler. It is not compatible with the RP files generated by BASIC Plus. On the source code side, the A-Shell compiler is compatible with all AlphaBASIC source code written for the version 1.3 compiler, and virtually all source code written for the version 1.4 compiler. (AlphaBASIC 1.4 is a moving target and thus it is difficult to claim total compatibility at any point in time, but as new statements are added to the AMOS version, they are soon added to the A-Shell version as well.) The A-Shell compiler also supports most of the BASIC Plus source code (but not the compiled object code.) See PLUS Extensions for details on which BASIC Plus code is supported.

The A-Shell compiler (either COMPIL or OCMPIL) will nearly always generate the exact same RUN file, right down to the hash code, as the corresponding AMOS COMPIL and OCMPIL will. Thus, except for BASIC Plus, you have compatibility in both directions for both your source code and compiled programs.

A-Shell and MIAME

A-Shell was originally developed as part of a larger system called the Machine Independent Alpha Micro Environment, "MIAME" for short (pronounced like the beach in Florida). MIAME is no longer considered a viable product or software environment apart from A-Shell, but many references to MIAME remain in the A-Shell system.


General Questions and Topics

This section provides information that may be of interest to people updating from older versions of A-Shell, or selecting a platform on which to run A-Shell, or moving A-Shell from one platform to another.

A brief note on the confusing language of "update" and "upgrade" and "conversion." In this documentation, we use the terms as follows:

• Update: this is a move from an older version of A-Shell to a newer version. It does NOT involve a software license, it does NOT provide additional options or features, it (generally) does NOT cost anything and you will probably not even notice any difference between the old and new versions. The purpose of an update is to keep your software "reasonably current" in relation to what the developers of A-Shell are working on and distributing. A-Shell is constantly being improved, in large ways and small, with bug fixes and new features, and it is generally a good idea to keep your copy up to date. There are exceptions and special considerations, of course.

• Upgrade: this is when you add features or capabilities to A-Shell, or when you increase the number of authorized users. Such changes generally require issuance of a new software license, and make your software "bigger" than it was before, in the sense that you have expanded its capabilities by either numbers or features. For example: A-Shell has an add-on bit of software called "PDFX" that allows you to easily create PDF files from reports. Adding PDFX to your system is an upgrade and requires a new license; see Updating the License if that's what you need to do.

• Conversion: this is a platform change from Windows to Linux or vice versa, or from any A-Shell platform to any other.

Also note that the information in this section frequently parallels and/or overlaps with the Installation documentation, which see for related details.

Subtopics

Updating A-Shell

Conversion: Linux to Windows 1

Conversion: Linux to Windows 2

Questions on ATE, ZTERM, SSH, Printing

Conversion: AM to PC File Transfer Problems


Updating A-Shell

A-Shell is an evolving software product, meaning that it is always changing. The developers of A-Shell work on it constantly, and new versions are churned out several times a month.

In order to bring some degree of order to what otherwise might be a fairly chaotic and never-ending confusion about updates, the A-Shell versions are segregated into two major categories:

• Stable: The stable version of A-Shell has not changed since its formal release date, which is usually months or years in the past. The software is being used by many firms, is recommended by MicroSabio, and can be counted on to not change. It is stable, dependable, reliable, risk-free. The only exception to the not-changing rule is bug fixes, which are usually minor and obscure.

• Development: The development version changes weekly or even daily, and incorporates an endless stream of improvements and new features. These changes rarely have any effect on existing programs, but it is at least possible that they might. Therefore, the development version is intended primarily for software developers who are interested in the latest features and improvements in A-Shell.

For most users of A-Shell and in most circumstances, the stable version is preferred. Although some organizations want to always have the latest and greatest version of the program, most prefer the stable version because it eliminates most of the risk of something going wrong. That risk is very low even with the development version, but it is even less with the stable version.

To determine what numerical versions equate to the current stable and development systems, please see the A-Shell downloads page here.

Version Numbering

A-Shell's version number consists of three parts, separated by periods. For example: 6.2.1412.

• First digit: in twenty-some years of development (as of 2016), A-Shell has had six "major major" version number changes. The current one is "6," and that will likely remain true for quite a while.

• Second digit: this indicates a "major" release of A-Shell. Also, there's another important element to this digit:

EVEN numbered versions are stable, ODD numbered versions are development. So A-Shell 4.7, 5.1, and 6.3, for example, were all development releases, whereas 4.6, 5.0, 6.2, etc., were all stable releases.

• Third digit: this indicates the "build" number of A-Shell, and shows at a glance how many times A-Shell has been recompiled / rebuilt and released to the world since its origin.

To determine the version number of your currently-running version of A-Shell, enter ABOUT or SYSTAT at the A-Shell prompt.

Updating

A-Shell is used in many different ways by many different kinds of organizations. Some have in-house programmers and technicians that keep A-Shell up to date, others rely on consultants or advisors, some have relationships with a computer dealer or reseller or other firm. You should make sure that the responsible person or firm is the one updating A-Shell.

Subtopics

What Version Should I Be Using?

Updating A-Shell Windows and ATE

Updating Linux

Updating SOSLIB and EXLIB


What Version Should I Be Using?

Unfortunately, there is no one-size-fits-all answer to this question. Possible—and only possible—answers are:

• Do you get your application software plus A-Shell from a dealer / reseller / consultant? Ask them about which version is right for you.

• Do you get A-Shell directly from MicroSabio? You likely should have the latest stable version.

• Are you a "bleeding edge" user or developer who always wants the latest version and the attendant risks? Get the very latest available version.

The best source of information about versions—latest, stable, historical—is the MicroSabio webpage that deals with that subject. Click on this link http://microsabio.com/downloads/ to go directly to that page.

Remember that A-Shell is being continually updated by the developers. In other words, the target is always moving and today's "latest stable" version might be—will certainly be, at some point—tomorrow's historical version. If you are the person in change of keeping your copy of A-Shell or ATE up to date, then you should probably be updating every few months.

Also note that it is up to you, the person installing the update, to know what you are doing! You need to determine if the update is required or recommended, and what problems you might encounter during the process. The normal answers are yes (recommended) and none (expected problems), but you are nonetheless responsible for the process. Caution is advised.


Updating A-Shell Windows and ATE

For A-Shell running under Windows, and for ATE, A-Shell has a very nice, clean, simple update mechanism. Here is pretty much everything you need to know:

In other words, go to the "Help" menu in A-Shell/Windows or ATE, and select "Check for Updates." The system will respond with something like this:

All you need to do is decide if you want to perform the suggested update. If yes, then A-Shell will download a new copy of itself and run the installation program.

That's really all there is to it, unless something goes wrong or you have special circumstances or needs. Be aware that A-Shell cannot update itself while it is running, so a dialog box will pop up and tell you to shut down A-Shell; simply exit A-Shell, and click on the "Retry" button.

If something DOES go wrong or you DO have special circumstances or needs, then please follow the directions for Linux updates but substitute "Windows" or "ATE" for "Linux version."

Note that the update process described here is actually the small tip of a very large iceberg of update controls and procedures. If you are a system administrator or other technical person who is responsible for updating large and/or many systems, please see the "Automatic Updating" discuss in the A-Shell ATE documentation.


Updating Linux

There is no "automatic" method for updating to Linux, but the manual update procedure is simple. This method also works for A-Shell/Windows, ATE, and all other supported versions of A-Shell.

• Determine which version you are using now, and which version you wish to update to. Make sure you know what you're doing here!

• Go to the MicroSabio distribution folder on our webserver, and view the directory contents. It should look something like this:

• "60rel" means "Version 6.0 standard release," etc. You will normally want to select the latest (highest numbered) release that is followed by "rel." Numbers followed by "dev" indicate an under-development version, which you are welcome to download but which has not yet been declared "stable."

• Click on the name of the applicable folder, such as "62rel" and see another folder display like this:

• Note the file install-notes-linux.txt which will apply to all Linux installations.

• The "el" numbers (EL5, EL7, etc.) refer to "Red Hat Enterprise Linux version #." The version number applies to Linux from any of the major distributions such as Red Hat and CentOS. The A-Shell versions are generally upward compatible (the EL5 version will run fine on EL6 or EL7 systems) and are generally NOT downward compatible (the EL7 version of A-Shell will not run on an EL4 system).

• Again, click on the name of the applicable folder, such as "bin-linux-el7" and see another folder display like this:

• To get the latest version, click—sometimes twice—on the "Last modified" column header that the files will be sorted by date. Unless you have reason for not doing so, you should also download the latest available version.

• To download the file(s) you need, simply click on them. Go back up the directory tree to read the installation instructions if needed.

• "EFS" in the file/folder name refers to A-Shell Encrypted File System. You generally do NOT want to use this version, unless of course you do.

• See the documentation on UNIX / Linux Installation for more information about the "bin" and "tz" file types and how to deal with them.


Updating SOSLIB and EXLIB

SOSLIB and EXLIB are libraries of files that will be of interest only to A-Shell developers, programmers and resellers. These libraries are updated by copying new versions over the top of previous versions. Click on the links at the beginning of this paragraph for information on where to find the current copies of the libraries.


Conversion: Linux to Windows 1

From a Microsabio bulletin board discussion of November 2012

Question

My client is running A=Shell 4.8 on Linux, and is considering moving to Windows. They have approximately ten users on the system, and we originally went with Linux because it was a better choice than Windows for that many users. However, that was more than ten years ago.

Would Windows now be reasonable for ten users? And if we convert to Windows, how much recompiling of their .BAS files will be required?

Reply

There is a range of possibilities for a Windows environment (P2P workgroup, domain server, ATS, Terminal Server), but all of them would work fine for 10 users if properly configured.

Most AlphaBASIC applications are disk-bound, rather than CPU bound, and rely on shared access to files with some kind of locking scheme. So in choosing a configuration, you should give more consideration to that aspect of performance.

The peer-to-peer (P2P) workgroup is the simplest and probably the cheapest Windows configuration, but has the lowest file I/O performance and the greatest exposure to network problems, particularly if different versions of Windows are in the mix.

A domain server is a step up in terms of overall network reliability, but not a big step in file i/o performance.

The ATSD (A-Shell Telnet Server) and Windows Terminal Server (along with its competitors - Citrix, etc.) put all the CPU and file activity load on the server (as in Linux), but end up giving you much better performance by eliminating all the network file sharing overhead. Given the same hardware, Linux will still be faster, but the point is probably moot given the performance of modern hardware.

If your server is old, tired, or short on memory, ATSD might be a better choice since it has relatively tiny overhead (less than 10 MB per connection), and is probably cheaper. But any decent modern server with 4GB+ of RAM and a quad-core CPU can easily handle ten Terminal Services connections, and does give more flexibility in client devices.

Note that ATSD, unlike Windows Terminal Server and its ilk, does not strictly require a "server" version of Windows; an ordinary "professional" version will work just as well, at least from A-Shell's perspective, for a system of modest size. This can further reduce your costs for licensing and the expertise required, if you don't have any other reason to use the features of a true Windows "server". At some point, perhaps above 20 users, the advantages of the "server" editions in terms of resource management become more substantial or even necessary.

As for the recompiling, you may not need any, either for the platform change or the A-Shell update. Regarding the platform, the only issue would be if your application had extensions that specifically related to the UNIX environment (e.g., referenced native filespecs, launched native LINUX commands via HOSTEX, etc.) As for the update, the old RUN format is still supported by both the runtime interpreter and the compiler. It's always possible though that in the intervening updates between 4.8 and the current 6.0, some fix, change or enhancement might inadvertently affect your app.

The main compatibility issue that I know of is the switch from octal to decimal for the [p,pn] system in 5.0. This was done to expand the range of ppns from 255x255 to 999x999, which was important to some developers with large sites subdivided by ppns into companies, departments, profit centers, etc. The change does not affect RUN programs per se, unless you used an XCALL to manipulate ppns that stored each as a single binary byte. Obviously, to handle 999, you need either two bytes or a three-character string.) If unsure whether that might be an issue, you should probably grep your source for XCALLs and generate a list of all the different XCALLs you use, which you could either look up in our documentation or send to us for review. Fortunately it's usually pretty easy to swap out or upgrade such calls, assuming it's even an issue at all.


Conversion: Linux to Windows 2

From a Microsabio bulletin board discussion of December 2012

Question

Does it make sense performance-wise to switch from Red Hat Linux to Windows Server for an A-Shell system which typically has 70 users running programs on it at the same time?

Reply

Given the same hardware, Linux handily outperforms Windows, particularly in larger environments like yours. That said, there are a number of possibly mitigating or extenuating considerations:

1. Windows peer-to-peer should be ruled out of hand for this size system. So we'll assume some kind of server-based model (Windows Terminal Server, Citrix, GoGlobal, ATSD, etc.) for the remainder of the discussion.

Note that these server-based models divide into two completely different categories, what I'll call RDP-style (Windows Terminal Server, Citrix, GoGlobal, etc.) and Telnet-style (ATSD). For the RDP-style (they don't all used RDP specifically, but the concept is the same), the logical screen (within the server) is replicated to the client screen by some pixel-based protocol. As opposed to the Telnet-style case where the server sends characters (bytes) to the client, which is responsible for maintaining its own state and updating the display based on the logic of the character and character-based commands that arrive. The input channel is pretty much the same for the two variations.

2. For RDP-style protocols, you'll need a much bigger server than you would for Linux, or for ATSD, because each connection is essentially a full-blown Windows environment on the server. It's not easy to estimate those memory requirements, but as a very rough approximation, I would take the MEMORY partition size specified in the miame.ini and add about 10MB per telnet/ATSD connection, and about 50MB per RDP-class connection. That would be for plain text applications. Add another 10-20MB for GUI.

3. In the old days, you'd have to squint very carefully at the previous paragraph. Nowadays, you may just get a server with 16GB RAM and not sweat the details.

4. Likewise for CPU - in the Windows environment, all the display operations are GUI/pixel-oriented (as opposed to byte-oriented in the Linux/ssh environment - even when using ATE for a GUI front end), so it takes a lot more CPU power to update displays. So while a single core Pentium could manage your 70 Linux users, you'd want 8 cores or more for the Windows equivalent. But again, that's no big deal these days, so maybe another meaningless detail not to sweat over.

5. If you go with an RDP-style environment (as opposed to sticking with telnet), you're probably looking at substantial licensing costs. (On the other hand, maybe all those workstations already have client licenses for other reasons, in which case the additional cost may be minimal.)

6. A-Shell GUI operations in the RDP-style environment are actually simpler than in the telnet/ATE environment, because it acts more or less just like the Windows standalone environment. (The AUI layer which converts GUI calls into ATE messages, relays them to the client, and processes the responses, is bypassed. Instead, there is a more seamless screen-replication layer, which may involve more raw bits being transferred, but for many GUI operations is actually more efficient. Plus you eliminate the latency delays involved when an ATE command requires a response from the client.)

7. For plain text applications, the situation is somewhat reversed. ATSD/telnet style communications are generally much more efficient than the RDP-style remote screen replication when it comes to displaying characters. The one exception is scrolling (like in long DIR or TYPE operation) where, in the telnet case, every byte must be transferred, whereas in the RDP case, the scroll may not be as smooth, but it can effectively skip much of the updating by just resynchronizing the display at the end of the scroll. (Admittedly this is a special case, but I do get asked why scrolling displays take longer with byte-oriented telnet than with bit-oriented RDP.)

Fortunately, if you already have a Windows server at the site, which it sounds like you do, you can probably experiment on it without a lot of investment. Particularly if you're leaning towards the Terminal Server approach and already have it installed on another server, just install a demo copy of A-Shell/Windows on it and make an RDP connection to it. You may be able to get a preliminary feel for the performance just by playing with VUE, DIR, and some of the programs in the EXLIB. If you're leaning towards keeping the present telnet clients, you'll have to install ATSD, but that isn't very difficult either.

As for version, existing Windows Server installations of A-Shell range from W2000 to W2003 to W2008 to W2012. Although there are plenty of differences in Windows from one version to the next, those differences don't seem to matter much to A-Shell. In fact, if you use the ATSD/TELNET configuration, you don't absolutely need a real "Server" version of Windows; the "professional" version will work. For the relatively large system of 75 users, however, the server versions may provide better environmental support in terms of resource management, security, etc.

Caveat: We have a couple of Windows server sites in the vicinity of 50 users, but yours might well be the biggest ever. In contrast, we have many Linux sites with hundreds of users.


Questions on ATE, ZTERM, SSH, Printing

A new A-Shell client, who is converting from an AMOS system, asks several questions:

• Do we really need to use ZTERM, or is connecting to the host using any ssh client and starting A-Shell from there sufficient? I ask this because previously the users connected to the AMOS box using an ssh tunnel and ZTERM on top of that. I want to get rid of that scheme in favor of something simpler which I think it could be done just by an ssh session.

• In the same topic, the FTP configuration is something I would like to change to a SFTP connection to the host box (Linux in this case) with an user jailed to the disk directories of A-Shell. Do you think this approach would have a problem when comparing to using the TCP/IP support of AMOS? Again I am trying to prevent the tunneling and going straight to the box using the ssh stack as much as possible.

• Does A-Shell printing depend on any particular terminal emulation(s)?

Following are extended discussions on each of these topics.

I'm glad you asked about ZTERM, because I was under the impression that the client was actually committed to it. We still sell it due to a long-time agreement with the developer, but because he stopped doing any support or development on it more than a decade ago, we decided to create our own emulator. That A-Shell-based emulator is called ATE (A-Shell Terminal Emulator), and we fully support it as well as modernize/enhance the capabilities as time goes by. One of those being proper SSH2 / SFTP support! Another is the enhanced printing capabilities, both in redirecting Linux print requests via the Windows system, as well as supporting preview, print-to-PDF, print-to-email, etc., that I may have referred to in a previous message.

Perhaps the biggest enhancements are in the area of GUI support, but I gather that the client's application currently has no need for GUI. Whether they are interested in adding some GUI enhancements to the application, I have no idea, and it may not be your concern either. But if you or the client expect to be using the application for a long time into the future, those GUI capabilities become ever more important. So take note!

But even apart from "GUI-fyng" the application per se, there may be areas where they might benefit from improved communication capabilities between the application running on Linux and the resources of the Windows environment. There is a reasonably coherent summary of ATE on the Micrrosabio ATE page, and there is a list of extended TAB(-10,x) commands the A-Shell reference to give some idea of the kinds of server-to-client commands that are available. Many of these overlap the ZTERM ESCAPE Sequence commands, in which case ATE also supports the same ESCAPE sequences for upward compatibility.)

Most of the A-Shell/ZTERM users have migrated to ATE, and nearly all of the new A-Shell/Linux users choose ATE. But, it is a commercial product with a cost associated; you can see the prices on our website. To avoid those costs, or due to prior preference, some sites use other emulators, ranging from commercial ones like Anzio and AlphaLAN, to free/open-source emulators like Putty. As long as the emulator supports an emulation that is compatible with A-Shell and the features used by the application, it should work. The specific emulations that A-Shell supports are the AMOS emulations (AM62A, AM62C, AM65, AM75), plus WYSE50. It also supports a "generic" terminal emulation that works through the Linux TERMINFO database, allowing emulations that are known to Linux, such as VT220, VT320, etc. to function, although the capabilities are generally pretty limited. (The AMOS terminal driver system was quite advanced for its time and encouraged applications to take advantage of terminal features; the scheme was theoretically terminal independent, except that they then came out with their own line of terminals which certain tweaked capabilities to coerce most users into buying the more expensive AMOS terminals.) I haven't seen your application, so I don't know what features are being used, except that I do know that it uses the protected fields, i.e. TAB(-1,13) and TAB(-1,14), which probably rules out the use of generic emulations. Other features that are common in AMOS applications but possibly dependent on the AMOS terminal emulations are insert/delete, line drawing, save/restore, and status lines. Although it may be somewhat self-serving, my general opinion is that the difference in cost between ATE and a free emulator typically isn't worth the effort to identify and work around these issues, not to mention losing access to some of the really useful features, like printing.

Regarding printing, no, A-Shell does not depend on any terminal emulator for printing. Printers can be defined to Linux, similar to how they are defined to AMOS, and A-Shell can print to those printers via PRINT.LIT or XCALL SPOOL, just like it does under AMOS. A text configuration file is used to associate the logical printer name known to the application, with the system print queue name known to the Linux operating system. The ability to print back to the terminal, for redirection to real or virtual Windows print devices, is just a bonus.

Regarding the SSH tunnel and SFTP, I agree that getting rid of the tunnel would make your life easier. Since ATE (and other emulators like Putty) support SSH2, there is no need to use a tunnel; just SSH directly to the server. In the case of ATE, you can launch SFTP transfers via the same SSH terminal channel/port, which also simplifies firewalls. Jailing or sandboxing the users is possible in the normal way, based on the way you configure the SFTP service on the server, but if the application is driving those transfers (using the ZTERM ESCAPE sequences), then it probably assumes that the SFTP home directory is the real home directory, so re-homing might require some slight modification to that code, if it exists.

One feature which ATE does not offer, but ZTERM does, is an interactive file transfer user interface. We deliberately excluded that because we felt that in most cases, it was an invitation to abuse, i.e. it was better to limit file transfers via the application logic, rather than to encourage users to transfer files back and forth unsupervised. But if that's the way you like to work, we recommend using one of the free SFTP-capable file transfer clients, such as FileZilla. One of our A-Shell developers also makes available a free one called MadFTP which has some features to make it integrate slightly better with A-Shell, i.e. sharing the login, knowledge of A-Shell directories, etc. But it isn't quite as sophisticated/powerful as FileZilla. Either one can be put on to the ATE menu bar via a simple application startup command, so further integrate it into the terminal environment, if so desired.

Another detail I forgot to mention earlier about file transfers: A-Shell supports the ZTXFER.LIT command that may be used from the AMOS dot prompt (or A-Shell dot prompt) to transfer files, as an alternative to the application-driven transfer method. ZTXFER with no arguments gives the help info:

.ZTXFER

ZTXFER usage:

To send from Host to PC:

ZTXFER{/switches} host-name PC-name or ZTXFER{/switches} host-name

To send from PC to Host:

ZTXFER{/switches}{a host-name=PC-name or ZTXFER{/switches} =PC-name

Switches:

/A forces ASCII mode

/2 requests new FTP/SFTP implementation if avail (faster)

/ATE use ATE terminal channel (automatic for PC -> ATSD)

Source file name may contain * wildcard (ATE/UNIX only; no /2)

For example:

.ZTXFER AAA.BBB c:\temp\AAA.BBB

.ZTXFER CCC.DDD = c:\temp\AAA.BBB

The above would transfer the AAA.BBB file from the current directory to C:\TEMP\AAA.BBB, and then transfer it back to CCC.DDD

The file transfer protocol and authentication would be determined by terminal emulator configuration; for ZTERM it would be FTP; for ATE it would be SFTP.

But, as I mentioned before, the assumption within ZTXFER is that the current directory as seen by the application, matches the directory as it would be seen by the {S}FTP server. If that were not true because of of jailing/sandboxing/re-homing, an adjustment would have to be made somewhere to convert from one to the other. (It wouldn't be too difficult, but would require some tinkering.)


Conversion: AM to PC File Transfer Problems

A client attempt to transfer files from an Alpha Micro to a PC using ZTGERM, on the way to their happy future with A-Shell, reports the following:

I am not having much success with ZTXFER. I have programmed and built command files for porting over my clients files from the Alpha to a Win7 Pro workstation using the ZTXFER program. Major issues. It runs exceeding slow, maybe 2 kbs per second. It also fails about every 5th transfer. It especially fails on .dat and .mmo files (do I need the /C switch?), however some port ok. Most frustrating is if it fails there is no way to either cancel , exit, reset terminal, etc. If I use task manager to end task it will stop but as soon as I open ZTERM again it just keeps going until it fails again.

Our response to the client was:

The /C switch for ZTXFER only applies when copying to AMOS, not from, so that's not an issue here.

Our best guess as to the cause of the lockup is handshaking, i.e. that the serial connection from the ZTERM workstation to the Alpha is not wired for RTS/CTS handshaking, and/or ZTERM has not been configured for that handshaking. As a rule, XON/XOFF is not reliable with file transfers, and file transfers are not reliable without working handshaking. The symptom is typically the one reported, i.e. it works for a few files and then locks up.

A good way to test handshaking is with a barber pole display, like this one:

program BARBER,1.0(100) ! barber poll

MAP1 I,F

MAP1 BAR$,S,79

? tab(-1,99);  ! smooth scroll (probably not supported, but no harm to try)

FOR I = 33 TO 111

    BAR$ = BAR$ + chr(I)

NEXT I

FOR I = 1 TO 1000

    ? BAR$

    BAR$ = BAR$[2,-1] + BAR$[1,1]

NEXT I

END

That should output about 80K characters, which should take about 40 seconds as 19200 baud, or 20 at 38400. If the handshaking isn't working, it will probably become scrambled noticeably after several seconds. Until you can get that to work reliably, file transfer is going to be painful.

Other than improving the baud rate, about the only other thing you can do is run it on multiple terminals at the same time in parallel. I remember once doing a conversion like this with 5 transfers running, and me going around from one to the next to check on them, move to new PPNS, restart after errors, etc. for the better part of a weekend.)

Of course getting ethernet working will make it a hundred times faster, at least, so it's worth a little effort. But I don't know much about the hardware of a 2000VME machine. One tip: if you do get it working, you'll need to add the -n switch to the FTPD startup so that FTP will be compatible with the weird AMOS DEV:[P,PN] syntax.


Installation

This section describes the procedure for physically installing the software on your computer. Since the procedures differ slightly between Windows and UNIX/Linux, each is described separately.

If you are updating A-Shell as opposed to doing an original installation, also refer to the separate though frequently overlapping documentation on General Questions and Topics.

Subtopics

Before Installation

Windows Installation

UNIX / Linux Installation

After Installation


Before Installation

Read these introductory notes and make sure you are aware of the various issues involved before beginning the installation.

Subtopics

File System Setup

Installation Overview

Security Key

Updating

Multiple Installations

Development vs. Runtime

Hardware and Performance


File System Setup

Although A-Shell itself can exist in any directories, for system administration purposes is may be wise to try to separate it from other application and operating system directories, if possible. This is less of an issue under Windows, where you typically have only one file system (or partition) available, and thus the best separation you can achieve is to give A-Shell its own directory tree, and possibly its own share name. Under UNIX on the other hand, it is normal to have multiple file systems, and there are some particularly good reasons for defining one or more individual file systems to keep A-Shell separate from the rest of the operating system:

• Individual file systems can be separately backed up and restored.

• Separate file systems are naturally insulated from each other, so that any corruption that occurs in one will not spill over to another. (This will not only protect A-Shell from problems caused by some other application but also protect you from being accused by your system administrator of allowing your application to corrupt the system.)

• Since different file systems can be mounted at the same mount point (though not at the same time), you have the ability to easily switch to another version of your data or application (backup, test, archive, etc.) temporarily without making any changes to A-Shell or your application. (This works best when you have "extra" scratch file systems available which you can restore a tape to.)

• Putting your A-Shell application in a separate file system will eliminate the possibility that you can bring the system down by filling up the disk. You may still cause your application to halt when it runs out of space, but the operating system will not be affected.


Installation Overview

In essence, there are two separate sets of files which are installed: the A-Shell runtime system, consisting of the AMOS emulation command programs and the A-Shell module itself, and the development system, consisting of the object modules and source to a user-defined XCALL module, enabling XCALL subroutines to be developed. Since the second set of files is usually offered as an added-cost option, most users will only need to concern themselves with the first set.


Security Key

After installation, it is necessary to install the security key that was supplied at the time of purchase. This process is described later in this section. If you don’t have a security key, the software will run in demo mode, which is fully functional except for nag messages (which will eventually drive you crazy) and the single user limitation.


Updating

If you are updating an existing A-Shell installation, you should follow the same process as for an original installation. Under all operating systems, the installation process will detect that (or ask if) an update is being performed and will not overwrite any existing configuration files. Any configuration files that might have new fields added, or differing formats, are stored in example form with .new extensions. If the function key translation tables are updated, the original ones will be saved with .ifs (.ifx) and .vus (.vux) extensions.

The ash_install script used for installing and updating A-Shell under UNIX will execute two special customization scripts (pre_ash_install and post_ash_install) if they exist in the custom subdirectory of the specified target directory tree. These allow you to customize the update process, perhaps saving, renaming, or removing certain commands or files, etc. See the sample scripts included with the release for further notes and examples.

Also See

• Updating A-Shell


Multiple Installations

It is possible to install A-Shell several times on a single machine, in different paths, which enables multiple virtual Alpha Micro environments to be set up. While not recommended for end-users running A-Shell as a single-purpose application, multiple environments can be very useful for developers/resellers when trying to duplicate customer site configurations. The recommended directory structure is to have all virtual machines located in the \VM or /vm directory. Each A-Shell installation would live one directory level below this identified by its machine name and the MIAME environment variable pointing to this subdirectory. It is recommended that the first A-Shell installation on a machine be made in the default directory \VM\MIAME or /vm/miame.


Development vs. Runtime

The question of development vs. runtime causes a good deal of confusion. Up through the present version, and for the foreseeable future, the BASIC development tools (i.e. COMPIL and VUE) are included as part of the standard runtime package which everyone gets. What isn’t included is the Developer’s Kit whose purpose is to allow developers to add their own subroutine extensions to A-Shell. This option is available for most platforms as an add-on package, but due to the many issues that complicate the matter, its installation is not discussed in this document. Contact MicroSabio for further details.


Hardware and Performance

In May 2007, an A-Shell developer started a big new project and asked our advice about the fastest kind of computer on which to run an A-Shell application. The application will have lots of users and very large files. I don't have enough experience with different hardware environments to be able to give an absolutely definitive answer—and in fact, doubt that anyone could do so. But a mixture of incidental and anecdotal experiences, along with some theoretical knowledge, have led me to the following prejudices:

Platform

Linux is far faster than Windows. I'm less sure about how Linux compares with AIX, although our largest systems in the field—over 500 users—do happen to all be AIX.

From FDM in Florida, May2007: We are a dedicated Linux shop, and it is extremely fast and robust. It bogs down when using the main console, though, so don't throw any activity there.

CPU

Dual CPUs are better than a single dual-core CPU. This is logical because A-Shell is single-threaded. Two A-Shell instances can each run on one of the separate CPUs, but I don't think they can share the cores of a single CPU. Dual core may have other benefits though, certainly for OS kernel code, and nowadays are practically standard. 64 bit CPUs do not offer any significant advantage for A-Shell.

Memory

From FDM in Florida, May2007: I would definitely splurge on extra RAM, and go with at least 2GB. Linux caches very well, and often repeat disk requests don't even hit the hard drive. (A-Shell also caches well, if you have all the tweaks setup in miame.ini.)

Disk Drives

SCSI or SAS is faster than SATA, particularly when there are queued requests, although perhaps this difference is minimized in very high-end RAID environments. SCSI is also more expensive, but the drives seem to have fewer failures. 15K RPM drives are significantly faster than 10K, since that reduces the average latency (involved in every random access) from 6ms to 4ms. With average seek times in the range of 7ms, those extra 2ms are significant.

From TJ in Sacramento, May2007: 15K drives run much hotter than 10K drives, therefore the enclosure must have positive disk drive ventilation.

Disk Dollars

A-Shell applications are almost always disk-bound before they are CPU-bound. Thus, money should be directed towards the fastest disks, rather than just the highest CPU MHz—which, as you'll notice, is how inexpensive systems are always advertised.

RAID

In most cases, simple mirroring (RAID 1) is faster than striping (RAID 0, 5, etc), because a smart controller can seek independently from either physical disk. Having multiple independent disks (or mirrors) is better than a single disk subsystem, for the same reason. Put the OS on one disk (or mirror unit), the app on another, or perhaps split the most commonly accessed files in the app on to different physical disks.

From TJ in Sacramento, May2007: I've recently started using RAID 10 for my high performance installs. This is a mirror of striped drives. I was very surprised when I first benchmarked this configuration. This was MUCH faster than a RAID 5 and 10% faster than a RAID 1 for writes and almost 20% faster for reads. This does require 4 drives to net 2 but it really made a big difference.

Configuration and Design

Application configuration and design may make as much of a difference as hardware, and is difficult to give general advice about. But here are a couple of pointers anyway:

• Don't put too many files in one directory. After several hundred, performance really starts to suffer. Use more directories instead. This is a common problem, where people create sequentially-named output files by the thousands and just put them all in one big directory with the rest of the application files—and then wonder why performance tanks.

• For large files, ISAM is much better than binary search schemes like SERCH.SBR. (A 64K record lookup will take 16 disk accesses in SERCH.SBR, and probably only 4 in ISAM.) An exception might be if you can memory-map the index file, since memory-mapped i/o is so much faster than ordinary i/o.

More Information

Given the pace of change in the computer hardware environment, the information presented above may be accurate or hopelessly out of date. For more information and the latest discussions on this subject, see the relevant discussions on the A-Shell Forum.


Windows Installation

For purposes of A-Shell installation there are basically three types of Windows environments:

• Single users

• Local area networks (LANs) of modest size.

• Other networks: this broad category includes large LANs, WANs, networks with remote users, networks where multi-user access and/or network traffic are significant concerns, and every other network situation that is other than the two simple environments mentioned above. See Windows Performance for more information.

Single User Installation

A-Shell/Windows is normally downloaded from the MicroSabio web site and installed on a PC like any other Windows program. To install, follow the normal Windows software installation procedure—that is, download the appropriate Windows installation program from the MicroSabio downloads page and then run program, following the prompts and answering the questions. The installation procedure will optionally create a shortcut for launching A-Shell, and you're off and running. The final step is to run A-Shell, go to Help...Check for Updates, and install the latest version of the software.

Subtopics

Windows Network Installation

File Locations

Installation Problems

Machine Names

Drive Mapping

Windows Printers

Windows Performance


Windows Network Installation

Most Windows instances of A-Shell are installed into relatively small local area networks, with or without a central file server. If this is your situation, then you're in the right place. If your network situation is more complex, see Windows Performance.

Note that "server" as used in the following discussion does not mean "dedicated Windows Small Business Server" or any other centralized computer upon which the other computers in the network are dependent. It simply means "the place where A-Shell data files and programs are located." This CAN be a dedicated file server, but it can also be just one of the regular PCs on the network that has been designated as the location of the A-Shell data and programs.

The objectives in a typical Windows installation of A-Shell are simple and straightforward:

• Have a shortcut or start-menu item on each PC so that the user can quickly and easily get A-Shell running

• Load application data and programs on a server so they are accessible by all PCs running A-Shell

• Create an environment for easy, manageable and coherent A-Shell updates in the future

The shortcut that executes A-Shell can retrieve the A-Shell program from either the local PC or the server. Which is better? Well, that depends.

• Do you have an old / tired / slow network, such that you do everything possible to minimize "get from server" calls? Then putting A-Shell on the local PCs makes more sense.

• Do you have a modern, 100-MB (or faster) network where everything is always loaded off the server? Then put A-Shell on the server too.

• When it comes time to update A-Shell, do you want each individual PC user to update at her convenience, and to make her own decision to update? If yes, then install A-Shell on the individual PCs.

• Do you want to control future updates of A-Shell from a central location—which requires making everybody on the network stop using A-Shell so you can update? If yes, then put A-Shell on the server.

As you can see, there are variables involved—and there is no right or wrong way to do this.

Subtopics

Recommended Steps

Alternative Steps


Recommended Steps

In most cases, and in the absence of information suggesting otherwise, MicroSabio recommends that the A-Shell installation program be run FROM EACH of the PCs that will be running A-Shell. While this seems a little redundant, and is in fact a little redundant, there are reasons for doing it this way. So here are the recommended steps:

1 Create the folder on the server where A-Shell is to be installed. You can use any name you want, but MicroSabio recommends—for historical purposes and the sake of consistency—the folder "VM." You also need to create a network share, which should also be named "VM." Note: DO NOT share the entire c:\ drive; this is guaranteed to create headaches.

2 Working on one of the workstation PCs (not the server), download the applicable version of A-Shell for Windows from the MicroSabio downloads page .

3 From the workstation, install A-Shell by running the installation program. When asked for the location into which to install A-Shell, enter: \\servername\VM\miame. As you will see the "\vm\miame\" part is already included; just replace c:\ with \\servername\.

4 Finish running the installation program.

5 Run A-Shell to confirm that all is well. A few LOG and DIR commands is enough. What we're confirming is that the desktop shortcut you created actually executes A-Shell as intended, and that the miame.ini file—A-Shell's initialization file, like AMOSL.INI—is being found and processed. Don't proceed until you're happy and convinced that all is working, by which we mean that you click on the desktop shortcut and A-Shell runs as expected.

At this point, the workstation you've been working on should be perfectly set up for A-Shell, and you know how to run the installation procedure. Now go run it again—the same steps, starting with #2 above—on each of the PCs that will be using A-Shell.

It would appear that you are installing the same software into the same location multiple times. That is actually true. But the installation program is smart and knows to not actually copy files that are already present and up to date, and the installation is being rerun not for the A-Shell files but for Windows files over which A-Shell has no control. Subsequent installations will be much faster than the first one, and at the end of the process each PC will be properly and completely set up.

The final step of the process is performed after you have finished installing A-Shell from each of the PCs. It does not matter which PC runs this procedure, but it needs to be done after all the installations.

6 While running A-Shell, go to Help...Check for Updates. This will insure that you have the latest copy of A-Shell on the server. Run the installation as you have the other times, and you're done. You only need to run this once, and not from each PC.

Note that you must not run A-Shell from any one PC while you are installing from another PC.

Also note that despite the multiple installations, all the PCs are running off the same server-based copy of A-Shell.


Alternative Steps

It is perfectly fine to install a unique (not shared) copy of A-Shell on each PC, if you think there will be some benefit from that approach. One possible reason for this approach is that you want individual PC users to be in charge of their own updates. Obviously, each user must be running her own copy if she wants her own update.

When you run the A-Shell installation program, use the default install-to directory of c:\vm\miame. This puts a copy of all the A-Shell files on the local machine, and the miame.ini initialization file will be configured to run that copy of A-Shell.

However, you must manually modify the Windows shortcut or start menu command that invokes A-Shell so that it knows to look on the server for the initialization file miame.ini.

Refer to Installation Problems and the discussions about miame.ini for information on the necessary modifications and, if necessary, troubleshooting steps.


File Locations

By default, most Windows programs install themselves in a folder called c:\program files\<company name>\<program name>. A-Shell, by contrast, installs itself in the folder c:\vm\miame, although this can be changed by the user at the time of installation. If you need or want to change the installation directory, you can do so without penalty or complication. However, A-Shell uses its unconventional installation directory tree for historical and functional reasons, and you should make sure you know what you're doing before changing the installation folder. This is especially true if other people or computers are involved in your A-Shell environment.

A-Shell does not use the Windows registry to record its settings or location or anything else. All configuration information for A-Shell is contained in A-Shell's configuration files, so you don't need to be concerned about changing values in the registry when you move, backup, delete or reinstall A-Shell. Note to ATE users: this is not true for ATE—i.e., ATE does make registry entries; use appropriate caution.

A-Shell may be installed multiple times on a PC. If it is installed in different folders, and you can keep the start-up icons and commands separate, then different versions of A-Shell can exist and run on the PC without problem. If you install a new version over the top of an old one (i.e., into the directory where A-Shell already exists), then obviously the old program files will be overwritten with the new ones. Note, however, than none of the configuration files will be overwritten, and all of your previous settings and values—including anything written onto A-Shell disks and other devices— will be preserved.


Installation Problems

There is very little that can go wrong during a Windows installation of A-Shell, and it is likely that if something does go wrong, the problem is related to something unexpected done by the installer. Unless there were some problems during the installation process itself, and the files A-Shell requires in order to run were not actually installed on the PC, there are basically two places to look for problems.

Config File

First, make sure you understand the A-Shell Configuration File and how it works. If A-Shell does not start up properly, it is likely that some file specification in miame.ini is pointing at a wrong or non-existent location, or a required command in the ini file is misformatted or misspelledd.

Start Command

Secondly, check the Windows start command (shortcut) that is invoking A-Shell. The command line should have two parts, as shown below. Note that if the path in which A-Shell was installed includes spaces (like "Program Files"), then the file specs on the target line will (and must) have quotes around them.

• The first part of the command line specifies the file specification of the program to run—i.e., A-Shell. The program name is "ASHW32.exe" and it should be at the end of a file specification that begins with "c:\...." If A-Shell was installed in the c:\vm\miame folder, for example, the first part of the target command should look like this:

C:\vm\miame\bin\ASHW32.exe

• The second part of the target line, which begins after the first part and a space, should begin with "-i" and be followed by a space and the full file specification for the A-Shell initialization file (normally "miame.ini"). If A-Shell were installed as above, then the second part of the target line would look like this:

-i C:\vm\miame\miame.ini

If A-Shell were installed in the C:\Program Files\MicroSabio\Ashell folder, the full command line should look like this:

"C:\Program Files\MicroSabio\Ashell\bin\ASHW32.exe" -i "c:\program files\microsabio\ashell\miame.ini"

The "Start In" specification of the A-Shell shortcut should be blank.

If you need more tips to get A-Shell running, see the following sections that discuss specific errors you may encounter.

Subtopics

Missing or invalid MIAME

Cannot INIT DSK0

Commands Will Not Execute


Missing or invalid MIAME

If you see this error, it is because A-Shell is trying to run but cannot find or process the required initialization file (normally "miame.ini"). This would normally indicate that the "-i <ini file spec>" argument on the launch command line is missing or incorrect. See Specify INI File for related information.

missing miame this is NOT linked

A similar and related error message for a missing ini file is shown below. This normally occurs if A-Shell has previously been set up properly and has run as expected, but the ini file has been moved or renamed.

this is a NOT linked file


Cannot INIT DSK0

This error (below) normally occurs when the statement in your miame.ini file that specifies the location of DSK0: is entirely missing. The three lines below show what happens as A-Shell tries to execute A-Shell's default startup command, ASTART, and there is no DSK0: on which to find that file. Solving this problem should be easy; simply add the DEVICE statement in miame.ini, or perhaps remove the semicolon in front of it that is turning it into an inactive command (i.e., a comment).

?Cannot INIT DSK0:ASTART.CMD[2,2] - device does not exist

?Cannot INIT DSK0:ASTART.DO[2,2] - device does not exist

?Cannot INIT DSK0:ASTART.LIT[2,2] - device does not exist

A properly formatted statement in miame.ini for defining DSK0: would look like either of these:

DEVICE=DSK0 "c:\program files\microsabio\ashell\DSK0\" ; Pathname for DSK0:

DEVICE=DSK0 c:vm\miame\dsk0\


Commands Will Not Execute

If you get a screen like the one shown here, it normally means that your DEVICE=DSK0: statement is present but invalid. The problem is likely a misspelling or bad punctuation. Remember that paths with spaces in them must be quoted.

this is a linked file


Machine Names

Rewritten April 2015

In a peer-to-peer (P2P) network environment, A-Shell/Windows uses the computer name to establish a unique ID for each session. The computer name is sometimes referred to as the NetBIOS Machine Name and can be found and set in the My Computer System Properties dialog. It is critical that each workstation on the network has a unique Computer Name, although it is unfortunately common for installers to overlook this step when installing new machines.

When a new A-Shell session is launched, it scans the job table to see if there is an existing record for this machine/instance, and if so, it assumes that the prior session was terminated uncleanly, such as by rebooting the PC, and re-uses that same job table record so as to avoid accumulating orphaned job table entries. If there are multiple machines with the same name, A-Shell will be fooled into thinking that a new and distinct session is actually a restart of a previously aborted one, causing the earlier session's job table record to be overwritten. This is likely to lead to the first session aborting with a cryptic "your job table has been zapped" message. Outside of A-Shell, the duplicate computer names will cause a variety of other problems that are best avoided.

To help identify this error before it becomes a more serious problem, A-Shell (see History, below) generates its own unique identifiers for each machine during installation; it can then use that information to identify duplicate machine names when new sessions are launched, thus allowing the problem to be detected and resolved right away. In order for this to work, you must run the installer/updater to update each workstation, rather than manually installing the update by copying files.

The installer/updater establishes a unique identifier for each machine and saves it in the HKLM section of the registry, to be used to determine whether an instance with the same machine name as an existing instance is actually the same machine or not. If so, then the new instance can safely overwrite the old one. But if not, an error message is displayed and the new session is not allowed to start.

The error message will indicate the machine name, the user name and jobname of the offending existing instance, and the unique identifiers (8 hex digits) for the two machines. You can use the new SYSTAT/CU switch to display the unique identifiers for existing sessions, which may be helpful in tracking down the offending duplicate-named machine.

Also note that the issue only affects P2P networks; ATE, Terminal Server, and UNIX systems are not subject to the problem and are not affected by the update.

History

2015 April, A-Shell 6.1.1408: A-Shell now detects duplicate machine names.


Drive Mapping

The astute reader will have noticed that we rather glossed over the issue of drive mappings in the preceding discussion. Indeed, the essence of a network installation is setting up drive mappings so that each workstation can reference shared directories on the server. It is assumed that the installer will have enough expertise to create those drive mappings using the standard Windows procedures. However, there are a couple of subtleties worth mentioning here.

First, the server must "share" the drive that will hold the files common to all of the workstations. This much is obvious. However, although it may be desirable, it is not absolutely necessary that the workstations actually create a drive mapping to it. Instead, you can use the UNC (Universal Naming Convention) notation to reference the server and share name instead of the mapped drive letter. For example, assuming the server’s machine ID is "BIGBOY", and the shared drive on the server is simply shared as "C", then you could specify the following destination directory while running the SETUP program:

Destination: \\BIGBOY\C

This technique has the advantage of eliminating the need to define a drive mapping to the server for every workstation, and eliminates any possibility of different workstations ending up with different mapped drive letters. If you decide to use the more traditional mapped drive letter approach, it is strongly recommended that you choose a relatively high drive letter (like X:) to reduce the possibility that you run into a workstation that has so many devices mapped that the desired letter is already taken up.

The only known disadvantages to using the UNC name of the server rather than creating a drive mapping are that you may experience a delay the first time you try to connect (while a dynamic network connection is established) and in some cases, such as after a period of inactivity, some servers may begin to drop UNC connections. (This could cause a problem if the inactive application had files open.)

Another subtlety to note is that since data transfer over the network is subject to bottlenecks, it is often desirable for performance reasons to define one or more devices (logical disks) that reside on each local workstation for the purpose of holding print files, temp files, that don’t need to be shared. This assumes that the application provides an option of where to send different categories of files, such as DSK1: for the master data files, DSK2: for print files, etc.


Windows Printers

Like all other versions of A-Shell, A-Shell/Windows uses the PRINTER command line in the miame.ini file to define the default spooler name. This name, in turn, is usually associated with a configuration file for that printer, called SYS:<spoolername>.INI (or ASHCFG:<spoolername>.PQI), the contents of which are discussed in detail in Printer Configuration in this document. The main aspect of printer configuration to be dealt with at this point is simply to identify the printers which will be used by the application, and to install and configure the necessary drivers so that each workstation can refer to each printer by a common descriptive (i.e. "Invoice Printer #1") or network (i.e. \\prtsrv\invoice1) name. This name will then be associated with the spooler name via the DEVICE statement in the spooler configuration file.

In most cases, it is no longer necessary to manually install a local printer driver for network printers, provided they can be accessed via the \\machine\sharename.

Applications that embed their own ESC sequences into print files for the purpose of controlling printer functions (e.g. condensed print), may need to use a printing mode called "PASSTHROUGH" printing. PASSTHROUGH printing is somewhat unusual in the mainstream world of Windows, and thus many printer drivers (and in some cases the printers themselves) do not support it. If uncertain, you can always use the Generic Text Only printer driver (provided the printer hardware supports it – try the driver Test page to confirm that.) Refer to Printer Configuration for more details about PASSTHROUGH vs. non-PASSTHROUGH printing.


Windows Performance

This section of the documentation should talk about

• How network traffic becomes a concern as the size of the network grows

• What steps can be taken with A-Shell to minimize that traffic and therefore A-Shell's performance

• What steps can be taken with/by other network components besides A-Shell

• At what point should A-Shell go with the Telnet (ATSD) model

• At what point should A-Shell go with the Telnet plus (ATE) model

Unfortunately, we didn't quite get to that documenting chore just yet. Hopefully it's coming soon.


UNIX / Linux Installation

A-Shell/UNIX releases are binary specific for a particular machine and architecture. However, the procedure is pretty much the same, regardless of the flavor of Linux / UNIX. Where there are important differences, they will be noted.

Note that the document uses the term "UNIX" to mean "UNIX, AIX, HPUX, Linux and all UNIX-variants." We of course recognize the differences between the operating systems. But because they all work about the same with regard to A-Shell, and the A-Shell commands are the same for the entirely family, we've chosen to use "UNIX" as the family name.

A-Shell/UNIX is downloaded from our web site in the form of one or more "cpio" files, typically named a???###*.bin, where ??? indicates the platform, ### indicates the build number, and * is a suffix which is usually "r" (for runtime package) or a number (for a patch release). The file name "ash-6.2.1421.3-el5.bin," for example, indicates A-Shell version 6.2, build 1421.3, for Enterprise Linux version 5. Often the file will have an additional extension, either Z or tz, in which case it first needs to be uncompressed, using uncompress <file>.Z or tar xvzf <file>.tz.

To install the A-Shell software, copy the cpio file to a convenient location, such as /tmp, and log into UNIX using your normal user id. Do not log in as the superuser (root). Then enter the following:

$ cd /tmp

$ su

[Enter root's password if requested]

In the examples below, we assume you are installing from a cpio file, with an A-Shell build number of 827. For the installation from a file, replace the same filename given below with the actual one you downloaded.

For Linux:

# cd /tmp

# tar xvzf ar7x827r.bin.tz

# cpio -iuB ash_install < /tmp/ar7x827r.bin

For SCO, AIX, HPUX:

# cd /tmp

# uncompress axxx827r.bin.Z

# cpio -icuB ash_install < /tmp/axxx827r.bin

Then, for all platforms:

# chmod +x ash_install

# ./ash_install

# exit

The ash_install script will prompt you for the directory location for the object and runtime files (we suggest /vm/miame for both) and for the name of the file or device you are installing from (which will be the same as the one you extracted the ash_install script from above.)

The ash_install script will execute two special customization scripts (pre_ash_install and post_ash_install) if they exist in the custom subdirectory of the specified target (object) directory tree. These allow you to customize the update process, perhaps saving, renaming, or removing certain commands or files, etc. See the sample scripts included with the release for further notes and examples.

The process will only take a couple of minutes. At the end, it will remind you to set up your MIAME and PATH environment variables and edit the miame.ini file as needed.

History

2006 July, A-Shell 4.9.960: Some improvements were made to the UNIX / Linux installation procedure:

• The installation script now replicates the TERMINFO definitions for am62a to am62cg and am75 to am75g if needed. (This is a convenience when updating older systems with the intent of using ATE. For new installations, you still need to run the tic am62a.tis command to compile the TERMINFO definitions for the am* emulations.)

• ASTART.CMD is no longer overwritten

• ASHLPR components (OPR:ASHLPR.INI, ersatz def ASHLPR:=DSK0[1,24], BAS:ASHLPR.SBX) now installed if not already there.

Subtopics

File Ownership and Privileges

Advanced Privilege Settings

Setting Up UNIX Logins

Modifying the User .Profile

Backspace Key Operation

Enabling the Use of KILL.LIT


File Ownership and Privileges

After completing the script, and before proceeding to the configuration steps below, you may need to adjust the ownership and access privileges for the files and directories installed. The script sets the group ownership to group 100, which may not be appropriate for your system. Consult your operating system documentation for the chgrp, chmod, and chown commands for details.

A good starting point would be to create a user group (e.g. "ashell" or perhaps the name of your application) and add all applicable users to that group. Then assign the entire A-Shell directory system to that group. Assuming you installed in /vm/miame, you could do this under most UNIX flavors as follows:

# cd /vm/miame

# chgrp –R ashell *

The above commands would assign every file in the entire directory tree starting from /vm/miame to the ashell group. You could then provide unlimited access to all files for all members of that group, as well as the actual file owner, very simply with the following commands:

# cd /vm/miame

# chmod –R ug+rwx *

This sets the read, write, and execute flags for both the owner and group for all files in all subdirectories starting from the /vm/miame.

If you are concerned about unauthorized users having the ability to overwrite important parts of the A-Shell installation, then you should set up a special user (or root) to be the owner of all the files distributed as part of A-Shell, and then allow only that user to have write privileges for those files. As an example, you might protect the files in the /vm/miame/bin and /vm/miame/dsk0/001004 directories as follows:

(while logged in as root)

# cd /vm/miame

# chown –R root *

# chmod 750 bin/*

# chmod 640 dsk0/001004/*

For all the files in the /vm/miame/bin directory (where the ashell executables normally are,) the above commands would allow read/write/execute access to the root user, read/execute to users in the ashell group, and no access to other users. The idea is similar for the /vm/miame/dsk0/001004 (aka SYS: or DSK0:[1,4]) directory, except that those files don’t need the execute bit, since they are never really executed by UNIX. Instead, they are handled like data by the A-Shell interpreter.

Use the UNIX ls –l command to verify the correct settings, which might look something like this:

# cd /vm/miame/bin

# ls –l

-rwxr-x--- 1 root ashell 827127 Jan 31 17:06 ashell

#

# cd /vm/miame/dsk0

# ls –l

drwxr-s--- 2 root ashell 512 Jan 31 17:27 001002

drwxr-s--- 2 root ashell 2048 Feb 2 11:47 001004

drwxr-s--- 2 root ashell 512 Aug 12 02:41 001006

drwxr-s--- 2 root ashell 512 Jan 31 17:17 002002

drwxr-s--- 2 root ashell 512 Jan 21 15:29 007000

drwxr-s--- 2 root ashell 2560 Jan 31 17:19 007006

#

# cd 001004

# ls –l

-rw-r----- 1 root ashell 2474 Jan 31 17:03 time.lit

-rw-r----- 1 root ashell 3024 Jan 31 17:03 type.lit

-rw-r----- 1 root ashell 2396 Jan 31 17:03 ver.lit

<etc>

#

If you have files in a lot of directories (corresponding to many PPNs) you can use the –R (recursive) switch to chmod as follows to act on all of the subdirectories at once:

# cd /vm/miame/dsk0

# chmod –R 640 *

# chmod 750 *

The first chmod command above would set read/write privileges for the owner and read privileges for users in the ashell group for all files in all subdirectories of /vm/miame/dsk0. (The –R switch causes the command to descend the directory tree recursively.) The second chmod command then adds the execute flag to all of the files in the /vm/miame/dsk0 directory, since these files are actually directories, and directories must have the execute flag set.

Warning: Under most UNIX implementations, the execute flag must be set in all directories in order for users to be able to access those directories. Thus while the execute flag is not needed for most A-Shell files, such as *.RUN, *.LIT, and *.DAT, it is essential for the directories themselves.

Another warning: Shared data files in your application must offer read and write access to all users, so it would probably be unwise to limit write privileges to the file owner for such files. Putting your *.RUN files (which don’t need to be written to by all users) in a separate PPN (e.g. [p,0]) from your data files would make it easier to fine tune the access privileges at the directory level rather than the file level.

If you don’t care at all about security, and it doesn’t bother you if certain files have their executable flag set even though they are not really executables, then you can just set all the read/write/execute flags for all of the files as follows:

# cd /vm/miame

# chmod –R 777 *

In this case, the owner and group attributes don’t matter, since everyone is allowed all types of access.

Most versions of the chmod command support a syntax for adding or removing privileges, without having to replace the current privileges with a single specified value set. For example, chmod –R a+rw * would add the rw privilege bits (for all three levels – user, group, other) to all files in the current directory tree, without removing the x privilege bit from any files or directories that already have it set. Replacing the "a" with some combination of "u" (user/owner), "g" (group), and "o" (other) would limit the effect to the specified categories. Also, replacing the "+" with a "-" would remove rather than add the privilege bits.


Advanced Privilege Settings

Aside from the privilege considerations discussed above, there are a couple of more advanced settings that you will need to consider, and if desired, carry out manually in order to enable certain auxiliary utility operations such as CHAT, SEND, KILL, and LOKUTL. The basic problem is that unlike AMOS, where assembly language commands or subroutines can read from and write to any region of memory, including the monitor and other jobs’ partitions and control blocks, under UNIX it is generally not possible for one job to see or affect any other job’s private information, nor is it possible to see the kernel’s private memory. There are two general cases to consider here.

The first is the case of a utility that needs to see or affect another job, such as KILL, SEND, or CHAT. To allow this, the sender and receiver must either both be running under the control of the same effective user, or the sender must have root (superuser) privileges. The second case occurs when we need to access kernel information (such as the lock list, or the list of active processes.) In that case, we must have superuser privileges. Since having every user log in as the same user, and especially as the superuser, would defeat all of the safeguards which help make UNIX a more reliable operating system than AMOS or Windows, we need a way to temporarily obtain the necessary privileges in a way that is out of the control of individual users to abuse. The SETUID mechanism allows us to do this, by providing a special bit in the directory entry for an executable command which causes the user of that command to assume the privileges of the owner (creator) of the command, but only while executing the command. As an example, the UNIX utility ps (process status) uses this technique to allow anyone with sufficient privileges to execute ps to temporarily acquire the superuser privileges necessary to read the kernel’s process table in order to display a list of what every process is doing.

The A-Shell utilities KILL.LIT, SEND.LIT, and CHAT.LIT fall into the first category of commands described above, since they require that both the sender and receiver either share the same effective user ID, or that the sender be the superuser. Of the two alternatives, we prefer the former, since as a general principal it is wise to limit the use of superuser privileges to the bare minimum. So instead, we can use the SETUID bit to cause everyone that is running under ashell to have effectively the same user privileges. For example:

# cd /vm/miame/bin

# chown ashusr ashell

# chmod +s ashell

The above commands, we first make the user ashusr be the owner of the ashell executable, and then we use the chmod +s command to turn on the SETUID bit. Thus all users executing ashell will assume the effective identity ashusr while they are in A-Shell, and thus then can use SEND, CHAT, and KILL on each other. (You must first create a user called ashusr.) Note that this "effective" user ID does not conflict with the login ID, which remains distinct, and which is used in utilities such as SYSTAT to allow you to distinguish the users from each other.

Because of the dangerous implications of the KILL command, there is another level of safety involved in enabling its use which is described in section following titled "Enabling the Use of KILL."

The second case of utilities (those that need superuser privileges to access kernel information) are mostly taken care of by the standard operating system installation, and are not of particular to concert to A-Shell. There are a couple of exceptions though, most notably the lslk (list locks) utility, which is used by A-Shell’s LOKUTL.LIT (under UNIX versions) to access the list of locked files and records. Since this utility comes from a shareware source you may need to manually install it (either in the same directory as the ashell executable or somewhere in the PATH) and, if not already done, change the owner to root and set the SETUID bit using chmod +s as shown below:

# cd /vm/miame/bin

# chown root lslk

# chmod +s lslk

In most cases, lslk is distributed with and installed by A-Shell, but you may still need to perform the above steps since the ownership and privileges may get overwritten by the steps described in File Ownership and Privileges above.

Another utility similar to lslk which may be distributed with A-Shell (or obtained from the web) is lsof, which displays a list of open file handles by user. You would also want to set the ownership and privileges for it exactly as for lslk, even though it is not integral to A-Shell.


Setting Up UNIX Logins

The actual technique for setting up UNIX logins varies among UNIX flavors, and is outside the scope of this document. However, since many A-Shell users are used to a rather casual security atmosphere under AMOS in which there may have been no formal user definitions, it is worth discussing the basic strategies that are available here.

The simplest strategy is to define a generic user (e.g. "ashusr" or just "user") and let everyone log in as that same user. If this lack of refinement doesn’t bother you, it doesn’t bother A-Shell. The only detrimental side effect is that SYSTAT will not be able to give you any useful clues as to who is who (unless they are all on serial connections and you recognize the port numbers.) It may be possible to overcome that shortcoming by setting the A-Shell user name within A-Shell based on some kind of application logic, but this strategy is not workable if you want to use UNIX utilities such as mail, which depend on the user login to establish identities.

At the opposite extreme is the traditional approach of setting up a separate UNIX login for each real user, which offers advantages such as allowing SYSTAT to be able to display each user’s login name. The main down side to defining individual UNIX logins is that it can be a lot of administrative work (if you have a lot of users.) However, most flavors of UNIX provide some way of simplifying this (e.g. template user profiles, sharing of home directories, etc.) so it generally doesn’t require much more than assigning a login name and password for each user, letting the rest of the settings (group, home directory, shell, etc.) default to the template value. The other main complication with having individual user logins for each user is the security problem of not being able to send signals to each other, but the SETUID trick described in the previous section effectively works around that problem.


Modifying the User .Profile

There are three or four minor modifications that usually need to be made to the .profile ("dot profile" or shell initialization) file for each user to set the necessary environment variables and optionally launch A-Shell automatically after login. All of this can be done interactively from the shell prompt each time a user logs in, but it is much cleaner to make it all happen automatically.

On the theory that an example is worth more than just an explanation, a typical user .profile (in this case for the Korn shell under AIX) is shown below, with A-Shell modifications, followed by explanations. Note that your .profile will probably be different, but similar.

PATH=/usr/bin:/etc:/usr/sbin:/vm/miame/bin:/usr/ucb:$HOME/bin:

MIAME=/vm/miame

TERM=am62a

export PATH MIAME TERM

set +o monitor

ashell main

exit

In the PATH statement, we just added the A-Shell executable directory (/vm/miame/bin), so that users could execute ashell (or more importantly, vue) from anywhere. You might argue that this is unnecessary in a turnkey system, since the only time users would ever launch ashell is from within this same file, in which case it would make just as much sense to call out the full /vm/miame/bin/ashell path on the last line. Similarly, even if you wanted to use the A-Shell vue editor instead of vi, you could always put a link to it in a directory that was already in the PATH, such as /usr/bin. However, adding it to the PATH is clearly preferable if you plan to go in and out of A-Shell many times. Note that the delimiter is the colon (:). It can also avoid a lot of confusion if you are having problems launching background sessions with XCALL AMOS or SUBMIT, and it may be necessary for certain utilities such as KILL and LOKUTL, which in turn execute native UNIX commands (ashkill and lslk) which are expected to be in the PATH (and which are typically stored in the same directory as the ashell executable..

MIAME=/vm/miame defines the environment variable MIAME, which is used by A-Shell to locate the miame.ini file. Again, you could get by without defining this variable since you can always specify the miame.ini on the startup command (e.g. ashell –i /vm/miame/miame.ini)

TERM=am62a is shown here for those cases where the login script (specifically the tset command) is not managing to set the TERM variable correctly. If you are using a known terminal type (am62a, am62c, am75, wyse50, hz1500, vt420) then it is essential that the TERM variable get set correctly to one of those names (using the spelling and case as given in the list above.) Otherwise, A-Shell will not recognize your terminal type, and will be forced to use the TERMINFO database, which is at best, not as good. Of course it is less than ideal to hard code your terminal type in your login script—it is much better to have the login routine prompt you (see the Validate terminal type switch to PolyShell)—but this at least demonstrates the brute force approach.

If you want to use the am62a emulation with UNIX utilities (such as the vi editor) then you will need to define a TERMINFO entry for it. Since am62a is not a standard UNIX terminal type, we provide a TERMINFO source, am62a.tis which you can add to your TERMINFO database with the following command (execute as root from the /vm/miame directory): # tic –v am62a.tis

The export statement is needed to make the preceding environment variables visible to programs running outside of the shell (such as A-Shell).

set +o monitor is only needed when you are using PolyShell and a "job control" shell, such as the Korn Shell (ksh) or Born Again Shell (bash). It turns off the shell’s trapping of the job control signals so that PolyShell can use them itself.

ashell main launches A-Shell (assuming it is in the PATH and the MIAME environment variable defines the location of miame.ini) and tells it to execute CMD:MAIN (CMD or DO) as a startup command. If that command file brings up your main menu, and you want the user to go directly back to the UNIX login prompt when exiting from your main menu, then add a HOST command at the end of your MAIN.CMD file, as shown here:

:R

LOG DSK1:[20,0]

RUN MAIN

HOST

When HOST command is executed, the A-Shell session is terminated, returning execution control to the login profile script, where the next command to execute (based on the example above) is exit. This logs you out of UNIX. Depending on the connection type, you may then go back into the UNIX login prompt, or perhaps your Telnet connection window will close and disappear.

Another way to force the A-Shell session to terminate after the program completes is to use the –e switch on the A-Shell command line.


Backspace Key Operation

Within A-Shell, the Backspace key on a PC keyboard should work just as you would expect the Rub key to work (backspace-space-backspace.) However, if you work at the UNIX prompt with a terminal emulator, you may find that the backspace key terminates the command line. This can be very frustrating. To get the Backspace key to work like you would expect (and to change the interrupt command from Backspace to Ctrl+C) try typing the following commands (or adding them to your profile.):

$ stty intr \^C

$ stty erase \^?

$ stty echo


Enabling the Use of KILL.LIT

Because the normal UNIX security rules do not permit one process to send signals to another (unless they both belong to the same user or the sender is the superuser), the A-Shell KILL.LIT utility invokes a command called ashkill rather than accessing the standard UNIX kill command directly. It is up to you to create the ashkill file according to the type of security you want for this potentially dangerous function. In most cases, the thing to do is to make a copy of the standard kill executable called ashkill. (It is typically located in the /usr/bin or /bin directories.) To avoid mixing A-Shell files up with the operating system files, it is recommended that you put ashkill in the MIAME bin directory (e.g. /vm/miame/bin).

If you only want the superuser to be able to use the KILL.LIT command, or if you have already set the SETUID bit on the A-Shell (as described above) so that every A-Shell job is effectively owned by the same user, then there is nothing else to do. Otherwise, if you want ordinary users to be able to execute KILL.LIT, then configure ashkill to temporarily give the user superuser privileges with the following commands:

$ su root

<enter root password>

# cd /vm/miame/bin

# chown root ashkill

# chmod +s ashkill

# exit

Another option is to create a script called ashkill that uses more sophisticated logic to decide whether the current user (perhaps on the basis of his logon identity) should be allowed to kill other users.


After Installation

After the formal installation is complete, as described in the preceding pages, there are a number of miscellaneous configuration and follow-up steps to be performed before the installation can be considered complete. These include reviewing and adjusting the MIAMI.INI file, installing the security key, possibly transferring programs and data from another machine, etc. Instructions for these topics follow.

Subtopics

Modifying MIAME.INI

Installing the Security Key

Transferring from AMOS

Folding Filenames to Lower Case

Selecting a Terminal Emulation

Running A-Shell

Erasing Log Files Periodically


Modifying MIAME.INI

Before proceeding with installation of the security key, it is a good idea to review the miame.ini file to make sure that it references the proper local drives and directories. This is particularly necessary for A-Shell/UNIX if you didn't install the software in the default directory. Refer to Configuration for more details, paying particular attention to the DEVICE parameter. Attempting to launch A-Shell with references to incorrect or non-existent paths in the miame.ini is to invite confusion and even grief for the faint-of-heart.


Installing the Security Key

A-Shell runs in one of two modes: licensed or demonstration. To run in demonstration mode, it is necessary only to install the software and run it; when prompted for the serial number, simply enter "0000."

To run A-Shell in licensed mode, and thereby avoid the demonstration mode message, you need to enter three data elements: a serial number, a company name, and a security key (also called the "Product Installation Code" or "PIC"). This information is available from MicroSabio or your reseller, and is normally provided when you purchase your original or updated A-Shell license.

• The serial number is a four-digit number.

• The company name is not sensitive to case or to punctuation (spaces, hyphens, etc.), but otherwise needs to be entered exactly as provided.

• The security key (also called a "product installation code", or "PIC") is not case-sensitive, but is sensitive to punctuation and spacing. It is a 29 character string which encodes information about the licensed company name, number of nodes, machine and operating system type, and other options such as PolyShell, D-ISAM, expiration dates, etc. The key is made up of numbers, dashes, possibly an @, and lower case letters (except lower case l, which is given as L to avoid confusion with the number 1.)

To install or re-install the security key, see the next topic, Updating the License.

Notes

The security key is requested the first time A-Shell is invoked. For UNIX, this is achieved by typing ashell at the host machine command prompt (assuming the necessary PATH and MIAME variables were defined.) For Windows, you generally launch A-Shell by clicking on the icon.

The key is stored in the miame.ini file, and re-validated each subsequent time you launch A-Shell. The company name is stored in a file referenced by the CONAME parameter within miame.ini (typically DSK0:CONAME.DAT[1,4].) If either is invalid, it will give you the option of re-entering it (which is useful for converting from demo mode to a proper license).

You can force A-Shell to prompt you for a new key (which is necessary for updating your node license) by using the LICENS.LIT command from the dot prompt (or applying the –k command line switch to ashell in old versions of A-Shell).

The company name and security key are intimately related. This means that you cannot change the company name without impacting your A-Shell license. If your firm's name is Smith Jones & Wilson, and then Wilson leaves the firm, you cannot simply change the A-Shell company name so that it now displays Smith & Jones. If you do so, A-Shell will stop running (or, more precisely, the license will fail and A-Shell will revert to demo mode). If you want to change the company name, you must contact MicroSabio or your reseller.

Attempting to run more nodes than the key allows will result in a message similar to the following:

?A-Shell 4-node license already in use

The number of nodes licensed, as well as any options such as D-ISAM or PolyShell, is noted in the license banner that displays for a few seconds on startup. You can also view detailed information about the license from the dot prompt using the ABOUT command. Under A-Shell/Windows, you can also view similar information on the Help...About dialog box.

Note that the definition of a "node" is slightly different for different operating systems. For A-Shell/Windows, a node is simply a PC, and any number of windows may be running A-Shell on each PC without using up node licenses. (In the case of Windows Terminal Server and Citrix, A-Shell attempts to determine when multiple A-Shell sessions originate from the same workstation, but this is not always possible.) Under A-Shell/UNIX, generally each A-Shell session counts as a separate node. So a PC with a terminal emulator running two sessions over Ethernet for example would use up two node licenses. The exceptions to this are (1) that an A-Shell session can spawn another one with no penalty, and (2) all sessions running underneath a single instance of PolyShell count as a single node for licensing purposes.

Subtopics

Updating the License

LICENS Error Codes

Troubleshooting Licensing Issues

Other License Matters


Updating the License

There are several reasons why you might need to update your A-Shell license: increase the numbers of licensed nodes, extend your software maintenance contract through a new update expiration date, add options, change company name, or change platforms. In all cases, make sure you have received clear and unambiguous license information before beginning. Having somebody tell you over the phone that the company name is "Smith and Company," for example, is likely to cause problems; is it Smith and Company? Smith & Company? Smith & Co, Inc.? J. SmithCo? It may not make a difference to you or Smith, but it does to A-Shell.

The company and license key fields are NOT case-sensitive.

Normal Update

1 Log to the system operator account OPR:

2 type LICENS followed by the Enter key.

There are two things that can happen at this point: either LICENS will run, or it will not, in which case A-Shell displays ?LICENS?. If LICENS runs, then you need only to follow the prompts and enter your new or updated information. If it does not run, then this means that your version of A-Shell is pretty old, and you need to use the old method of updating the license.

If LICENS runs as expected but the license info you enter is declared invalid, look up the LICENS Error Codes and try Troubleshooting Licensing Issues.

Old Method

The program LICENS was added in A-Shell version 4.7.830 of April 2003. If your working copy of A-Shell is older than this (you should update!), then you will need to follow this method of updating your license. It consists of forcing A-Shell to prompt for a new security key when A-Shell starts. To accomplish this, use the start-up switch -k (e.g. ashell -k). When you start A-Shell, in other words, add -k to the command line.

Under A-Shell/Windows, the easiest way to temporarily launch it with the -k option is right-click on the icon, click Properties, then Shortcut. Highlight the command line (if it is not automatically highlighted, as it should be), then press Ctrl+C to copy it to the clipboard; then lick Cancel to exit the dialog. Click on the Start menu, select Run, then press Ctrl+V to paste the A-Shell command line (i.e., that which you earlier copied) into the edit box. Finally, position the cursor just past the ashw32.exe and add a space followed by -k, then click the OK button.

Notes

The "Maintenance Expiration" date will not prevent A-Shell from running unless you update A-Shell beyond your maintenance expiration date. If your expiration date is 15 January 2006, for example, and you install a new version of A-Shell on 16 January 2006 or after, A-Shell will revert to demo mode and require that you get an updated license. So remember: don't ever update A-Shell unless your maintenance expiration date is in the future.

The "old method" described above will also work with newer versions of A-Shell, although it is recommended that you use LICENS.

Information about the A-Shell license is also available with the ABOUT command, and from the Help | About menu (under Windows).

If the existing company name needs to be changed (it was misspelled, firm has a new name, you need to add "Inc.", etc.), you must simultaneously get a new security key from MicroSabio and change the company name on your system. Both the new PIC and the name company name can be entered by use of the LICENS command.

Note on Background Tasks

Provided that the license is for five or more nodes, the first five (simultaneous) background tasks do not count. After that, they count as regular nodes.


LICENS Error Codes

When you run the licensing program LICENS.LIT to install a new license, the normal and desired result is a final response from the program saying "License Valid!" Given that things don't always work as expected, however, a "License Invalid!" response is not beyond the realm of possibility. If and when this happens, knowing WHY the new license data was rejected can be helpful. The table below shows the meaning of the error codes that may be shown in brackets immediately following the negative message.

Error | Description
2 | Bad encryption key
3 | Bad company name
4 | No node license
5 | PolyShell not licensed
6 | Key applies to other platform
7 | License expired
8 | EXE date beyond end of maintenance license
9 | Key in old format
10 | ATSD not licensed
11 | Support use only
12 | MAC not valid
13 | Serial number too large, or invalid


Troubleshooting Licensing Issues

The A-Shell license program and process has been in place for many years, and has never been shown to have a problem or to produce invalid results. If you having a problem, it is likely because either you or the person who provided the license has overlooked something. Here are some suggestions for finding the problem.

Confirm your license

If you are having trouble with any aspect of A-Shell (including ATE) licensing, the first thing to do it to make sure that your license is and says what you think it is. Use the following steps to check for discrepancies, oddities, unexpected results, etc.

• Run ABOUT from the prompt.

• If you are using A-Shell/Windows or ATE, check the Help...About box for confirming info.

• Run SYSACT from the prompt.

• Run LICENS from the prompt while not logged in to OPR:

A-Shell Version 6.2.1425

In February 2016, the A-Shell license key format was changed to xxxxxxx-xxxxxx-xxxxxx-xxxxxxx (seven characters, two sets of six characters, seven characters). If you are trying to us a key of that format in a version of A-Shell before 6.2.1425, that's the problem; it won't work. Please request another key in the "old" format. The format of the old key, by the way, in characters, is 4-4-3-6-8.

ATE Issues

Run ABOUT from the prompt. As of ABOUT.LIT 2.2(108), it will show the license options for the ATE aux license independently of the main server license. In addition, next to "ATE Licensing:" it will list "Client", "Auxiliary (aux.lic)", AND/OR "Server". If it lists "Client" in addition to one of the other two, that means that the ATE client supplied its own license, even though the server could have done so. (This could be the reason for the confusion between the features included in the server-based license and those in the client-based license.) Also note that in this case, the information displayed will be relative to the aux license, even though that won't necessarily be what the client is actually using. To check what the client is actually using for licensing, see Help > About on the ATE menu bar.

If you are using A-Shell/Windows or ATE, check the Help...About box for confirming info. In the case of ATE, near the bottom, after "Additional license information:", it will indicate "(Server supplied)" if the license info came from the server. If it doesn't say that, then the information will be relative to the license which is local to the ATE client.

Run SYSACT/ATE from the A-Shell prompt.


Other License Matters

Unfamiliar License Options and Terms

Although you will be familiar with most of the options that show up in your license, there are a few terms that may not be so familiar.

LFS stands for Large File Support, referring to support for files larger than 2GB. This is not a pay-for feature (although perhaps it should have been). It appears as a "license option" just because it seemed like a handy place to put it. It is more precise to call it an attribute of the build, as opposed to the license. Generally, all current versions of A-Shell support LFS, except perhaps the Windows "C" version.

W32IO is a similar kind of thing - this is a build option, not a licensing option. It means that we're using the WIN32 I/O routines, as opposed to the standard "C" library I/O routines.

VI(5.65.7) is a reference to the Victor Imaging library. That originally was a kind of licensing option (in that we did charge for it) but like the other two just described, doesn't relate to any bits in the actual PIC code.

COM, an acronym for Microsoft's Component Object Model, was an extra-cost option for A-Shell when it was introduced quite some time ago. It is no longer charged for, and may show up in both Windows and Linux licenses. Note that the COM interface is now always enabled in A-Shell, and works regardless of whether "COM" is displayed with the license information.

Exceed A-Shell License

If you exceed your A-Shell license ("authorized nodes") by trying to log in when all available nodes are in use, you will be a message saying "node counted exceeded," and you will not be able to log in.

Exceed ATE License

If you exceed your ATE license authorization—i.e., you try to connect as the sixth ATE connection in a system where five ATE nodes are licensed—you will get a "nag" message but will be allowed to operate.

Group Licensing

Beginning with A-Shell 6.3.1540 of December 2016, A-Shell provides an option for group licensing. This allows fine tuning of the license usage by providing a means of reserving and/or limiting the license usage relative to license groups. For example, in a fifteen user license, you can reserve two licenses for "admin" users, and/or limit the "remote" users to no more than five licenses.

When group licensing is enabled, via an option encoded in the A-Shell license, A-Shell will call BAS:ASLICGRP.SBX on startup. The routine and its contents determine which license group the current user should be assigned to, and also specifies the various allocations or limits for each group.

See the sample ASLICGRP.SBX source code in [907,52] of the SOSLIB for details on the calling interface.


Transferring from AMOS

As mentioned in the introduction, A-Shell provides binary file compatibility with all of your data files, and in most cases your program source code (*.BAS, *.BSI, etc.) as well. The only files that must be converted are any ISAM PLUS files, which you must first dump using ISMUTL on the Alpha, and then use a binary transfer method to get the dump file to the UNIX or Windows box, where you can reload it using the A-Shell version of ISMUTL.LIT.

Source files (BAS, CMD/DO) and other text files are binary compatible between AMOS and Windows. Under UNIX, these files normally have line terminators of LF instead of CRLF, but since A-Shell can accept either format, the easiest approach is to just transfer all your files using the binary transfer method. The main down side of not using an ASCII or text transfer method to transfer your source files to UNIX is that VUE will give you a warning that the file is in AMOS format and will be converted. (You can, however, turn off the warning; see CVTWARN.) On the other hand, by not converting the line terminators from CRLF to LF, you preserve the hash code and size of the files, which allows you to verify the transfer results by comparing the hash codes using DIR/H and/or VERIFY which are implemented on both AMOS and A-Shell.

In particular, it is not desirable to expand TABs to spaces when transferring program source code, as this may cause some lines to exceed the 510 byte limit of AlphaBASIC.

Because of the difference in directory structures between AMOS, Windows and UNIX, it is virtually impossible to do wildcard transfers of files involving multiple PPNs and devices. Instead, it will be necessary for you to manually specify the UNIX or Windows path that corresponds to the AMOS PPN for each directory. (See the discussion of the DEVICE parameter of the miame.ini file for information on how PPNs are mapped to directories.) The only way around this with FTP transfers is to use an FTP package that allows programmatic scripting. A free utility program is available from MicroSabio that uses this technique in conjunction with the ZTERM terminal emulator to transfer multiple PPNs in bulk.

If you don’t have FTP on your AMOS system or can’t connect the two systems via a network, then there are still several ways to get your files from the Alpha to your UNIX box or PC. One approach is to use a communications package (such as AutoLog) to transfer files over a serial or modem connection. Another is to first transfer from the Alpha to a PC using a PC-to-Alpha communications package such as ZTERM or AlphaLAN, and then (if using the target is UNIX) to transfer from the PC to the UNIX box using FTP.

A third method is to use a TAR format tape transfer, provided that you have a compatible tape drive on both systems.

Contact Soft Machines for information about the UNIX version of AutoLog. Contact MicroSabio or your dealer for information on obtaining ZTERM. Contact your Alpha Micro dealer or U.A. Systems for information on obtaining AlphaLAN. Contact MicroSabio for information on TAR tape transfers and on scripting ZTERM transfers of multiple PPNs in a batch operation.


Folding Filenames to Lower Case

One additional consideration when transferring files to UNIX is that the filenames must all be folded to lower case. If your PC-based FTP package does not support an option for this (a problem with the built-in W95 FTP.EXE), then we advise getting one that does (such as ZTERM or WS_FTP Pro.) If that is not practical, or you forget and end up with thousands of files with mixed upper and lower case names, there is a utility script called trlcs in the /vm/miame/bin directory which will properly fold one or more filenames (based on a wildcard spec) in a single directory to lower case. It does, however, require that you execute the command in each of your directories. For example:

$ cd /vm/miame/dsk0/020001

$ trlcs '*'

$ cd ../020002

$ trlcs '*'

<etc>

(Note that if a wildcard specification is given, it must be quoted.) If for some reason you do not have the trlcs command, you can create it by typing in the following and then using chmod +x trlcs to make it executable:

# trlcs: converts wildcarded files to lower case names

if [ $# != 1 ]

then

echo "trlcs converts names of files in wildspec list to lcs"

echo "usage: trlcs \047wildspec\047 (wildspec must be quoted)"

else

for f in $1; do

mv $f `echo $f | tr A-Z a-z

done

fi


Selecting a Terminal Emulation

Under A-Shell/Windows, selecting a terminal emulation is usually a one-setting-fits-all affair. Typically one specifies the default driver PCTDVG in the CONSOLE statement in miame.ini and that’s the end of it. Under UNIX/Linux, it can be a bit more complicated because you could be connecting from a variety of different types of terminal devices or terminal emulation software.

Typically, UNIX/Linux will attempt to establish the terminal type when you log in, either by querying the terminal directly, or by prompting the user. It then saves the terminal type in the TERM environment variable, which in turn, A-Shell queries to determine which terminal driver to use. If A-Shell does not recognize the terminal type as being one of those that it supports internally, it will use a generic terminal driver that works through the Terminfo database via the curses library. (This assumes that the terminal type is defined in the Terminfo database!) The generic driver is adequate for many applications, but it is not nearly as sophisticated as the drivers embedded into A-Shell. For example, it will not provide very good function key support, nor 132 columns, nor status line support. For this reason, we recommend that if at all possible, you use one of the following terminal types:

TERM type | Description
aixterm | AIX window emulation.
am62a | Alpha Micro AM62A emulation. This is perhaps the most common in the AMOS world. Field attributes, monochrome.
am62az | ZTERM-enhanced version of AM62A. Use only with ZTERM 2000 build 144 or higher. Supports variable rows.
am62c | Color version of AM62A.
am62cz | ZTERM-enhanced version of AM62C. Supports variable rows.
am65 | Alpha Micro AM65 emulation. Similar to AM62A, but uses mode rather than field attributes. Also supports 42 rows.
am65z | ZTERM-enhanced version of AM65.
am75 | Alpha Micro AM75 emulation. Essentially a color version of the AM65.
am75z | ZTERM-enhanced version of AM75.
cgi | Special pseudo-driver which is automatically set when running in CGI mode.
dumb | Dumb tty (hard-copy style) terminal. Useful for running background tasks to avoid cluttering log file with terminal-specific ESC sequences.
h1500 | Hazeltine 1500 emulation. Uses tilde as a lead-in sequence. Not recommended.
vt220 | VT220 emulation. This is often a reasonable choice for console devices that might otherwise use "ansi", "scoansi", or "linux" terminal emulation.
vt220a | (Linux only) Special version of vt220 emulation that uses no delay on the aux port commands. This is mainly of interest to users of a particular proprietary emulation package.
vt420 | VT420 emulation. Supports both 7 and 8 bit versions.
wyse50 | Wyse 50 emulation. Similar to AM62A but does not support addressable status lines, certain smart box operations.
wyse5z | ZTERM-enhanced version of Wyse 50. Supports variable rows.
wyz50 | (Linux only) Special version of Wyse 50 adapted from the original DOS version of ZTERM (by John Pruitt.) Requires ERSEMU.DLL to work with ZTERM.

The terminal type names stored in the TERM environment variable should always be in lower case. (A-Shell, like AMOS, confuses things by displaying the names in upper case when within A-Shell.)

The ZTERM-enhanced versions shown above all require ZTERM 2000 Build 144 or higher. In addition, you will have to manually set up the TERM environment variable, which you can do in one of two ways. One is to plug the "z" name into the Terminal Identity field on the Emulation tab of ZTERM’s configuration dialog (e.g. specify "am62az" or "wyse5z"). The other is to manually assign the TERM environment variable before launching A-Shell (e.g. TERM=am62az). Note that although ZTERM allows you to specify the number of display rows within its configuration screens, it is best to leave it at the default setting there and only change it from within A-Shell. Otherwise, your software will not be able to determine the current number of rows via the TRMCHR.SBR. To change the number of display rows, use the SET TERM HEIGHT command (see SET.LIT TERMINAL options) or TAB(-6,x) (see Set Number of Columns). VUE and EZTYP will allow you to toggle between 24 and 42-row display mode. You can also set the initial number of rows in the INI.CLR file; see Color Configuration.


Running A-Shell

Once the software is installed, and the AlphaBASIC applications to be run have been loaded into the correct accounts, A-Shell is ready to run. Under UNIX, type "ashell" at the host machine command prompt; under Windows, select the A-Shell icon from the Start menu or desktop icon.

A-Shell will respond with its prompt, and you are free to enter any AMOS commands that have been defined. To terminate the A-Shell session, enter the command "host" at the A-Shell command prompt.

Refer to Launching A-Shell for details on the command line options and other details of launching A-Shell (and PolyShell). See LIT Commands for details on the commands that can be entered from the A-Shell command prompt (aka the "dot prompt").


Erasing Log Files Periodically

A-Shell creates a couple of running log files that you will need to periodically erase (or else the disk will eventually fill up.) The most important one is spool.log), which will be found in the DSK0:[1,2] directory, and which contains an audit trail of every print request. The other log file is ashlog.log which if present, will be found in the same directory where the miame.ini file resides. Its contents and existence depend on the settings of the TRACE parameter (described in Configuration), but is mainly used under UNIX to log unexpected telnet disconnects.


Configuration

This section and the two following, System Parameters and Printer Configuration, serve as references to the configuration files and settings which are critical to successful operation of A-Shell. You should browse through this material, immediately before or after installing A-Shell, to get a sense of what kind of options exist. Later, you will probably use this as a reference document to get precise details on specific system parameters that you want to change.

Subtopics

MIAME Environment Variable

A-Shell Configuration File

Color Configuration

Help Menu Links


MIAME Environment Variable

The first thing A-Shell does upon being launched is look for its main configuration file. By convention, the configuration file is called miame.ini, though in keeping with the UNIX convention, the filename is given in lower case, ("miame.ini") on both UNIX and Windows system.

Unless overridden via a command line switch, the location of the configuration file is given by the MIAME environment variable. This variable is generally defined in a system configuration file, such as AUTOEXEC.BAT or /etc/profile, though may be defined at any stage using the appropriate system command, as shown in the following examples:

MIAME=/vm/miame; export MIAME (UNIX)

The actual pathnames used may be changed of course, but it is recommended that the MIAME directory is made a subdirectory of /vm (to enable multiple virtual A-Shell machines to be configured), and the parent of the directories which correspond to the devices where the application files are stored.

A-Shell itself allows the location and name of the configuration file to be overridden with the -i switch. This is particularly useful, and is standard procedure, for A-Shell/Windows, since it enables a desktop icon in the program manager to be configured with properties to auto-start A-Shell without the need to set an environment variable in AUTOEXEC.BAT or elsewhere. For example:

ashell -i /vm/miame/miame.ini (UNIX)

c:\vm\miame\bin\ashw32.exe –i c:\vm\miame\miame.ini (Windows)

If the location of the configuration file is given by the MIAME environment variable, then the file must be called miame.ini. If it is given via the -i switch, then it may have any valid filename.


A-Shell Configuration File

Updated January June 2008

The system parameters which define and configure the A-Shell operating environment are specified in the main A-Shell configuration file, which is normally called miame.ini. This is a standard text file that must be edited with VUE or another text editor to make changes. Each line of the configuration file is in the form of an equation defining a particular system parameter. Some of these are so critical that A-Shell cannot run at all without them, while others are more for fine-tuning the system or achieving better compatibility with a particular application. A typical A-Shell configuration file is shown below. Note that anything to the right of a semicolon (comment marker) is ignored.

SERIAL=3401OJGI-6280-BNJ-400695-L1109B ; Serial # and key

CONAME=C:\VM\MIAME\CONAME.DAT ; Licensee file

FILES=40,40 ; 40 files, 40 ISAM

ERSATZ=C:\VM\MIAME\DSK0\001004\ERSATZ.INI ; Ersatz defs

LANGUAGE=C:\VM\MIAME\DSK0\001006\ENGLSH.LDF ; Language defs

CONSOLE=NETUNIQUE,PCTDVG ; Console device

;Device definitions

;Use this format for an individual ppn

DEVICE=DSK0:[1,4] C:\VM\MIAME\DSK0\001004\ ; Individual ppn def

;Use this format for logical disks with implicit \###### ppns

DEVICE=DSK0 C:\VM\MIAME\DSK0\ ; Pathname for DSK0:

;Subroutine aliases (alias-name:ashell-name)

ALIAS=INPUT:INFLD

ALIAS=SPOOL:EZSPL

SBR=CCYY:50,MALLOCSORT

LOKSER=ON ; LOKSER; ISAM sequence checks

PRINTER=LP0 ; Set printer default to LP0

MEMORY=500K ; A-Shell memory partition

QUEUE=100,DISK:C:\VM\MIAME\QFLOCK.SYS ; Q blocks

The file is processed only at the start of an A-Shell session (like the AMOS32.INI file is processed only on booting the system), so for any changes to it to take effect it is therefore necessary to exit A-Shell and start a new session.

Under Windows, the install program will configure your initial miame.ini file to match your install directory, allowing you to at least launch A-Shell with no manual configuration changes. Under UNIX, however, you will need to adjust the miame.ini file manually before launching A-Shell for the first time, unless you installed it in the default (/vm/miame) directory.

You can embed system environment variables in any of the filespecs in miame.ini by using the %ENV-VAR% notation. Some examples:

CONAME=%MIAME%/coname.dat

DEVICE=TMP0:[1,1] %TMP%\

See System Parameters for detailed information on the individual parameters specified within the A-Shell Configuration File.

History

2008 June, A-Shell 5.1.2008: The ini file also permits an optional [MIAME] section header at the top, thereby making it easier to use standard INI-processing routines, including INIX.SBX, for updating it. This capability was added to A-Shell in version 1117 of June 2008.


Color Configuration

Color configuration is an entirely optional step, and may be skipped without penalty.

Although application programs have the ultimate control over the colors that appear on the screen, for applications that do not assume such control, it is possible to customize a number of aspects of the color display by configuration a color initialization file.

When A-Shell launches, it checks if the file DSK0:INI.CLR[7,0] exists, and if so, processes it. If you update the file, or wish to experiment with different color configurations, you can force a new color initialization file to be processed using the SET.LIT command (SET TERM COLORINI <color init file>).

Setting | Description
VUECLR | Allows you to set up the color scheme used by VUE.
EZCLR | Defines the color scheme used by EZSPL (and EZTYP/EZVUE).
INFCLR | Defines the color scheme used with INFLD.
SCNCLR | Defines the initial color scheme to be used when A-Shell launches. The default is 6,0 (green on black).
MMOCLR | Defines the color scheme used with INMEMO.
SCNSIZ | Defines the initial number of rows and columns.

Example

A typical INI.CLR file is shown below. Note that lines that start with semicolons are ignored (comments). The numbers correspond to the color numbers which may be used in the SET TERM FCOLOR # and SET TERM BCOLOR # commands (or in the TAB(-2,x) and TAB(-3,x) BASIC print statements). Note the embedded comment lines that explain the color numbers and the various statement parameters.

; Color Definition File

; Color legend: 0=blk, 1=wht, 2=blu, 3=mag, 4=red

; 5=yel, 6=grn, 7=cyn

; VUECLR=override?,edit fg,edit bg, command fg,

; command bg, help fg, help bg,

; status/info fg,bg

VUECLR=Y,6,0, 5,0, 7,0, 1,0

; EZCLR=override?,text fg,bg, border fg,bg

; cmd fg,bg, sts fg,bg, help fg,bg,

; highlight fg,bg, menu fg,bg, brief menu fg,bg

EZCLR=Y, 6,0, 6,0, 5,0, 0,9, 1,3, 3,6, 5,0, 7,0

; INFCLR=override?,display fg,bg, edit fg,bg

; negative fg,bg, update fg,bg,

; message fg,bg, original msg line fg,bg, forms fg,bg

INFCLR=Y, 1,0, 5,0, 4,0, 7,0, 5,0, 6,0, 9,0

; MMOCLR=Y,border fg,bg, text fg,bg, arrows fg,bg, prompt fg,bg,

; status line fg,bg, protected fg,bg

MMOCLR=Y, 6,0, 7,0, 5,0, 5,0, 5,0, 10,0

; SCNCLR=override?,screen text (fg), screen background

; The following sets up magenta on black

SCNCLR=Y,3,0

; SCNSIZ=rows,cols

SCNSIZ=18,60

Most of the lines begin with an "Override?" option. When set to Y, the color scheme defined on that line will override the default color scheme normally used for that function, or the one which a program has specifically asked to use. Setting it to N is nearly the same as commenting out the line entirely, except for situations where no other color scheme had been set up or specified for that function.

You may set any color number to –1 to indicate that it should use the color which happens to be current at the time the function begins. (Setting all of the numbers to –1 will effectively defeat any color changes within the function.) Also note that making the foreground and background numbers in any pair the same effectively makes that text impossible to see. This is generally a very bad idea, except in some isolated cases. For example, some people don’t like the status line information displayed by EZTYP; you can eliminate it by setting the status line pair of the EZCLR line to 0,0 (black on black)


VUECLR

The VUECLR line allows you to set up the color scheme used by VUE. The first pair of numbers defines the foreground and background colors used for the editing display. The second set defines the colors used in command mode. The third set defines the colors used with for HELP displays. And the fourth pair defines the colors used for status and other information displays. In the example above, this would be green on black for the display mode, yellow on black for the command mode, cyan on black for the help displays, and white on black for the status displays.


EZCLR

The EZCLR line defines the color scheme used by EZSPL (and EZTYP/EZVUE). The concept is the same as that for VUECLR except the color pairs refer to the EZTYP display mode ("text"), graphic line drawing characters used for borders, command mode, status line, help (pop up) display, highlighted search strings, printer selection menu mode, and the brief version of the printer selection prompt/menu.


INFCLR

The INFCLR line defines the color scheme used with INFLD. The pairs refer to display of data (without editing), editing mode, negative numbers (red), the redisplay of a field after it has been edited, the message line (bottom line of screen), the original color of the message line (so it can be returned to its original state), and the color used for forms characters. Note that applications have the option of specifying all of these colors explicitly for each field edited or displayed. If you set the "override" field to Y, this will override any colors specified by the application. However, if the application does not specify colors, then it is not necessary to set override to Y. (In other words, if you set the override option to N, it will only override the color scheme on fields for which the application did not establish its own color scheme.)


MMOCLR

The MMOCLR line defines the color scheme used with INMEMO. Here the pairs refer to the color used to draw the border around the memo, the color of the text within the memo, the color of the navigation arrows (which display on the border), the color of the prompts (top and bottom titles), the color of any status messages, and the color of protected text. Note that these colors also apply to PCKLST.SBR (and any other utility which internally uses INMEMO.) The comments about the override field given above for INFCLR apply here as well.


SCNSIZ

The SCNSIZ line defines the initial number of rows and columns. The default is 24 by 80. Under Windows, rows may range from 1 to 50, and columns may range from 1 to 160. Under UNIX, it depends on the capability of your terminal emulator. In most cases, you will be limited to 24 by 80 or 24 by 132. In the case of ZTERM (Build 144 or higher), the number of rows may vary from 1 to 50.


Help Menu Links

The contents of the A-Shell/Windows Help menu are easily configurable. It is recommended that you take a minute to set up documentation and other help links appropriate for your type of installation. Configuration is accomplished via the text file ASHELP.MDF, which is installed into the DOC subdirectory. A sample copy of the file, as it is included with A-Shell, is shown below.

The documentation set-up step is entirely optional; the presence or absence of documentation files will not affect the operation of A-Shell. If the documentation files are missing, or if the set-up file ASHELP.MDF is damaged or contains invalid data, or even if the entire documentation folder/directory is missing, A-Shell will run without problem—although also without, of course, documentation.

;This file sets up the selections on the A-Shell Help menu.

;

HELP,"h1",SEP

HELP,"&A-Shell Reference",REG,"http://www.microsabio.net/dist/60rel/doc/conref/00ashref.htm"

;

;The previously separate Setup Guide, Commands Ref, Xcall Ref, and Dev Guide are now all included in the above Reference

;

HELP,"&Release Notes",REG,"http://www.microsabio.net/dist/60rel/doc/ashdevnotes/00ashdevnotes.htm"

;

HELP,"h2",SEP

;

HELP,"A-Shell &Documentation Home",REG,"http://www.microsabio.com/documents.html"

;

;Add your app's docs here...

HELP "h3",SEP

The above ASHELP.MDF produces the following help menu:

The lines that start with semicolons are comments and are ignored.

The first field on each line (HELP) indicates that it applies to the Help menu. The second field indicates the text that will appear in the menu item, unless the menu type (third field) is "SEP" (i.e. separator), in which case the second field just needs to be a unique string used internally for identification. The third field indicates the type of menu item. The most likely choices are SEP (separator) or REG, which means that the file or URL in the fourth field will be launched according the Windows file-type association in the Registry. The fourth and last field is the document file or URL to be launched. If it is a file spec, you must include the complete path, unless it is in the DOC subdirectory (where the ASHELP.MDF file itself is.)

You can (and are encouraged to) edit this file, using any text editor. In addition to removing or commenting out links that you don't want, you can add links for your own application documentation, as well as any links to sites frequently referenced by A-Shell users, such as government, shipping, legal, search, dictionary, etc.

A complete listing of available A-Shell documentation is always available from the A-Shell web site on the downloads...documents page.


System Parameters

Following is a list of the A-Shell system parameters, the terms that are used as verbs in the A-Shell configuration file, miame.ini. All lines except comments must begin with one of these parameters followed by an equals sign. They are listed here in alphabetic order, and may appear in any order within the miame.ini file, except for SERIAL, which must be the first non-comment line of the file and is therefore listed first in the following table. See Boolean Arguments in INI Files if needed.

Parameter | Description | Parameter | Description
SERIAL | Define A-Shell serial number | MAPIDA | Enable/disable ISAM Plus extension mapping
ALIAS | Specify A-Shell subroutine aliases | MAXINST | Specify max A-Shell instances per workstation
ATETIMEOUT | Set the ATE timeout period | MAXJOBS | Specify maximum number of jobs total
CHARSET | Specify A-Shell character set | MAXLOCKS | Specify max locks to track for LOKSER
CONAME | Specify location of licensee name file | MEMORY | Specify A-Shell memory partition
CONSOLE | Define console device format and default driver | MMAPLIST | Specify files to be automatically memory mapped
DEVICE | Map devices to host machine pathnames | OPTIONS | Set miscellaneous A-Shell options
ERSATZ | Specify ERSATZ definition file | POLYKEY | Define PolyShell hot key
FILES | Specify A-Shell FILE buffers | PRINTER | Define default printer name
FKEYWAIT | Specify delay following function key lead in | QUEUE | Specify A-Shell queuing system
FLDATTR | Enable/disable field attributes | QUITKEY | Define or disable UNIX QUIT key
FONT | Specify A-Shell font face name (Windows only) | SBR | Tune operation of A-Shell XCALL subroutines
IATIMEOUT | Define idle timeout | SSD | Define returned SSD sequence
IJCFREQ | Define frequency of Inter Job Communication clock | SWAPKEY | Define PolyShell swap key
INCLUDE | Include specified file | SWAPWAIT | Specify delay after screen swap
JOBPREFIX | Specify jobname prefix for auto-named jobs | TRACE | Activate debugging options
LANGUAGE | Specify language definition file | TRMDEF | Define terminal characteristics
LOGDIR | Specify location of ashlog.log file | UMASK | Specify default file creation mask
LOKSER | Specify LOKSER operation | XONXOFF | Enable or disable XON/XOFF protocol
MALLOCLIMIT | Specify limit on dynamic memory allocations |  |


SERIAL

Updated June 2008

SERIAL=Serial Security key

This parameter must be present in order for A-Shell to run, and it must be the first line of the file except for comments (see History, below).

If the security key field is set to DEMONSTRATIONXX, then A-Shell will operate in demonstration mode. If the field is set to XXXXXXXXXXXXXXX, then the first time A-Shell is invoked, then the correct security key will be requested:

A-Shell Serial Number:

A-Shell Serial # nnnn security key:

Company name:

You should then enter the serial number, security key and company name as listed in the A-Shell license paperwork which accompanied the A-Shell software. This key will then overwrite the SERIAL line in miame.ini. An incorrect security key will cause A-Shell to operate in demonstration mode.

Use the LICENS command (from the A-Shell prompt) to force A-Shell to prompt for a new security key.

The security key and company name must match, although the case and punctuation of the company name are not important.

Note that the SERIAL line in miame.ini can be replaced with an INCLUDE=<fspec> line, where <fspec> is the full native filespec of a file which contains SERIAL. This feature is to allow firms supporting multiple A-Shell installations to maintain just one miame.ini for all the installations, while storing the one thing that is unique—the SERIAL specification—in a separate file.

History

2008 June, A-Shell 5.1.1117: Beginning with this update it is possible to have comments (starting with either ; or #) appear in the file above the SERIAL line. Prior to this update, SERIAL had to be the first line of the file in order for A-Shell to run.


ALIAS

ALIAS=newsbr:oldsbr

Under AMOS, many different XCALL subroutines have been developed over the years which often perform identical (or compatible) functions, but which have been given different names. Software developers have also written routines to replace or supersede those supplied with AMOS. An example of this type of routine is EZSPL.SBR from MicroSabio, which may be used as a direct replacement for SPOOL.SBR. A-Shell contains the C version of EZSPL.SBR as standard. Rather than have an identical definition for SPOOL.SBR, an alias is defined, saying whenever the line XCALL SPOOL is encountered, treat it as the line XCALL EZSPL:

ALIAS=SPOOL:EZSPL

Note that you can effectively disable a subroutine by aliasing it to a subroutine that does nothing. One such subroutine, under A-Shell, is PRIV.SBR, since the concept of write protection for accesses out of the "project" does not exist under any of the target operating systems for A-Shell.

There is a limit of 50 ALIAS statements.

Note that the ALIAS facility only works when the two subroutines have compatible parameter lists. If you need a subroutine which is similar to one we already offer but with different parameters, you can probably create your own SBX version as a wrapper to the existing one. See SBX Subroutines for details on writing your own subroutines. You may also contact MicroSabio for an estimate to add your routine to the set of standard embedded routines included with A-Shell. Typically these are very inexpensive to add.


ATETIMEOUT

Added December 2014

ATETIMEOUT=<milliseconds>

This allows you to change the default ATE command/response time out from the standard 7500 milliseconds to something else. Depending on your network, you may find that 7500 is too low, producing spurious timeout conditions, or too high.

History

2014 December, A-Shell 6.1.1399: Function added to A-Shell.


CHARSET

CHARSET=<charset name>

Examples: CHARSET=US

CHARSET=LATIN1

(Windows only) Under A-Shell/Windows, this parameter may be used to specify the character set used by the application, per the table below. Note that the CHARSET options may be abbreviated to the characters shown in parentheses in the table, but they must be in upper case.

CHARSET | Notes
US | (Default) Standard ASCII.
UK | British national replacement character set. The # or £ keys return ASCII character 35, and character 35 is always displayed as £.
FRENCH (FR) | French AZERTY
GERMAN (GER) | German
PORTUGUESE (PORT) | Portuguese
SPANISH (SPA) | Spanish
SWISS | Swiss
ITALIAN (ITAL) | Italian
DANISH (DAN) | Danish
SWE-FIN | Swedish/Fin
LATIN1 | Use 8 bit Latin1 characters. (All of the non-ASCII characters referenced above would need to be specified as 8 bit values in the range of 128-255.) Equivalent to OPTIONS=LATIN1.

CHARSET is related to, but not the same, as the symbol set parameter on the FONT statement (which see). The font symbol set is mainly of internal significance to A-Shell, while the character set specified with CHARSET must match up with the way your application encodes non-ASCII characters. It is highly recommended that you use the 8 bit LATIN1 character set for displaying non-ASCII characters, rather than one of the 7 bit national replacement character sets, since Latin1 is much more portable and standard under Windows.

In order for any of the character set choices above, other than US and LATIN1, to be effective, you must specify the OEM symbol set in the FONT statement.

The CHARSET statement replaces the special terminal driver names previously used with the CONSOLE statement (which see) to specify national replacement character sets. That is, setting the terminal driver to PCUK (rather than PCTDV) has no effect; you must instead specify CHARSET=UK.


CONAME

CONAME=Pathname of company name file

On installation of A-Shell, the security key field is tied to a specific company name (the Licensee company), which is stored in the file specified in the CONAME line of miame.ini. This is done by prompting for the Licensee when entering the security key after A-Shell is run for the first time:

A-Shell Licensee (company name):

The location of the CONAME file is specified in terms of its native operating system (e.g. C:\VM\MIAME\CONAME.DAT) rather than in AMOS format. You may, however, place it in a directory which also maps to a ppn to allow easy access from within A-Shell. For example, applications may read this file as a form of copy protection, since, although it is a straight text file, alteration of its contents will cause A-Shell to operate in demonstration mode.

Since the CONAME file must be shared by all users on a network, it must be placed on the server, and referenced either via a mapped drive letter or a UNC (\\server\share\path\coname.dat) name.


CONSOLE

Updated May 2016; see History

CONSOLE=<idformat>{,drivername}

This statement establishes an internal identifier for the instance, and optionally a terminal driver. Over the years is has devolved to become a nearly bottomless pit of complexity and confusion, but fortunately, in 99% of the cases, you can just set it to the following:

CONSOLE=NETUNIQUE,<tdvname> ; windows networks

The <tdvname> parameter should be either PCTDVG or PCTDV, with the only difference being that the PCTDVG version implements certain GUI improvements, such as the conversion of text message boxes to Windows dialog boxes.

Historically, certain national replacement character set variations of the terminal driver were supported, such as PCUK and PCFR. This function has been taken over by the CHARSET statement.

The NETUNIQUE option on the CONSOLE statement generates a unique identifier for each A-Shell session, made up of the NetBios computer name, followed by a colon and a numeric suffix indicating the instance number. (The computer name may be set via the Windows Control Panel, using the Networks applet under W9x and the System applet in subsequent versions.) Other options exist, but are for all practical purposes obsolete now.

You can see these identifiers with SYSTAT/C. You can also retrieve your own identifier with the subroutine GETUSN.

If you establish meaningful computer names, then these console identifiers are probably more useful than AMOS-style job names. But since job names are so embedded in AlphaBASIC applications, A-Shell also generates them using the TSKAAA, TSKAAB, etc. format. If you don't like the dynamically generated job names, you can override them by using the –j <jobnam> command line switch, or you can create a cross-reference association between console identifiers and job names using TRMDEF statements.

Because the console device name is used by the TRMDEF parameters, the CONSOLE statement must occur before any TRMDEF specifications.

History

2015 May, A-Shell 6.1.1408: Windows enhancement: A-Shell now detects duplicate machine names. Previousy, this would have led to the nth instance on machine 2 overwriting the JOBTBL record for the nth instance on machine 1. In order for this to work, you must run the installer/updater to update each workstation, rather than manually installing the update by copying files. It is also important to update the six LIT commands, described in the next item, although the installer will normally take care of this for you.

The installer/updater establishes a unique identifier for each machine and saves it in the HKLM section of the registry, to be used to determine whether an instance with the same machine name as an existing instance is actually the same machine or not. If so, then the new instance can safely overwrite the old one. But if not, an error message is displayed and the new session is not allowed to start.

The error message will indicate the machine name, the user name and jobname of the offending existing instance, and the unique identifiers (8 hex digits) for the two machines. You can use the new SYSTAT/CU switch to display the unique identifiers for existing sessions, which may be helpful in tracking down the offending duplicate-named machine.

Note that duplicate named machines can cause all kinds of problems for Windows networking, but it is not always detected. This new feature should help avoid the ensuing problems in both A-Shell and in the network in general.

Also note that the issue only affects P2P networks; ATE, Terminal Server, and UNIX systems are not subject to the problem and are not affected by the update.


DEVICE

DEVICE=Devicename Pathname

DEVICE=Devicename:[Proj,Prog] Pathname

The DEVICE statement allows you to map AMOS-style logical devices and PPNs to UNIX- or Windows-style paths. There are two variations of this mapping operation.

• The first, and most common, maps an AMOS-style logical disk (e.g. DSK1:) to a base directory (e.g. /vm/miame/dsk1/). The PPN equivalents are then set up as subdirectories of this base directory using the format <base directory>/pppnnn (corresponding to <logical disk:>[ppp,nnn]).

• The second variation overrides the implicit PPN subdirectory scheme just described, by specifying a complete and explicit directory to be associated with a specific devn:[ppp,nnn].

As an example, consider the following two DEVICE statements:

DEVICE=DSK1:[31,3] /usr/include/

DEVICE=DSK1 /vm/miame/dsk1/

on a UNIX-based machine. Together, these statements would be used by A-Shell / MIAME to map the specification DSK1:TEST.DAT[31,5] onto the path /vm/miame/dsk1/031005/test.dat.

The file name is mapped onto lower case. UNIX treats case as significant in filenames, whereas AMOS does not, so in keeping with the UNIX norm all filenames must be converted to lower case regardless of the case used inside of your source programs or in arguments to LIT utilities (e.g. DIR.LIT).

However, the file specification DSK1:TSTCPY.CPY[31,3] would instead be mapped onto the pathname /usr/include/tstcpy.cpy, since it matches the first DEVICE statement.

Note that in both cases, the host pathname must terminate with a directory separator character. Failure to do this will cause unexpected results.

In Windows network environments, you can substitute UNC-style names (Universal Naming Convention) in place of the DOS drive letter in these DEVICE statements. For example:

DEVICE=DSK1 f:\vm\miame\dsk1\

DEVICE=DSK2 \\kahuna\ashell\dsk2\

In the first DEVICE statement, logical device DSK1: is defined as being on the F: drive (which presumably is a mapped network drive.) In the second, DSK2: is defined as being at a location defined by the share name "ashell" on the server named "kahuna". The advantage to the UNC approach is that it eliminates the need to map the same (or any) drive letter on each client workstation to the server, thus simplifying the setup of client workstations in a network. The only known downside to this approach is that due to a bug in Windows 95, SYSTAT will not be able to report the number of free blocks on any device which is defined this way. But this is a relatively minor concern, and the bug is fixed in later versions of Windows.

Although not recommended, if you insist on mapping AMOS-style devices to directories that contain spaces, you can do so by enclosing the directory specification in quotes, as in this example:

DEVICE=XYZ0:[1,1] "C:\Program Files\COOL.STF\ZTERM For Windows\"

It should be noted that due to the automatic generation of pathnames from PPNs, and because AMOS-style filenames are restricted to thirteen (10.3) characters (as well as the case problem under UNIX) there are many files that cannot be accessed via an AMOS file specification. This mapping of an AMOS file specification (using the definitions described here) is performed by the fspec2host() function. To solve the file-inaccessibility problem, if the AMOS specification passed to fspec2host() contains a directory separator character ( / or \ ) then no attempted mapping to a pathname takes place. Under A-Shell, programs could be written to directly manipulate any files on the system (file protection permitting), for example:

open #1,"c:\autoexec.bat", input

..

In order to access a file in the current working directory whose name doesn't fit the 10.3 limit, or which contains upper-case characters or no extension under UNIX, then it is necessary to specify a path containing the current directory symbol ".", for example:

kill "./core"

The following special form of the DEVICE statement may be used to define a device that references user memory:

DEVICE=MEM: MEM:

Technically, you could use any device name for the logical name (the first MEM:) but the physical name (the second MEM:) must be MEM: (in upper case, with the colon on the end).

If you already have a PPN-specific MEM: or MEM0: device defined, then it must be defined first, i.e.:

DEVICE=MEM0:[1,1] /tmp

DEVICE=MEM: MEM:

Make sure there is no MEM: in your ERSATZ.INI file. (ERSATZ devices are processed first.) Obviously, if you are using the MEM: ersatz, you will want to make other arrangements. However, it you are too committed to using MEM: as an ersatz disk device, then you could use some other logical name to refer to user memory. For example, DEVICE=RAM: MEM: would define a logical device named "RAM:" which referred to the physical device MEM: (user memory).

Notes

Only those devices defined explicitly with a DEVICE line are allowable in an AMOS file specification. All others will report Device does not exist or Invalid filename messages, depending on the context.

If the configuration file contains both full device/PPN definitions and a default device definition for a given drive, then the full device/PPN definitions must appear first.

Under Windows, the host pathname may include the drive letter and a colon at the start, followed by the full pathname beginning (and ending) with a directory separator character; or, it may use the UNC format (\\server\sharename\path\).

Caution: If you use a DEVICE statement to define specific a specific PPN (as opposed to entire DSKs), make sure that the PPN so defined does not also exist in the location defined for the DSK. If you create a situation where the PPN exists twice, then the DIR command will display the files in both locations. This is a special case of a larger problem with DIR, in that DIR scans the raw directory, then for each entry found, tries to display it as if it were an AMOS file, using a backwards translation from the raw directory spec to the AMOS equivalent. This causes DIR to find things, both files and directories, that might otherwise not be quite what was intended by a particular set of DEVICE definitions. The only solution would be to then do another forward translation of the found AMOS spec back to the native spec to compare when that native spec matched the one found by DIR, but that would slow DIR down considerably.

Examples

For both Windows and UNIX, the host pathname may contain system environment variables, using the syntax %VAR%:

DEVICE=USR0:[1,1] %HOME%/

DEVICE=TMP0:[1,1] %TMP%\

DEVICE=DSK0 %MIAME%\dsk0\

The first example makes USR0:[1,1] map to the current user's home directory (assuming that the environment variable HOME was defined by the user's shell). Note that even though the normal syntax for environment variables under UNIX is $VAR, A-Shell uses %VAR%.

The second example makes TMP0:[1,1] map to the user's TMP directory (in this case assuming that the TMP environment variable was defined on the PC, either for the machine or for the login user).

The last example illustrates that the environment variable can be combined with other static elements.


EFSEXT

EFSEXT=ext1 {,ext2, ext3,...ext10}

If you are using A-Shell's Encrypted File System (EFS), this command allows you to specify which extensions are to be encrypted. Whenever a file is created (either via OPEN for output or ALLOCATE), if the extension is in the EFSEXT list, and encryption is supported, and has not been disabled via XCALL ASFLAG,1024, then the file will be created as an encrypted file.

Note that EFS is an entire system for file encryption and security, is not included in the standard release of A-Shell, (must be licensed as an option), and should be carefully considered before being implemented. If you are interested in implementing this filing system, (a) see the documentation on the EFS subroutine, and (b) contact and discuss with MicroSabio.

History

2006 May, A-Shell 4.9.956: Function added to A-Shell.


ERSATZ

Updated March 2011

ERSATZ=Pathname

Example: ERSATZ=C:\VM\MIAME\DSK0\001004\ERSATZ.INI

A-Shell supports ersatz devices in nearly the same way as does AMOS. They are defined in standard format ERSATZ definition files, which should be located in the file and path given (in host operating system format) in the ERSATZ command lines. Any number of ERSATZ command lines may be present in the configuration file.

As an added enhancement, the A-Shell implementation of ersatz definitions allows you to add to the list of definitions without having to close and re-launch the A-Shell session. (If there are multiple ersatz definition files, only the last one can be updated this way while A-Shell is running.) The way it works is that if A-Shell attempts to look up an ersatz definition and it is not found, and at least 30 seconds have passed since the last time it reloaded the ersatz definition file, in then reloads the last ersatz definition file to see if there are any new definitions. The 30 second limit is to prevent excessive thrashing if a rash of undefined ersatz names are encountered in sequence.

Any ERSATZ devices containing CPU numbers will be ignored.

The maximum number of ERSATZ device definitions allowed is 1000 for A-Shell/UNIX and A-Shell/Windows/32.

The maximum length of the ERSATZ filespec is 160 characters.

History

2011 March, A-Shell 5.1.1208: Increase maximum filespec length from 70 characters to 160.

Subtopics

Ersatz Definition Files


Ersatz Definition Files

Updated October 2014

Ersatz devices are defined in one or more ersatz definition files, each of which is activated by a corresponding ERSATZ statement in the miame.ini. By convention, these files are stored in the DSK0:[1,4] directory, with the first (and main) one being called ERSATZ.INI. If there are additional ersatz definition files, these are typically named xxxxx.ERZ where xxxxx is some kind of helpful allusion to the source or nature of the definitions contained in that file.

Each ersatz definition file line must match one of the following formats:

ersatz-device: =real-device:{[p,pn]}

++include real-device:file.erz{[p,pn]}

ersatz-device: =%INCDEV%:{[p,pn]}

Definitions

ersatz-device

the name of the ersatz device being defined: one to ten alphabetic or numeric characters, starting with an alphabetic character, and immediately followed by a colon.

real-device

the name of a "real" device, defined via a DEVICE statement in the miame.ini file. It must be immediately preceded by the equals (=) symbol, and immediately followed by the colon. The real device names must be three or four alphabetic characters, followed by one or two numeric digits, with a maximum length of five combined characters.

[p,pn]

an optional directory. If not included, then the ersatz device name can be used just like a real-device name in file specifications, meaning that you can optionally include a [p,pn] at that time.

file.erz

an arbitrary file name and extension of another ersatz definition file to "include" (i.e. effectively insert) into the current file. Note that contrary to the normal convention of ersatz definition files being in DSK0:[1,4], the ++include feature is most useful with ersatz definition files that are stored on some other device. (See %INCDEV% below for more details.)

%INCDEV%

This literal pseudo-environment variable may be used in place of a real-device reference within an ersatz definition file that has been ++include'd, and will be interpreted as the real-device that was in the ++include statement. See ERSATZ ++INCLUDE Statements for more details.

Whenever A-Shell attempts to decode an AMOS-style filespec, it compares the device part of the specification against the ersatz definitions first, before then comparing against the DEVICE definitions from the miame.ini file. So it is actually possible to "redirect" a real device by redefining it as an ersatz. For example, the ersatz definition DSK1:=DSK0: would effectively redirect all DSK1: references to DSK0:, even if DSK1: was a real device.

If the device is not found in either the list of ersatz definitions or real device definitions, then the last loaded ersatz file (i.e. the one referenced in the last ERSATZ statement in the miame.ini) will be reloaded, assuming that a minute has passed since the last time it was reloaded. So you can effectively add ersatz definitions without re-launching A-Shell, although the value of this is limited since re-launching A-Shell only takes a few seconds.

Examples

Valid ersatz file entries look like this:

SYS:=DSK0:[1,4]

LIB: =DSK0:[7,0]

DSK100: =DSK99:

AA12345678:=ZZZ12:[345,678]

The ersatz definition file that is distributed with A-Shell and invoked by default, ERSATZ.INI, looks like this:

OPR:=DSK0:[1,2]

SYS:=DSK0:[1,4]

DVR:=DSK0:[1,6]

CMD:=DSK0:[2,2]

LIB:=DSK0:[7,0]

HLP:=DSK0:[7,1]

BOX:=DSK0:[7,2]

BAS:=DSK0:[7,6]

SBX:=DSK0:[7,6]

MAC:=DSK0:[7,7]

ASHCFG:=DSK0:[1,7]

PTR:=DSK0:[1,7]

ASHLPD:=DSK0:[1,25]

FAXWRK:=DSK0:[1,26]

ASHBAS:=DSK0:[907,6]

ASHINC:=DSK0:[907,16]

Another example:

++include SOS6:SOSLIB.ERZ[1,4]

Within an ersatz definition file that has been ++included, the following would be legal:

SOSFUNC:=%INCDEV%:[907,10]

History

2014 October, A-Shell 6.1.1393: Add ++include capabilities

Subtopics

ERSATZ ++INCLUDE Statements


ERSATZ ++INCLUDE Statements

Added October 2014

ERSATZ definition enhancement: ersatz definition files may contain ++include statements of the form:

++include dev:file.erz[p,pn]

In addition, the dev specified in the ++include statement may then be referenced from within the included file using the pseudo-environment variable %INCDEV%, e.g.

ADCJSON:=%INCDEV%:[907,10]

The combination of these two enhancements facilitates the ad-hoc addition of modular sets of current-device-relative ersatz definitions. As an example, for the 2014 A-Shell Developer Conference, we created a set of ersatz definitions, in the file ADC.ERZ:

ADCARY:=%INCDEV%:[908,61]

ADCCGI:=%INCDEV%:[908,62]

ADCJSON:=%INCDEV%:[908,63]

Because there is no explicit device reference, these ersatz directories can be installed on any available device on the target machine, assuming no conflicting ppns. Let's say we want to use an existing device DSK29:. To install the ersatz definitions copy the ADC.ERZ file to any ppn on DSK29, let's say DSK29:[1,2]. Then just add a ++include reference to it in the main system ersatz.ini:

++include DSK29:ADC.ERZ[1,2]

Note: "main system ersatz.ini" refers to last one referenced in the miame.ini, since that is the only one that will be reprocessed on the fly, which is an essential part of this scheme.

Now, without re-launching A-Shell, you can use those ersatz definitions, i.e. LOG ADCJSON:

Aside from ad-hoc ersatz additions like this, the feature is also useful for maintaining different versions of the same ersatz definitions. For example, you might have a set of ersatz definitions for your application, but you also want to maintain two versions, the stable version and the development version. With this scheme, you can use a single app.erz file containing your ersatz definitions, and just install it and the associated directories on two different devices. By avoiding the need to explicitly reference the devices, you avoid the hassle of having to convert the device reference to match the actual device where you installed it, as well as the confusion that occurs when you forget to do that.

WARNING: If the applicable ERSATZ statement in the MIAME.INI comes before the DEVICE statement that defines the device referenced in the ++INCLUDE, it won't be resolved until after A-Shell is launched and a subsequent reference is made to the ersatz. Failed references trigger a re-scan of the ersatz definitions, after a small time interval. So that generally isn't a problem. BUT, in the case of the APN compiler command line, it only gets one chance to define the ersatzes, so if you are using this technique, move the ERSATZ statement(s) below the DEVICE statements.

History

2014 October, A-Shell 6.1.1393: Add ++include capabilities


FILES

FILES=<# File buffers>,<# ISAM buffers>

Example: FILES=40,40

In order to keep track of files opened within AlphaBASIC programs, A-Shell allocates internal file buffers within the memory partition (see MEMORY statement.) Each file buffer requires approximately 80 bytes, and each ISAM buffer approximately 300 bytes. In order to save memory, or to support an extended number of files, the number of buffers may be changed, according to the following rules. Note that the buffer values refer to the maximum number of files which may be simultaneously open at any one time.

ISAM buffers are only used for ISAM 1.0 files. If your application makes use of only sequential, random, and ISAM PLUS files, the number of ISAM buffers may be set to zero. Sequential, random, and ISAM PLUS files require only a single FILE buffer each. An ISAM 1.0 file requires two FILE buffers and one ISAM buffer for the initial open of the main index, while each subsequent secondary index requires just one FILE buffer, and one ISAM buffer.

Notes

The default number of buffers is 40 FILE and 40 ISAM, in order to maintain compatibility with earlier versions of A-Shell.

The FILES parameter only adjusts A-Shell’s internal resource allocations; you may need to adjust the parameters for your operating system locking mechanism to allocate enough locking resources for large numbers of open files.+

The operating system and/or environment may further impose limits on the maximum number of open files. Under UNIX, there are typically kernel configuration variables which set the limit, although it may be further limited by the shell.


FKEYWAIT

FKEYWAIT=<# ms>

Example: FKEYWAIT=50

(UNIX Only) Most "function keys" send multiple bytes. In order to distinguish between a true multi-byte sequence and a series of individual single-byte keystrokes, A-Shell considers the time delay between the first byte (the "leadin") and the following byte. In practice, this means that whenever A-Shell sees a byte that could be a "leadin" (typically Escape or Ctrl+A), it does a timed input operation for the next byte. If one or more bytes arrive within the specified interval, then it is considered a multi-byte sequence, otherwise the initial byte is treated as a stand-alone character. Under normal circumstances, the default 5 ms. (five one-thousandths of a second) wait is sufficient, but still short enough that you don’t notice the delay. However, in some cases, the delay between the "leadin" and the following bytes can be substantially longer. One example of this occurs when using rlogin instead of telnet to log into a remote system. In that case, you may need to specify a much longer delay, perhaps as much as 200 ms.

If the FKEYWAIT value is too short, function keys may stop working properly, and will instead typically put some kind of garbage on the screen. However, the longer the wait, the longer you have to wait before an individual Escape or Ctrl+A is acted on. For example, in VUE, the Escape character switches between edit and command mode. If you like to switch quickly between these modes, you may find that a 200 ms delay in response to the Escape key is unbearable. So the advice is to use experimentation to get the FKEYWAIT value as low as possible without causing your function keys to break up.

Since the required FKEYWAIT value may change from terminal to terminal, you may also change this on a job-by-job value at runtime using SET.LIT (type SET /? from the A-Shell prompt to display help info).


FLDATTR

FLDATTR=ON/OFF (default is ON)

This option may be used to disable "field" attributes, to avoid display problems caused by programs assuming "field" emulation, when the actual display device is operating as a "mode" terminal. See FIELDEMU under OPTIONS for a discussion of the difference between "field" and "mode" emulations.

When FLDATTR=OFF, "field" attribute commands, such as reverse video and underline, are ignored. Doing without your reverse video and underline highlights is better than having them spill over the screen incorrectly, as would otherwise happen if your application was not written to support both field and mode emulations.

FLDATTR=OFF is equivalent to OPTIONS=NOFLDATTR.


FONT

FONT=<facename> {,<symbol set>}

Examples: FONT=Courier New (default)

FONT=Lucida Console, ANSI

Under A-Shell/Windows, FONT may be used to specify two aspects of the font: the face name and the symbol set. The face is the name that appears in standard font selection dialog boxes (including the one on A-Shell's Edit menu), such as Courier New or Lucida Console. It is case sensitive. If not specified, A-Shell will select what it thinks is the best font from the available choices—i.e., those installed on this system. Common choices are Courier New, Lucida Console, and Consolas..

The symbol set may optionally be specified as OEM, ANSI, or DEFAULT. If not specified, OEM is used.

The face name will be overridden by a font specified in the default.ash or other settings file. (See the –Settings File switch and the

See Also

• Color Customization

Font

topic for more details.) However, the symbol set will affect all subsequent font selections, even overriding a previously saved font in the settings file.

The only fonts suitable for A-Shell are those that offer a fixed pitch, so that typically limits you to Courier New, Lucida Console, and Consolas (on Vista-or-later PCs). Miame Terminal and Andale Mono were frequently used in older versions of Windows and A-Shell, but they are no longer convenient; Miame Terminal because it is a bitmap font that doesn't scale well, and Andale because it is now available only for a fee.

The symbol set determines which characters are available and how they are numbered. Most of the fixed pitch fonts support both OEM and ANSI. Fortunately, both character sets use the same values for the ASCII printable characters 32-127, so it probably makes little difference in most applications which one you use. Furthermore, both character sets include the Latin1 characters in the range 128-255, and although they are mapped differently, if you specify OPTIONS=LATIN1 A-Shell will convert both mappings to match the Latin1 mapping used under AMOS (such as with the AM65A terminal).

Historically, the main problem with the ANSI character set in A-Shell was that it didn't include the line drawing characters, but this is no longer an issue since A-Shell renders them graphically. The only remaining shortcoming is its lack of a few special characters available in the alternate character set via TAB(-1,65) thru TAB(-1,77) commands (raised dot, end of line, horizontal tab, paragraph, dagger, section, cent, quarter, half, trademark, copyright, register mark). On the other hand, the OEM character sets (except for the MIAME Terminal version) do not include a Euro symbol. With ANSI , you can display a Euro symbol via TAB(-1,253) or chr(128).

Note that Windows applications such as A-Shell can only make "requests" for a particular font. The system then provides a font that is the best match for the requirements given. Thus, you can easily end up with an unexpected font if your system does not have the requested font installed. For example, if you ask for Andale Mono but it isn't installed, it should try to select something with similar capabilities, hopefully (but not necessarily) ending up with a font reasonably like Courier New.

The actual font and symbol set in use is identified on the A-Shell/Windows Help...About box.

In order to use a national replacement character set, you must specify the OEM symbol set. See the CONSOLE and CHARSET parameters.


IATIMEOUT

IATIMEOUT=<minutes>

Example: IATIMEOUT=60

The IATIMEOUT parameter activates an inactivity timer that will shut down a session if it has been inactive (no keyboard or BASIC/LIT instructions) for at least that many minutes. In practice, the actual delay until the timeout is detected and the job is shutdown may be as much as twice the specified number of minutes. The default value is 0, meaning no inactivity timer.

The –cgi command line switch automatically sets the IATIMEOUT to 7 seconds.


IJCFREQ

IJCFREQ=<seconds>

Example: IJCFREQ=10

The IJCFREQ parameter activates a timer interrupt that checks for "Inter Job Communication" (IJC) messages. These include inactivity timeout checks (see IATIMEOUT above), and SEND.LIT and KILL.LIT under A-Shell/Windows. (The UNIX version of these commands uses the more powerful and direct UNIX signals.) The default value is automatically determined based on the number of users licensed, and will be in the range of 5 to 30 seconds. To disable the timer and the corresponding functions, set IJCFREQ=0. Note that in the Windows world, checking for IJC messages involves reading a record from JOBTBL.SYS on the server, and thus you don’t want to make it any more frequent than necessary. But if you set the value too high, you could have to wait for a long time to get a response from a KILL or SEND command.


INCLUDE

INCLUDE=filename

Example: INCLUDE=f:\miame\trmdef.ini

The INCLUDE parameter is the equivalent of the C #include or AlphaBASIC ++include directive. It forces the inclusion at that point of another file which itself contains any of the valid configuration file commands, with the exception of INCLUDE itself.

The typical use of this command is to reference a file containing TRMDEF statements, as shown in the example above.

Another way you might use this command is to separate the statements which may differ from one user to another from the main body of the miame.ini file.

Note that most users can get by without including a TRMDEF.INI file, since A-Shell will, by default, generate names of the form TSKAAA, TSKAAB, etc., for the jobs and terminals as needed. TRMDEF.INI is only relevant if you want to predefine certain job and/or terminal names to be associated with specific terminal devices.

The INCLUDE command may replace the SERIAL command as the first line of the file (provided that the file being included starts with a SERIAL line. This is useful if you want to have identical miame.ini files across many systems (each referencing a separate file for the SERIAL information, i.e. INCLUDE=SERIAL.INC.)


JOBPREFIX

JOBPREFIX=<up to 3 prefix characters>

Example: JOBPREFIX=JOB

Default: JOBPREFIX=TSK

JOBPREFIX allows you to override the default jobname prefix ("TSK") which is used to generate unique job names. The prefix is normally 3 characters, to which A-Shell appends a sequentially generated suffix (e.g. "AAA", "AAB", etc.) resulting in job names like TSKAAA, TSKAAB, TSKAAC, etc.

Job names can also be specified by the TRMDEF statement or by use of the –j <jobname> command line argument.


LANGUAGE

LANGUAGE=Pathname

Example: LANGUAGE=C:\VM\MIAME\DSK0\001006\ENGLSH.LDF

A-Shell supports the language definition file in exactly the same way as does AMOS, though currently multiple languages are not supported. The file and pathname given in the LANGUAGE command line specifies a standard AMOS 2.x format language file. As with the specification of ERSATZ files, if the files are desired in DSK0:[1,6], then the full (host) pathname must be used, for example /u/miame/dsk0/001006/englsh.ldf.

The language file is supported via the MIAME gtlang() implementation of the monitor call and GTLANG.SBR within A-Shell. A-Shell also makes use of the language file in its implementation of DATE.LIT, TIME.LIT, PRINT USING masks, VAL(), and in displaying PPNs.

Note that A-Shell stores system error messages in DSK0:ERRMSG.???[1,4], XCALL subroutine messages in DSK0:SBRMSG.???[1,4] and PolyShell (UNIX version only) messages in DSK0:PSHMSG.???[1,4]. The extension (???) used is that defined as the language extension in the specified language file.

History

2009 January, A-Shell 5.1.1136: LDF enhancements: New LDF files (each named by appending an "X" to the existing name) have been created to add a standard Latin 1 character collating sequence for the upper 128 characters. This may be an interim measure until we decide whether there is any reason not to just update the standard LDFs with the collating sequence. Until then, if you are interested in the collating sequence, either rename the "X" version to the standard name, or change the miame.ini ERSATZ statement to reference the "X" version of the LDF.


LOGDIR

LOGDIR=<native directory specification>

Examples: LOGDIR=/vm/miame/dsk0/001002

LOGDIR=C:\TEMP

LOGDIR=$MIAME/log

The optional LOGDIR parameter allows you to specify a different directory for the A-Shell log file (ashlog.log) than the standard one, which is the same directory where the miame.ini file is stored. You must specify a directory using native operating system syntax, but you may optionally include environment variable names (such as $MIAME in one of the examples above.)


LOKSER

LOKSER=['ON' | 'OFF'] {,FORCE_WRITE}

This command specifies whether LOKSER is to be emulated.

Under AlphaBASIC and A-Shell, shared file access may be controlled using either the older FLOCK.SBR / XLOCK.SBR or via LOKSER. In the case of LOKSER, a file opened for RANDOM processing is considered open for exclusive use, while for shared use it must be opened RANDOM’FORCED. Since many AlphaBASIC applications were written using FLOCK.SBR, which does not distinguish between RANDOM and RANDOM’FORCED, it is very inconvenient to have files effectively being exclusively opened when not required. For this reason, many Alpha Micro sites do not use LOKSER.

If LOKSER is turned off under A-Shell, there is no difference in operation between RANDOM and RANDOM’FORCED files, and no automatic locking occurs in conjunction with OPEN, READ and WRITE statements. If LOKSER is turned on, then full file locking occurs with all the AlphaBASIC locking errors being trapped. Because of the nature of the LOKSER implementation on Windows and UNIX-based systems, the problem whereby locking a record exclusively would effectively lock all records in the same block, does not occur, as it does under pre-2.0 releases of AMOS.

Under AMOS, use of RANDOM’FORCED and INDEXED files force every write operation to actually be flushed to disk. This is necessary in order to get correct multi-user interaction due to the nature of the operating system. Under operating systems such as UNIX, or Windows, it is not necessary for the latest change to a file to actually be flushed to disk in order to be seen by other processes. The default operation of A-Shell is therefore not to flush on every write but to leave this a decision for the controlling operating environment.

On non-robust machines such as PCs, flushing to disk can be of particular importance, particularly if the PC is likely to be turned off or lose battery power at any time. The FORCE_WRITE modifier may be specified in this case which will cause such flushing to take place. and it may be specified both with and without the locking aspect of LOKSER.

Note that FORCE_WRITE only has effect under A-Shell/DOS. Due to its potential effect on performance, it is not recommended that it be used except where absolutely necessary. For example it would not be used on an optimized machine running Windows 95 which has write-behind caching enabled.

Under AMOS, the enabling of LOKSER also enables the seemingly unrelated feature of ISAM sequence checking for ISAM 1.0. This performs checks on the order of ISAM 1.0 file accesses, preventing for example an ISAM add record being performed without an ISAM search to see if that record exists. Under A-Shell, ISAM sequence checking is also enabled if LOKSER is turned on:

LOKSER=ON{,FORCE_WRITE}

Notes

Under A-Shell, ISAM sequence checking is controlled by the value of the LOKSER command, on both UNIX and Windows systems.

There is no equivalent of the LOKSER database. Either all files are controlled or none. This is analogous to the operation of LOKSER under AMOS 2.0.

ISAM Plus files are implemented with C-ISAM or D-ISAM, and record locking for them is enabled permanently, regardless of the LOKSER setting.

A-Shell’s emulation of LOKSER requires the existence of the underlying operating system file locking mechanism, which may have to be configured or enabled. For example, under DOS, SHARE must be initialized.


MALLOCLIMIT

MALLOCLIMIT=<size in bytes>

Examples: MALLOCLIMIT=32M

MALLOCLIMIT=1500K

The MALLOCLIMIT statement is useful for changing the default dynamic memory allocation limit of 8MB. This mainly affects sorting, which, if the SBR=MALLOCSORT option is specified (which see), can allocate (and take advantage) of large amounts of memory. A situation where you might want to increase the limit would be under Windows (where you probably have huge amounts of physical memory per workstation) if you were sorting files larger than 8MB. For example, if you were often sorting files of up to 32MB in size, setting the MALLOCLIMIT to 32M would make sure sorts run many times faster. A situation where you might want to decrease the default MALLOCLIMIT would be on a large, older, multi-user UNIX system where memory might be a bit tight. Although any memory allocated for sorting would be released back to the system pool as soon as the sort was complete, UNIX systems often will delay making the memory available to another process until the situation becomes desperate. (This is based on the historical case where UNIX processes tended to be short-lived, and thus efficiencies could be gained by delaying all memory cleanup until the process exited.)

The MALLOCLIMIT limit will also affect the size of the largest file that can be brought entirely into memory by the VUE editor.

Note that the limit is stored as a 32 bit unsigned variable in units of bytes, so it will wrap back to zero at 4096M. Thus the maximum value is 4095M.


MAPIDA

MAPIDA='ON' | 'OFF'

Under AMOS, ISAM Plus files are given the same extensions as their ISAM 1.0 counterparts, namely .IDA for the data files and .IDX for the index files. Under A-Shell, however, C-ISAM or D-ISAM are used to implement ISAM Plus. This gives the data files extension .DAT; the index files have the same extension.

Many AlphaBASIC programs are likely to use the lookup and kill statements on AlphaBASIC ISAM Plus data files. If MAPIDA is specified as true, then an extension of .IDA will be mapped onto an extension of .DAT if no file with extension .IDA exists.

Care must be taken specifying MAPIDA if ISAM 1.0 applications are to run concurrently with ISAM Plus. It is possible that some minor programming changes will be required in terms of LOOKUP and KILL.


MAXINST

MAXINST=##

Example: MAXINST=1

(Windows only) MAXINST is an optional parameter, which allows you to limit the number of A-Shell windows or sessions that can be run simultaneously on one workstation. If not specified, then there is no particular limit. The main reason for setting a limit (especially a limit of 1) would be to eliminate the confusion that’s arises when inexperienced users don’t realize they have a session already going (perhaps because it is minimized) and so they open another, perhaps repeatedly. This, by itself, is not a problem for A-Shell, but it may be a problem for the application, if, for example, the user has a record locked in one of the sessions and then leaves it there indefinitely because they forgot about the session.


MAXJOBS

MAXJOBS=## ; set job table size to ##

MAXJOBS=*## ; set size to ## times licensed nodes

MAXJOBS specifies the maximum size of the job table (JOBTBL.SYS) and is analogous to the JOBS statement in the AMOS system INI file. JOBTBL.SYS gets automatically allocated to this size whenever an instance of A-Shell is launched and there is no pre-existing JOBTBL.SYS. (Like QFLOCK.SYS, it gets removed automatically as well when there are no active A-Shell jobs, and can be removed manually if for some reason the automatic removal fails and you want to re-initialize it.) If you fill up the job table, the next attempt to launch an instance of A-Shell will get a job table full error. However, you can fix that by simply adjusting the MAXJOBS parameter and launching A-Shell again, at which point it will expand the table. (It is not necessary to get all users out to perform this expansion.) The second form of the command is preferable since it results in the file automatically expanding as you increase the number of licensed nodes. The only penalty for making the job table excessively large is the few extra microseconds it takes to scan the table when looking for active jobs (so when in doubt, make it larger.) If you don’t specify a MAXJOBS parameter, a complicated and classified formula will be applied to arrive at a reasonable size.


MAXLOCKS

MAXLOCKS=##

Example: MAXLOCKS=500

MAXLOCKS (added in build 837) specifies the maximum number of locks (per job) that A-Shell will keep track of for enforcing the LOKSER rules on ISAMPLUS UPDATE'RECORD and DELETE'RECORD operations. According to the rules under AMOS, UPDATE'RECORD and DELETE'RECORD must only be used on records that were previously locked, and it uses the LOKSER lock queue to enforce this. A-Shell implements LOKSER via the natural locking facility of the native operating system, which does not permit it to easily scan the lock list. Thus it uses its own internal list to keep track of which records have been locked.

The default for MAXLOCKS is 100, which should be more than enough in most cases. The only likely reasons why you might want to override this would be if you wanted to disable the rule (i.e. allow unlocked records to be updated or deleted, even when LOKSER=ON), in which case you would specify MAXLOCKS=0, or if your application allowed a user to lock more than 100 records at a time, in which case specify an appropriately large number. The lock list requires 8 bytes per lock, and is allocated separately from the memory partition and thus does not subtract from any other specified allocation size.

History

2003 September, A-Shell 4.7.837: This parameter added to A-Shell


MEMORY

MEMORY=<workmem size>{,sbxmem size{,cachelimit}}

Examples: MEMORY=700K

MEMORY=700K,200K

MEMORY=2M,400K,500K

MEMORY configures certain memory allocation sizes used by each A-Shell user.

The first number specifies the size of the BASIC work area. If no MEMORY statement is specified, the default work area size is 512K. This work area is used for a variety of purposes, including variable storage, the CALL/RETURN stack, allocation of dynamic arrays, string stack, and if sufficient in size, for sorting files, and compiling, and editing programs.

The AlphaBASIC mem() function displays the amount of free memory available in the main work area. Note, however, that as of A-Shell 4.7, the program itself (and any modules loaded by the LOAD command) is stored in dynamically allocated memory outside of the BASIC work area.

The second parameter specifies the amount of memory to be provided for any SBX subroutine call. If not specified, the default is 384K. In either case, if the main work area has sufficient free space at the time of the XCALL, then that will be used instead. (So if you call a lot of SBX routines, it might be more efficient to make your main work area large enough to accommodate the needs of your largest SBX.)

The last parameter specifies the maximum amount of memory to be set aside for caching of SBX subroutines and other modules that are automatically loaded on demand. The default is 200K. Such modules are kept in memory for a period of about 10 minutes after their last access, or until the specified limit is exceeded. At that point, modules are discarded on a LRU (least recently used) basis.

Notes

A number of A-Shell operations that require additional memory, such as BASORT, COMPIL, and VUE, may take the liberty of allocating it outside of the BASIC work area. See the MALLOCLIMIT statement for details on limiting those allocations.

The minimum practical amount of memory to execute many of the LIT commands is now about 350K.

You can also specify the memory size on the A-Shell command line.

History

2016 July, A-Shell 6.3.1518: Memory enhancement: Move the string expression stack out of the main partition into a separate module which now auto-expands as needed. This should eliminate the most common and yet most unpredictable cause of out-of-memory (or stack-overflow) errors, which are related to operations on strings whose size is not obvious or easily predictable.

The main partition (specified by the first and/or second values in the MEMORY statement) is now used mainly for mapped variable storage, call stack, and command files. The actual RUN files are loaded separately. SYSTAT/M shows the minimum available memory in the partition since the beginning of the session, allowing you to perhaps gauge how much larger-than-necessary your partition allocation is.


MMAPLIST

(UNIX only) MMAPLIST=<fspec> to allow you to specify a list of files that should automatically be memory mapped whenever they are opened. <fspec> should be a fully qualified filespec (although it may contain environment variables using the %ENVVAR% syntax). The specified file should contain a list of AMOS-style or native filespecs, one per line, for the files you want to automatically memory map. Blank lines are ignored, and anything after a # is treated as a comment. Ersatz devices are allowed. For example:

#List of files to be memory mapped

c:\vm\miame\dsk0\100005\myfile.dat # native allowed

MYAPP:MYDATA.DAT # ersatz allowed

DSK0:MYIDX.DAT[100,5] # standard AMOS allowed

The above list specifies three files to be memory mapped whenever they are opened. Note that AMOS specifications are recommended over native ones since they are not sensitive to changes in the device definitions. In the example above, the device where MYAPP: is could be redefined without having to change the MYAPP: reference in this file. But if c:\vm\miame was relocated to d:\vm\miame, you would have to remember to also edit this file to fix the native filespec.

Memory mapping gives you much better file i/o throughput, at the cost of more memory usage. It works best on files that have a lot of access relative to their size (XCALL SERCH index files are a particularly good example.) There are other ways to memory map files (using ASFLAG.SBR or by loading the files directly into memory and using OPTIONS=AUTO_MEMOPEN in the miame.ini file. This method has the advantage of being entirely independent of your application, allowing you to tune your system or just experiment with memory mapping, without making any changes to the application itself.


OPTIONS

Updated December 2013 (Added STR0)

OPTIONS=option {,option} {,option}...

The OPTIONS command is used to set various options that don’t fall neatly into another category. You can specify several options on a single line separated by commas, or you can specify them using multiple OPTIONS statements.

Options | Description
ABSLOOKUP | Causes LOOKUP to return a positive value.
AMOS_RUNSBR | Causes XCALL AMOS to execute commands as true subroutines.
AS400 | Special AS400 TELNET option.
AUTO_MEMOPEN | Causes OPEN to see if file is already in memory.
AUTOTPRINT | Causes PRINT statements to act like TPRINT (i.e., create static text controls).
BRKALC | Pre-fill random files with ]]]]]]].
CRLF | Terminate sequential files with CRLF.
CRNL | Same as CRLF.
AUTODLGSTATE | Make the MBF2_DLGSTATE option be the default for all dialogs. If you set it as the default, the only way to turn it off for individual dialogs would be to use MX_SETOPTIONS (GOP2_AUTODLGSTATE ) to clear the flag before creating the dialog.
EFFUSR | Returns "effective user name."
EFS | Various options related to "EFS," A-Shell's encrypted file system
EXITWAIT | Causes A-Shell to wait for a keyboard response before closing the window down due to the –e switch, thus giving you a chance to read any final screen messages before the window is destroyed.
EXTFIO | Allows access to contiguous files that are NOT a multiple of 512 bytes.
FIELDEMU | Emulate field terminal attributes.
FPROUND | Apply rounding factor of .000005 to INT and FIX.
GUI_SPC_IND | Tokenizes horizontal fixed-pitch spacing for use in variable-spacing GUI screens
HEXDEC | Special hexadecade date processing.
ISAM_IDXLOK | Causes the entire ISAM index file to be locked whenever it would otherwise only be necessary to lock the "rock" (i.e. during index update operations.) For reasons that no one understands, this actually seems to give better results in some Windows network environments.
LATIN1 | Remap OEM character set to Latin1.
LONGDIR | Causes DIR.LIT to use the 10.3 format by default
NOAUTOX | Disables auto expansion of ISAM & INMEMO files (same as NOISAM_AUTOX).
NOAUTOXLT | (Windows only) Disables the automatic translation of the PageUp and PageDn keys under A-Shell/Windows to Ctrl+R and Ctrl+T. This way you could translate the keys to something else. (See FIXTRN.LIT.)
NOFLDATTR | Discards field attributes.
NOISAM_AUTOX | Disables auto expansion of ISAM and INMEMO files; same as NOAUTOX.
NOJOBMAP | (UNIX only) Prevents JOBTBL.SYS from being memory mapped. Normally JOBTBL.SYS will be memory mapped or not depending on whether QFLOCK.SYS (i.e. whether the QUEUE= parameter specifies "DISK" or "MEM"). The option is mainly of interest for debugging or other exotic situations.
NOSPACEATTR | Eliminates the automatic space associated with the on/off field attributes.
NOWHEEL | Disables the otherwise automatic conversion of the mouse wheel events into Up/DownArrow key presses.
NOXABORT | Prevents user from closing window containing an active program.
NTTS | Identifies A-Shell instances like NT Terminal Server sessions.
NUMPAD_COMMA | Converts the "." key on the number pad to a comma for the convenience of locales which use comma as the decimal point.
RAWTABS | (UNIX variants only) Causes A-Shell to output raw tab characters rather than converting them to spaces. It would only be useful if your terminal emulator had some kind of special tab handling feature.
RC_DIMX | Tells the compiler to allow DIMX statement in /RC mode.
SBX_RUNDIR | Alters the search path for SBX modules.
SEQLOK | Enables locking on sequential files for UNIX.
STR0 | Causes numeric conversions to string, whether implicit or explicit, via str(x), to retain the leading zero for fractional values between -1 and 1. Normally the leading zero is stripped in all cases. For example, if x=0.5 and y=-0.3, str(x) and str(y) would normally return ".5" and "-.3" respectively, whereas with OPTIONS=STR0 set, the output would be "0.5" and "-0.3".
STRICT | Causes A-Shell to emulate various AMOS functions.
TRKTOPSTS | Causes PolyShell to treat the top status line as part of the screen.
XABORT | Generates error 255 when user tries to close window if program running.

History

2013 December, A-Shell 1369: Add STR0.


ABSLOOKUP

This option causes the BASIC LOOKUP statement (and corresponding BASIC Plus function) to always return a positive value. Otherwise, in order to more closely mimic AMOS, it will return a negative value if the file is an exact multiple of 512 bytes (since this makes it most likely that the file was originally random or contiguous, and thus you would have returned a negative LOOKUP value under AMOS.) Note that while this is a nice trick, it is not infallible, since the chances are 1 out of 512 that a sequential file will also be an exact multiple of 512 bytes. We strongly recommend that you review the use of LOOKUP in your programs and convert your logic to use ABS() to convert negative values to positive, rather than simply negating the value.


AMOS_RUNSBR

This switch causes XCALL AMOS to execute most commands (anything except CMD and DO files) as true subroutines within the current process, rather than in another process, as would otherwise be the normal behavior for A-Shell. For example, XCALL AMOS,"RUN XYZ" would run the XYZ program within the current process, using the current job environment. (This is how most versions of AMOS.SBR work under the AMOS operating system.) CMD and DO files cannot (currently) be executed within the current process, so they will run in a separate process regardless of the AMOS_RUNSBR switch.

Aside from making the A-Shell version of AMOS.SBR act more like most AMOS versions of AMOS.SBR, the other advantage of the AMOS_RUNSBR switch is that it is much more efficient. We recommend that you use this switch, and would have made it the default behavior, except for historical compatibility. There may be situations where the use of a separate process is actually better, particularly when you don’t want side effects from the subroutine process to linger, either on the screen or in the job’s current environment. For example, any screen output generated by the subroutine will remain on the screen after return to the caller if the subroutine executes within the current job/process. Otherwise, the screen output of the subroutine will appear in a different window, or in a different virtual screen, which will be discarded when it returns. Similarly, any changes to the job’s environment, such as the current ppn or other status settings will be discarded if the subroutine executes in a separate process, but will be retained if the subroutine executes within the current process. For example, consider:

xcall AMOS,"LOG DSK1:100,2"

xcall AMOS,"SET HEX"

The commands above make no sense if OPTIONS=AMOS_RUNSBR is not specified, since the effect of the command (changing the ppn or a job status setting) would otherwise be lost as soon as the command completed, since it would be taking place in a separate job and process from the caller.

When XCALL AMOS runs a command within the current job, it guarantees the child process will have a certain amount of memory, even if it has to be specifically allocated on the fly. The amount defaults to 360K, but can be specified with the second argument to the MEMORY parameter in the miame.ini.


AS400

(UNIX only) This is a rather weird option that was implemented to overcome some kind of shortcoming in the AS400 implementation of TELNET, and would only apply (if then) in a situation where AS400 users were connecting via TELNET to A-Shell running on a UNIX machine. The problem was that when the user typed too fast, bursts of Backspace and other control characters would mysteriously be dumped into the input buffer. With this option turned on, A-Shell filters those characters out.


AUTO_MEMOPEN

Updated June 2008

This option causes every BASIC random file OPEN to first check to see if the file being opened is already in memory. If so, it accesses the memory copy as if the filespec had specified MEM: directly.

The idea of this option is that it permits you to experiment with, or take advantage of the MEM: device (described above) without actually modifying your programs to specify MEM: in the file open statements.

For example, consider the following open statement:

OPEN #CH, "DSK2:MYFILE.DAT[123,222]",RANDOM,RSIZE,RFILE

If OPTIONS=AUTO_MEMOPEN is set, then the OPEN will first check to see if MYFILE.DAT is in user memory. If not, then it works normally. But if it is, then it uses the memory copy. So to make a particular report program run faster, you could just manually LOAD the file (e.g. .LOG DSK2:MYFILE.DAT[123,222]) before running the program.

It must be noted that this is only practical for files that are not updated by a program. (Any updates would be written to memory, not disk.) Caution should be exercised to make sure you don't inadvertently leave the file in memory and then run a program that performs updates on it (thinking the updates were being written to disk.)

History

2008 June, A-Shell 5.1.1116: AUTO_MEMOPEN also applies to sequential input files (OPEN #CH, FILE$, INPUT) and LOOKUP. See DEVICE for details on defining the MEM: device.


AUTOTPRINT

This option causes all PRINT statements in RUN programs to be treated as TPRINT. In other words, they will generate static text, proportional font controls. This can be useful for quickly establishing how well your application would work with all proportional fonts. (It can also be turned on and off with SET.LIT, i.e. SET {NO}AUTOTPRINT.)


BRKALC

Updated October 2009

This option causes A-Shell to pre-fill random files with a repeating pattern of close square brackets "]]]]]]]]]]]]]..." when they are allocated.

History

2009 October, A-Shell 5.1.1163: BRKALC outputs all and only brackets to the file. Previously, it output "MIAME" after every 27 brackets. This was useful in some cases for visually confirming that the file was allocated by A-Shell, but undermined one of the purposes of filling a new file with brackets (to make unwritten records sort to the end).

The old documentation said: "This option causes A-Shell to pre-fill random files with a repeating pattern of close square brackets "]]]]]]]]]]]]]]]]]]]]]]]]]]]MIAME" when then are allocated. In the early days of A-Shell this was the default, but it is not necessary for AMOS compatibility and slows down (slightly) the process of allocating a new file, so it is now available only by setting this option."


CRLF

(UNIX only) This option forces A-Shell/UNIX to terminate sequential file print lines with CRLF (e.g. 0x0D 0x0A) instead of the normal NL or LF (0x0A) used under UNIX. There are two good reasons why you might want to use this option. One is in a situation where you are creating files under UNIX that you want to share with some other operating systems that require the CRLF line terminators (like Windows, DOS, or AMOS.) Since the INPUT LINE statement is implemented under A-Shell in such a way as to throw away superfluous CR line terminators (if immediately followed by a LF), the addition of the extra CR on the end of print lines will not adversely impact A-Shell. The second reason is that you are having trouble getting your UNIX printers to automatically supply the carriage return when goes with each new line. Although this can generally be handled by a filter, having A-Shell simply add the necessary CR for you is an acceptable approach in some cases.


RC_DIMX

This switch tells the compiler to allow DIMX statement in /RC mode. (DIMX is not supported by AMOS, so this doesn't make sense, but it may be useful in cases where you know you won't try to execute the DIMX statement but just want to have a single copy of the RUN program that runs on AMOS and A-Shell.)


EFFUSR

This option (short for "Effective User") also applies only under UNIX implementations, in which case it forces A-Shell to return the "effective user name" instead of the "login user name" in any function that requires this information (such as SYSTAT.LIT, JOBPAR.SBR, etc.).


EFS

Reviewed August 2016

Following are the various EFS_xxx options that may be used in conjunction with A-Shell's encrypted file system.

Options | Description
EFS_OUT_AMOS | This causes any output file (sequential) which is created using an AMOS-style name to be automatically encrypted. (e.g. OPEN #1, "REPORT.PRT", OUTPUT)
EFS_OUT_HOST | This causes any output file (sequential) which is created using a LINUX-style name to be automatically encrypted. (e.g. OPEN #1, "/tmp/report.prt", OUTPUT)
EFS_ALLOCATE | This causes the Basic ALLOCATE function (to create a contiguous file) to automatically encrypt it.
EFS_ALCINDEX | This causes the ISAM-A ALLOCATE'INDEXED command (to create a new ISAM-A file) to automatically encrypt it.


EXTFIO

This option (short for "Extended File I/O") relaxes the normal A-Shell regulation that any file opened for RANDOM (contiguous) access must be an exact multiple of 512 bytes in length. This might be handy if you want to use AlphaBASIC to read/write some kind of unstructured binary data. It also removes certain AMOS peculiarities which seem of dubious value, such as the automatic stripping of isolated carriage returns from strings in INPUT and INPUT LINE statements.


FIELDEMU

(Windows only) This option causes A-Shell/Windows to emulate 'field' attributes (i.e. like the AM62A) rather than the 'mode' attributes which are otherwise normal under Windows (as well as the AM65 and VTxxx terminals.) In the normal 'mode' operation, all video attributes (such as reverse and underline) work just like dim and bright, except that the on and off commands cause a space to be output (unlike dim and bright, which do not.) That is, the attribute for a character is determined by the chronological sequence of attribute commands which preceded the display of the character.

When the FIELDEMU option is active, the attribute for a character is determined by the position of that character on the screen relative to attribute on/off commands which may be embedded in the display. The chronological sequence of the commands has nothing to do with it. For example, consider the following statements:

PRINT TAB(-1,0);

PRINT TAB(10,15);"What am I?";

PRINT TAB(10,9);TAB(-1,32);TAB(10,25);TAB(-1,33);

In field operation, the "What am I" string will appear in reverse video, even though the reverse ON command (-1,32) was sent chronologically later than the "What am I?" string. However, in mode operation, no reverse video will display at all, because no characters were actually displayed after the reverse video on command and before the OFF (-1,33) command.

To allow the above program to work correctly in both field and mode environments, it should be changed as follows:

? TAB(-1,0);

? TAB(10,25);TAB(-1,33);TAB(10,9);TAB(-1,32);

? TAB(10,15);"What am I?";TAB(-1,33);

The first TAB(-1,33) is superfluous in mode operation, and only serves in field operation to limit the screen flash that would otherwise appear when the TAB(-1,32) command is given. Since the TAB(-1,32) is sent before the "What am I?" string, as well as positioned to the left of the string, the string will appear in reverse in both field and mode environments.

Finally, the last TAB(-1,33); is superfluous in field operation (given that we already stored a reverse-off attribute in that position in the previous statement) but it is needed in the mode environment to prevent subsequently output characters from appearing in reverse.

The sole purpose for implementing the OPTIONS=FIELDEMU feature is to allow programs that were written strictly for field devices (like AM62A terminals) to work properly under A-Shell/Windows. Previously, the only option available to prevent such programs from displaying their attributes all mixed up was to specify OPTIONS=NOFLDATTR, which simply disabled the field attributes.

If your programs are able to run in both field and mode environments, then they will probably run faster and cleaner under A-Shell/Windows in the normal 'mode', since the performance advantage of certain field operations on a serial terminal (like moving a menu bar up and down) is lost in Windows where there is no noticeable screen I/O bottleneck.

Two other notes about the implementation of field attributes: 1) unlike on the AM62A terminal, A-Shell will automatically terminate the field spillover effect at the end of the line, rather than letting the attribute spillover to the end of the screen. Technically this is incorrect, but it is so rare for software to be deliberately written to take advantage of that spillover, and so common for the spillover to produce an unwanted screen flash, that we decided this was an improvement. 2) A-Shell does not currently support the blinking attribute.

Under A-Shell/UNIX, the choice of Mode vs. Field is determined entirely by the choice of terminal driver, which in turn is determined by the TERM environment variable setting.


FPROUND

When set, this option causes A-Shell to apply a rounding factor of .000005 (5 millionths) to the INT() and FIX() functions, and to the floating point comparison operators =, <>, <=, and >=. This fudge factor can be useful in programs that use floating point variables for dollars and cents computations without taking into proper account the fact that whenever floating point values are manipulated, they begin to accumulate tiny errors in precision. If the results of such expressions are not carefully rounded to the nearest penny, the errors can add up to the point that they become noticeable. This is particularly true with non-integers, which is why the SCALE option was invented in the original AlphaBASIC.

For more information on this subject, see Rounding of Floating Point Variables.


GUI_SPC_IND

Reviewed February 2008

Turning on OPTIONS=GUI_SPC_IND causes PRINT statements to be "tokenized" so that each token is positioned at the place where it would have been positioned if using fixed pitch. It also converts tokens made of hyphens (---------) or equals signs (=========) to graphic horizontal lines. For more detail, see the examples under the topic OPTIONS=GUI_SPC_IND.


HEXDEC

This rather strange option invokes two features related to "hexadecade" date notation (in which 1-Jan-2000 is coded as "0101A0", 15-Jun-2014 is "0615B4", etc.) which can possibly eliminate a lot of Y2K conversion programming in some legacy applications.

The first feature causes the VAL() function (whether called explicitly or implicitly, by assigning a string to a numeric variable) to accept a single leading hex digit. Thus, VAL("A5") would return 105. This may allow BASIC routines which add and subtract dates to continue to work, even with hexadecade format dates.

The second feature causes PRINT to scan the output for strings which look like hexadecade dates (e.g. ##/##/A#) and convert any such pattern to the 'standard' notation. For example, PRINT "12/15/A2" would display 12/15/02. This feature may eliminate much of the need to manually clean up the output when switching to hexadecade date format.

Note that all of the above would probably only make sense if you were also using INFLD’s hexadecade feature. Refer to the INFLD Parameter Reference for more details.

The HEXDEC PRINT formatting logic also applies to XCALL PRINT.


LATIN1

Updated December 2011

(Windows only) This option applies only when the (now deprecated) Miame Terminal font is being used. When invoked, it causes A-Shell to re-map the OEM character set used by the Miame Terminal font to implement the ISO 8 bit Latin1 international character set. By setting your Windows keyboard format to US International or equivalent, you can use the Windows compose sequences to input accented characters, and A-Shell will properly save them so that they will be displayed properly on any display device supporting the Latin1 character set.

Note that the Miame Terminal font is no longer recommended. For more information on fonts, see the FONT discussion in the System Parameters section.


LONGDIR

This option is the maime.ini equivalent of SET LONGDIR, which causes DIR.LIT to use the 10.3 format by default. Note that you need DIR.LIT 3.0(135)+ and SET.LIT 1.2(145)+ for the LONGDIR option to work correctly.

History

2005 June, A-Shell 4.9.934: Function added to A-Shell


NOAUTOX

Disables auto expansion of ISAM and INMEMO files (same as NOISAM_AUTOX).

The auto-expand feature can be turned off for individual files by creating a <file>.NOX file in the same directory where the <file>.IDX and <file>.IDA files reside. If they are in different directories, create a .NOX file in each location. Note:

• If you have multiple IDX files, you'll need a .NOX for each (unless you only want to disable the auto-expansion for a specific IDX).

• The .NOX file does not have to have any size. You can create it with the MAKE command (to create a 0 byte file), or with VUE or whatever. It is just the presence of the file in the directory that matters.

• All auto-expansion operations, including those disabled due to the NOX file, will be recorded in the ashlog.log file.


NOFLDATTR

(Windows only) This option (short for "No Field Attributes") causes A-Shell to "throw away" screen attributes that are field oriented (such as TCRT functions 32,33,34,35, etc.). The motivation for this would be to avoid screen attribute chaos when running an application on a "mode" display device (such as a VGA monitor,) when the application was only written to support "field" terminals. See FIELDEMU above for a more sophisticated way of dealing with this problem. Note that OPTIONS=NOFLDATTR is equivalent to FLDATTR = OFF.


NOSPACEATTR

The switch OPTIONS=NOSPACEATTR eliminates the automatic space associated with the on/off field attributes (TCRT commands 21,22,30-35,100-105). Currently this only applies to the AM75{G} UNIX emulation, and was implemented to provide compatibility with applications developed with a very old AMOS terminal driver standard in which mode emulation drivers did not automatically add the space which otherwise was added by field terminals directly. Note that if OPTIONS=NOSPACEATTR on the server side, the option will be automatically forwarded to ATE.


NOWHEEL

This setting OPTIONS=NOWHEEL disables the otherwise automatic conversion of the mouse wheel events into Up/DownArrow key presses when the focus is not on a control that captures the mouse wheel directly (such as XTREE, multi-line INFLD, etc.).

The default behavior allows you to use the mouse wheel to scroll within certain environments that are otherwise text-only (like VUE). But in some cases the default behavior is undesirable, for example:

• On laptops with sensitive mouse pads, you may get spurious cursor motion just from brushing your palm against it (very annoying in VUE).

• In screen contexts where there may be a mixture of controls that scroll (like XTREE) and those that don't (like a single line INFLD), users may attempt to use the mouse wheel with the intent to scroll an object like XTREE, when in fact the focus is on a control like INFLD where the conversion of the mouse wheel to an Up/DownArrow may trigger unwanted exitcodes (3 & 5), leading to further confusion.

Note that VUE supports its own version of this switch (in the INI.VUE and command mode) MOUSEPOS<boolean>, which see for information on the relationship of this setting and that one.

Also, the mouse wheel is now disabled in INFLD self-combo fields (which exit on the first down arrow key); otherwise it is too easy to end up with several additional down arrow key events which would then be interpreted according to logic impossible for the user to predict. Self-combos within XTREE continue to operate as before.


NOXABORT

(Windows only) This option prevents a user from closing the window while a program is running by clicking on the "X" button or hitting ALT-F4. With or without this option, such an action will bring up a dialog box warning the user about the reasons not to abort that way and suggesting the proper way to exit. But without this option, the user can choose to ignore the warning and click on the "OK" button to proceed with the abort anyway. With this option, the "OK" button is deactivated. See XABORT option.


NTTS

(Windows only) This option forces A-Shell to identify instances in the same way that it does if it detects the presence of NT Terminal Server (or the subsequently renamed Windows Terminal Server). This is useful both for testing and possibly for variations of NT Terminal Server, such as Citrix, which may not be automatically detected properly. A-Shell needs to use a different window numbering scheme when running under Terminal Server , since with the normal scheme, it would end up generating duplicate IDs.


SBX_RUNDIR

This option alters the search path for SBX modules. Normally, the search is: current [p,pn], [p,0], BAS: When OPTIONS=SBX_RUNDIR set, search is: current [p,pn], .RUN location, BAS:.

History

2004 September, A-Shell 4.9.900: Function added to A-Shell


SEQLOK

(UNIX) This option enables locking on sequential files (when LOKSER is enabled). Previously, sequential files under UNIX were not subject to locking rules (other than VUE, which implements its own locking scheme). Under Windows, sequential file locking has been enabled since 4.7.

History

2005 February, A-Shell 918: Function added to A-Shell


STRICT

This option causes A-Shell to emulate some of the more restrictive characteristics of AMOS that are not always wanted. (The presumed motivation would be to prevent you from getting too comfortable with bypassing such limitations, making it difficult to port back to AMOS.) As of Build 791, the only example of this is the "protection violation" error you get when trying to write to a file outside your project. (Since neither Windows nor UNIX has any such arbitrary restriction, A-Shell normally ignores it.) But if you want to a "protection violation" whenever you attempt to write outside your project, then set OPTIONS=STRICT. (Over time, additional "features" may be added to under this umbrella.)


TRKTOPSTS

This causes PolyShell to treat the top status line as part of the screen, to be saved and restored when switching sessions. Note that this behavior is automatic for the bottom status line, but the top status line by default is intended for messages that are associated with the user or terminal, rather than the session.


XABORT

(Windows only) Without this option, an attempt to close the A-Shell window by clicking on the "X" button or hitting ALT-F4 while a program is running, will display a dialog box warning you of the reasons why this might not be a good idea. If you ignore the warning and choose to abort anyway, the program will be aborted without any good chance of recovery. (See NOXABORT to prevent that possibility.) OPTIONS=XABORT presents a different approach by generating a BASIC error #255 instead of displaying warnings. Then your BASIC program can decide the best way to handle the situation, possibly by ignoring the error, possibly by closing the program gracefully and then exiting A-Shell.


POLYKEY

Updated August 2015

POLYKEY=key (or ^key)

Examples: POLYKEY=^W (Control W)

POLYKEY=| (vertical bar)

This parameter defines the hot key that can be used to switch between sessions, but there are two completely different cases:

• PolyShell Server Side: If the server session of A-Shell is running PolyShell, the key is transmitted to the server where it triggers a switch between server-side sessions. The key will be "hot", except when you have shelled out via HOST.LIT or HOSTEX.SBX, or when running in GUI mode. Also see SWAPKEY.

• Client Side: If the server session is not running PolyShell and the client is ATE, or in an A-Shell/Windows standalone or P2P environment, then the key is processed on the client side, causing the next A-Shell/Windows or ATE instance in the task list to be activated, put on top, and given the focus. If there are only two such instances, the key will toggle between them, equivalent to Alt+Tab. If there more than two such instances, repeated uses of the key will advance you through the set of sessions in sequence. You may also use Ctrl+Tab as an alias for the same operation.

History

2012 August, A-Shell 1255: Support for the Client-Side switching added.


PRINTER

PRINTER=<dflt ptr name>{,screen pict ptr{,NODLG}}

Examples: PRINTER=LASER

PRINTER=LASER,MYJET

PRINTER=LASER,MYJET,NODLG

PRINTER is used to define the A-Shell default printer, i.e. the printer to be used if no printer name is specified in a SPOOL.SBR or PRINT.LIT command. This name specified is the name that the printer is to be known by within your applications (i.e. the "AMOS Spooler Name".) To get further configuration information about the specified printer, including how it is known to the operating system, printer init files are used. See Printer Configuration or further details.

Optionally, you may define a separate printer name that will be used for screen pictures only. If defined, the screen picture command (Ctrl+P) will skip past the printer selection (saving precious keystrokes when taking screen pictures.) You may also specify a third parameter, the keyword "NODLG" (not case sensitive) which complete eliminates the screen picture dialog options (just sending the screen picture to the specified printer with no option to add a comment, view it, opt not to delete the picture file, etc.) See Screen Pictures for more details.


QUEUE

QUEUE=<Blocks>,MEM: | DISK:<Filespec>

UNIX Example: QUEUE=100,MEM:C:\VM\MIAME\QFLOCK.SYS

Windows (or UNIX) Example: QUEUE=100,DISK:C:\VM\MIAME\QFLOCK.SYS

A-Shell, like AMOS, uses a pool of "queue blocks" to keep track of locks and other shared system resources. While AMOS uses the queue for a variety of operating system functions, including LOKSER, A-Shell uses it primarily just for maintaining locks placed by XLOCK, FLOCK, and similar custom locking subroutines. (LOKSER-style locks are handled directly by the native operating system.) Thus, the required number of queue blocks is simply the maximum number of concurrent XLOCK and FLOCK (or similar) locks. Specifying an unnecessarily large queue file will have a minor impact on performance.

The queue may reside either in memory (MEM:) or on disk (DISK:), though as of A-Shell 4.8, memory based queues are only supported under the UNIX versions of A-Shell. (A-Shell 4.9 adds the capability for A-Shell/Windows.) Memory queues are quite a bit faster, but this is not significant unless your application makes a large number of XLOCK or FLOCK calls.

Whether QFLOCK is disk-based or memory-based, a complete pathname (including filename) must be given. The name is usually qflock.sys, and it must reside in a directory accessible by all users, typically the same directory where the shared miame.ini file is located. Memory based queues are implemented under A-Shell/UNIX as memory-mapped files, so even though all accesses are performed in memory, the file will appear in the directory. (In addition, a small control file named qflock.lck will be created in the same directory.)

Notes

The QUTL.LIT utility may be used to display the contents of the queue, as well as to manually remove locks placed by another user.

The queue file is created automatically by the first user to launch A-Shell, and deleted automatically by the last user to exit (provided there are no locks currently in use). On a normal exit, A-Shell will purge the queue of all locks owned by the current user, but if a job or user should crash out of A-Shell for whatever reason, locks may be left in the queue. (Use QUTL.LIT to manually remove such locks.) Should the queue file become corrupted, it can always be removed manually (provided it is not currently in use) since the next user will recreate it.

Prior to Build 4.6, the QFLOCK.SYS file also held two records for each job which functioned like the job table records under AMOS. As of Build 4.6, this information is now kept in a separate file called jobtbl.sys.

The jobtbl.sys file is also created and deleted automatically alongside qflock.sys. (See MAXJOBS.) If, for some reason you have to manually delete one of them, it is best to delete them both.

Warning: Although these files will be recreated automatically, they should not be removed while there are active users! Removing a disk based (DISK:) qflock.sys will cause all locks for any current users to disappear. Removing a disk based jobtbl.sys file will cause existing users to abort with a "jobtbl/queue zapped" error the next time they execute a command or perform any function that updates the job accounting information. Removing memory based (MEM:) versions of these files (by deleting them from the disk directory) will not appear to affect currently running users, since they will continue to use the copy in memory. However, the next user to launch A-Shell will create new copies of these files in memory, leading to a situation where there are two (or even more) "pools" of users that don't know about each other. Locks placed in one "pool" will not be visible in the other, which could lead to file corruption due to locking failure. So if there are any users currently running A-Shell (even if they appear to be "dead") it is preferable to manually remove the users (either with the QUTL.LIT "ZAP" function or via the operating system) before deleting the jobtbl and qflock files.

The maximum number of queue blocks is 65,535.


QUITKEY

QUITKEY=key (or ^key)

Examples: QUITKEY=^\ (Control backslash)

QUITKEY=~ (tilde)

QUITKEY= (no quit key) (default)

This optional parameter applies to A-Shell/UNIX only. It defines the key which UNIX uses to abort a running process. Normally, the UNIX "Quit" key is Ctrl+Backslash. Hitting this key while a process is running causes the SIGQUIT signal to be sent to the process. Since this signal is un-trappable, it invariably causes the process to abort with a core dump. The only defense an application has against this key is that it can be redefined or even disabled (prior to it being used.) Because of the obvious danger posed by the ability to abort A-Shell and cause a core dump just by hitting a key, the default is for the key to be disabled while A-Shell is running.

RUNDIR deleted 11/2011

RUNDIR=<native directory specification>

Example: RUNDIR=C:\Program Files\MicroSabio\AshLite\Run

RUNDIR is only used in AshLite (i.e. ASHLITE.INI), where it specifies the directory where all of the programs and files will be kept. (AshLite ignores device and PPN specifications and looks for all files in the RUNDIR directory.)


SSD

SSD=nnn-nnn-nnn-nnn-nnn-nnn-nnn-nnn

This parameter is more for programmers of A-Shell than end users. A-Shell contains a rudimentary but effective SSD emulator, which enables the eight numbers returned by the SSDIAG program to be exactly specified. It is these numbers, padded with leading zeros to three digits, which follow SSD on the command line. It is not a true SSD simulator since it is not based on an actual SSD number, but it does enable the same PIC code to be used for any software protected by a real SSD by simply specifying the same sequence of numbers as returned by SSDIAG.RUN on that machine.

The SSD emulator does not emulate all aspects of the SSD, so it is important that the SSD is written to and read from in the same manner as by the SSDIAG program. The read/write sequence (in AlphaBASIC) required is:

io(514) = 0

for SSD'LOOP = 1 to 8

io(514)=(2^SSD'LOOP)+1

print io(512)

next SSD'LOOP

Failure to use this read/write sequence within an application will still generate a unique PIC on each A-Shell machine (assuming they are given differing eight-number sequences). In this case, however, it is not guaranteed that if the eight numbers produced by SSDIAG from a real SSD are used, that the PIC used on the Alpha Micro will in fact work on the machine running A-Shell.


SBR

SBR=optioncode {,optioncode} {,optioncode}

The SBR parameter is used to specify various configurable subroutine options to account for local variations in some, otherwise standard, subroutines. These variations are typically the result of someone modifying a standard routine to suit their purposes. An example of this COMMON.SBR, which many people have modified to change the number and size of the saved modules. Rather than have several implementations of each subroutine which can differ, various SBR options can be specified to tune the operation of such subroutines.

Option | Description
AMOSJOB1 | Causes JOBNAM to return the name of the parent job.
AMOS_RUNSBR | Deprecated. Use OPTIONS=, not SBR=.
AUTO_DLG_MAX | Maximizes dialogs, helpful for tablets and net-books.
AUTO_TABX | Automatically converts all Tab controls to TabX controls.
AXLOCK | Causes A-Shell to duplicate the behavior of XLOCK under AMOS.
BSMID5 | Affects sequential search in SERCH.
BUBBLESORT | Obsolete, but documented by way of explanation.
CCYY | Affects the way INFLD and IDTIM guess at the century.
COMMONNDR | Non-destructive read in COMMON.
EZPRTX | Causes EZTYP to use EZPRTX.
INFLD_V1 | Eliminates the need to specify the V parameter to INFLD.
INFDEF | Specifies type codes to INFLD.
INFLD143 | Affects the operation of J justified types in INFLD.SBR.
INFLDB3 | Causes INFLD to add blank spaces for comma-formatted fields.
INFLDCBRJ | Right-justifies text label.
INFLDEDIT | Provide support for a variation of INVUE.
INFLDLDROP | Special handling for type "L" operation in INFLD.
INFLD_KEEPALIVE | Sends a few bytes every 15 seconds while waiting for input.
INFLDPS | Impacts the operation of types "P" and "S" in INFLD.
LSTLINSTRIP | Strips comments from command line before returning them to LSTLIN.
MALLOCSORT | Affects the memory allocation strategy of BASORT.
MESAGRTN | Changes behavior of MESAG.
MSGNUM | Changes the number of packets available to COMMON.
MSGSIZ | Changes the size of each packet available to COMMON.
MXLOCK | Forces XLOCK to conform exactly to standard documentation.
PCKLST_GUI | Use XTREE (GUI) in place of PCKLST (text)
PRINT_TIME | Allow for the time to be added to the report header.
PRINT_JOBUSN | Allow for the user name to be added to the report header.
PRINTNOFF | Eliminates form feed character in PRINT.
PRTCHK1 | Causes PRTCHK to return 1 if printer is found, 0 if it is not.
SUBMIT2 | Forces a new process to be the grandchild of the current process.
TRIMCTL | Causes TRIM to remove leading and trailing control characters.
TTI_PGRW | Affects how INFLD type codes "$" and "H" are handled.
XPPPNOCT | Affects how XPPN displays PPN value.
XTREE | Enables various operations for all XTREEs.


AMOSJOB1

This causes JOBNAM.SBR to return the name of the parent job rather than the current job, when the current job was launched via AMOS.SBR (and the AMOS_RUNSBR switch is not active.). This mimics one aspect of the way XCALL AMOS worked under AMOS (i.e. that the child process was still the original job.) Note that under A-Shell, the child process is truly a separate job and thus cannot share any memory based information (, unless the AMOS_RUNSBR switch is active, which see above.)


AXLOCK

The AMOS version of XLOCK.SBR has a bug in which an attempt to get a wildcard lock (e.g. X,0) will appear to succeed (i.e. return MODE 0) even when you already have a conflicting lock (X,Y). One could argue whether a lock previously set by the same user should be considered a conflict or not, but it is hard to justify returning a status of success when the wildcard lock was, in fact, not set due to the conflict. Yet, in the rarified world of programming, there are those that consider this a feature rather than a bug. For those, we have the AXLOCK option, which causes A-Shell to copy the AMOS bug. For all others, the default behavior is to return an error status (MODE set to your own job number) to indicate that there was a conflicting lock, set by yourself, and that the wildcard lock request was not set. Note that there is a similar issue relating to how to handle a request to obtain a lock that you already have, for which the MXLOCK switch was created.


AUTO_DLG_MAX

Updated December 2012; see History

This options causes AUI_CONTROL to automatically maximize any newly created dialog which is larger than the screen size (for single monitor systems). The intent is to help existing dialogs conform better to net book and tablet environments whose screens are smaller than the dialogs were originally designed for. Maximizing in this case actually reduces the size of the dialog, and scales all the controls within it accordingly.

If the dialog is small enough to fit, but is partially off the screen, it is shifted so as to be entirely visible.

History

2012 December, A-Shell 6.1.1329: Modified to work on multi-monitor systems. It now operates relative to the monitor over which the center of the dialog (in its original coordinates) appears.

2011 April, A-Shell 5.1.1214: Added to A-Shell.


BSMID5

This option affects the operation of the sequential search (BSMID=5) in SERCH.SBR. If specified, then the sequential search begins at the record following the current record in the file. This is the normal operation in the U.S. If omitted, then the sequential search begins at the current record, which is the normal operation in the UK.


BUBBLESORT

This option no longer has any effect. Historically, it was used to force BASORT to use the bubble sort algorithm, which was slow but didn't rearrange records with equal keys (like the other algorithms used to do). As of A-Shell version 4.7, all of the sort algorithms preserve the order of records with equal keys, eliminating any need for bubble sort.


CCYY

Updated January 2011

CCYY:##

(default ## = 60) This code affects the way INFLD and IDTIM guess at the century in a six digit date format. The two digit number (##) sets the minimum year which will be assumed to be part of the 20th century. Any year below that will be assumed to be part of the 21st century. For example, if you specify SBR=CCYY:25 and then supply a date to INFLD or IDTIM like 09/15/22, it will be treated as 15-Sep-2022. However, if the date you enter is 09/15/25, then it will be treated as 15-Sep-1925. This can be useful as part of a simplified workaround to the Y2K millennium problem in applications where the range of dates being dealt with is significantly less than 100 years. For example, a typical accounting system is only concerned with dates within a range of a few years. However, note that by itself, it doesn’t do anything for you unless you are storing your dates in some kind of format which can support century information. For example, if you are taking the result of IDTIM and storing it in a 4 byte binary format, or if you are using the INFLD TYPE code "j" to return the date in Julian format, then this CCYY trick can be helpful. But if you are merely calling INFLD to get a date in MMDDYY format and are then storing it in your files as MMDDYY, the CCYY trick doesn’t do anything for you except correctly determine whether 02/29/00 is valid or not (02/29/2000 is but 02/29/1900 is not.)


COMMONNDR

This option stands for "COMMON.SBR Non Destructive Read". Normally, a read operation in COMMON.SBR destroys the packet, requiring it to be rewritten before it can be read again. However, some developers apparently got their hands on a version of COMMON.SBR, in days of yore, which did not have this unfortunate characteristic, and thus were eternally grateful for the addition of this sensible option.


EZPRTX

This option causes the EZTYP print file preview utility (aka EZVUE) to use the customizable SBX routine, EZPRTX, in place of its own logic for printing of a selected range of pages. This allows more sophisticated or application-specific printing logic to be used in place of the generic logic within EZTYP. (For example, you may want to use different printer selection logic, or add logic to embed printer control codes into the selected pages to be printed.) The source code to a generic sample version of EZPRTX.SBX is included in EZPRTX.SAM in [7,376]. Use it as the basis for your own customized version. (There are additional notes in the source code about parameters and other technical details.)


INFLD_V1

This code eliminates the need to specify the V parameter to INFLD. Otherwise, if you fail to specify V, INFLD doubles the row. (This is an historical artifact going back to the invention of the 24 row display, which doubled the size of the previous 12 row displays.)


INFDEF

INFDEF:{string}

Under AMOS, INFLD.SBR supports a defaults file INFLD.DEF. This is used to contain default type codes which are always appended to any codes in a call to INFLD.SBR. Under A-Shell, the same is achieved by specifying these type codes after a colon with the INFDEF patch.


INFLD143

This code affects the operation of J justified types in INFLD.SBR. If specified, then a null input to a J-type field, as distinct from an explicit input of zero, will return ENTRY padded with spaces to XMAX, e.g. ‘ ’. This conforms to the operation of INPUT.SBR as supplied with AlphaACCOUNTING in the UK. If INFLD143 is not specified, then a null input would return ENTRY padded with zeros, e.g. 000000. This conforms to the operation of the Assembly language routine as supplied by MicroSabio for AMOS.


INFLDB3

Later versions of INFLD.SBR, and the C version used in A-Shell, output spaces to blank the fringe of comma-formatted numeric input types, dependent on the input size, decimal point specification, and so on. The old AlphaACCOUNTING INPUT.SBR routine (and very early versions of INFLD.SBR) were not so intelligent about this matter. For comma-formatted types (specifically $ type financial fields), they just output 3 blanking spaces regardless of field size. To accommodate older software, the INFLDB3 code has been implemented. If specified, INFLD.SBR will blank 3 spaces for comma formatted fields (‘M’, ‘$’ and ‘H’) to the right or left according to justification. Otherwise the number of spaces to blank will be determined exactly as a function of field size. Note that INFLD "prehistoric compatibility mode," which causes to INFLD to mimic nearly all of INPUT.SBR’s shortcomings and idiosyncrasies, (and which can be invoked with SBR=INFDEF:|p) will also accomplish this effect.


INFLDCBRJ

This parameter, INFLD Checkbox Right Justify, can be used to right justify the text label associated with an INFLD-created checkbox (TYPE |c). Without TYPE R, the text goes on the left and the box on the right; TYPE R reverses that. But in either case, the text itself is normally left justified within its space. SBR=INFLDCBRJ will force it to be right justified in its space.

History

2004 June, A-Shell 893: Parameter added to A-Shell


INFLDEDIT

The INFLDEDIT code may be used in conjunction with ALIAS=EDIT:INFLD to support a variation of INVUE.SBR written by Pat LaFollette that goes by the name EDIT. EDIT is very similar to INVUE, with the main difference being the return parameter.


INFLDLDROP

The INFLDDROP code affects the operation of L type in INFLD.SBR. The default for an L type field is for the right arrow to move across the field until it hits the end, and then it exits, setting the appropriate exit code. With INFLDLDROP set, it exits immediately.


INFLD_KEEPALIVE

(UNIX) This sends a harmless byte sequence every 15 seconds while waiting for input within INFLD (which includes the dot prompt and BASIC INPUT statements). This serves two purposes. First, it will prevent connections from being dropped due to lack of activity while they are actually in a program waiting for input. Second (and perhaps more important), it provides a mechanism for UNIX/Linux servers to detect connections that have been dropped (without having to wait for the standard keep-alive timers to expire, which by default may run to 2 hours). This way, within 15 seconds of the connection being dropped, the server will send a packet, which cannot be delivered. This should trigger a retry timer which will try to resend the packet some number of times before concluding that the connection is dead. This process is generally much quicker than the keep-alive detections process.

Note that under Linux, the retry timers are controlled by two files in the /proc filesystem: /proc/sys/net/ipv4/tcp_retries1 and tcp_retries2. The default values of 3 and 15, respectively, may be large for your liking, possibly taking as long as 15-30 minutes to close the dropped connection. You can set them as low as 1 and 2 for nearly immediate detection, at the possible risk of prematurely judging a temporarily sluggish connection to be dead. Here is some good documentation with more information about the tcp variables in the /proc filesystem.

History

2004 January, A-Shell 4.9.861: Function added to A-Shell


INFLDPS

The INFLDPS code affects the operation of P and S types in INFLD.SBR. The default is for a P type field to be a U.S.-format phone number, and an S type field to be a secure (non-echoed) input. This conforms to the operation of the standard AMOS version of INFLD. If INFLDPS is specified, then the meanings of the two types are reversed. This corresponds to the operation of INPUT.SBR with AlphaACCOUNTING in the UK, which uses type P for non-echoed passwords.


LSTLINSTRIP

The LSTLINSTRIP code causes comments to be stripped from the end of command lines before returning them to XCALL LSTLIN. Note that this occurs inside LSTLIN.SBR so it does not apply to use of the CMDLIN system variable to retrieve the command line.


MALLOCSORT

This code affects the memory allocation strategy of BASORT.SBR. Normally, BASORT uses only the "impure" memory within the user’s pre-allocated memory partition to perform the sort. Depending on how much is available, it decides between a pure quick sort (entirely in memory), a quick sort of a tag file consisting of the keys, followed by a one-pass reordering based on the sorted keys, or in the worst case, the dreaded poly-phase merge in which the file is broken into pieces which are individually sorted and then merged back together. When MALLOCSORT is specified, BASORT will attempt to temporarily allocate as much memory as it needs (within reason) to perform the fastest possible sort. This only makes sense under UNIX and Windows, where it is highly recommended, since it may dramatically speed up sorting in these environments which typically have lots of memory available for temporary use.

See Also

• MALLOCLIMIT


MESAGRTN

The normal operation of MESAG.SBR is such that a message type 1 is displayed followed by CR TO RECOVER, and a message type 2 followed by CR TO CONTINUE. If the MESAGRTN code is specified, then the operation of both these message types becomes identical, and they are displayed followed by Press Return. Also note that the text of this and other subroutine messages can be edited directly in SBRMSG.<lan>.


MSGNUM

MSGNUM :<number>

This changes the number of packets available to COMMON.SBR to the value specified after the colon. The default number of packets is 6.


MSGSIZ

MSGSIZ:<size in bytes>

This changes the size of each packet available to COMMON.SBR to the value specified. It may be used with the MSGNUM patch to tailor the implementation of COMMON.SBR to match that of equivalent AMOS installations. The default packet size is 150 bytes.


MXLOCK

The XLOCK.SBR routine normally returns the job number of the job which is in possession of a lock in the MODE parameter, if an attempt is made to create a conflicting lock. Under AMOS, if an attempt is made to duplicate a lock which your job already owns, then a MODE of zero is returned, indicating success, even though no extra lock information is created. This, although contrary to the standard documentation, is the default operation under A-Shell. If the MXLOCK code is specified, then the operation of XLOCK conforms exactly to the standard documentation. An attempt to create a lock which conflicts only with a lock possessed by your own job, will still return a non-zero MODE, the job number of your own job.


PCKLST_GUI

This switch causes PCKLST.SBR to use the GUI interface of XTREE. It is not quite the same as using ALIAS=XTREE,PCKLST, but very close.


PRINT_JOBUSN, PRINT_TIME

These options allow for the time and/or user name to be added to the report header:

SBR=PRINT_TIME ; Add time (hh:mm am) to date in header

SBR=PRINT_JOBUSN ; Add user name to date in header

If either option is selected, the "Run Date: mm/dd/yy" header string will be shortened to just "mm/dd/yy" with the time and/or user name appended. Note that the user name may be truncated to as few as 6 characters depending on the paper width and whether the time was also displayed. Also, if both are selected, the report title and coname strings will be truncated to 46 characters (down from the previous maximum of 50).


PRINTNOFF

This switch affects the operation of PRINT.SBR and leading form feeds. In the default case, PRINT.SBR would put a leading form feed character at the top of the file. Under AMOS, this would generally not result in an extra blank page, due to a peculiarity of the AMOS spooler. However, under most other platforms, it probably would cause an extra leading blank page. To eliminate those, set SBR=PRINTNOFF.


PRTCHK1

Some versions of PRTCHK.SBR return 1 if a printer is found and 0 if it is not. To get this behavior, add SBR=PRTCHK1 to the miame.ini file.


SUBMIT2

(UNIX only) This switch affects the operation of SUBMIT.SBR (and SUBMIT.LIT), and, as of 984.7, the COMMAND= parameter in printer initialization files. Each of these operations involves the UNIX fork() function to create a child process in order to run a command outside the current process. In the normal case, the new process is a direct child of the current process, which makes the current process responsible for burying the child when it dies. This is often not convenient, and can have either of two undesirable side effects. One is that the current process can get stuck waiting for the child to complete. The other is that if the current process exits before the child exits, the child will become a zombie.

SBR=SUBMIT2 causes A-Shell to use a two-level fork(), which results in the new process being a grandchild of the current process. The first child exits immediately, which makes the grandchild an orphan, to be adopted by the init process (pid 1). The end result is that the current process is relieved of its parental responsibilities, eliminating the two problems mentioned above.

In the case of the COMMAND= option in the printer initialization file, a more straightforward benefit is that XCALL SPOOL returns immediately to the program, regardless of how long the process invoked via the COMMAND= statement takes to complete. (Without SBR=SUBMIT2, SPOOL.SBR would wait for the child process to complete before returning.)


TRIMCTL

This switch causes TRIM.SBR to remove leading and trailing control characters, as well as blanks, from the string passed to it. You can also get the same effect by passing a second, numeric, non-zero valued argument to TRIM (e.g. XCALL TRIM,A$,1).


TTI_PGRW

This rather obscure switch activates certain adjustments to the way in which the TYPE codes $ and H are handled in INFLD.SBR. It also activates Ctrl+G as the help key in INFLD.SBR and SEL1.SBR.


XPPPNOCT

This switch causes XPPN.SBR to adjust the value of the returned P (project) and PN (programmer number) values so that even though they appear in decimal as if they were octal. For example, if you are in PPN [100,377], it would normally return 64 and 255, since those are the decimal equivalents of the octal values 100 and 377. But with SBR=XPPNOCT, it will actually return the decimal values 100 and 377. Note however, that such numbers may not fit in a single byte, so the P and PN parameters should be at least 2 bytes long.


XTREE

Added December 2012

Following is a list of the XTREE functions that may be set or enabled using the SBR= system parameter. For more information and context, see the discussion on XTREE's PopupMenu.

Switch | Description
XTREE_EXPCSV | Exports tree contents to comma separated file.
XTREE_EXPTSV | Exports tree contents to tab separated file.
XTREE_EXPOPEN | Launches player for above file type after export.
XTREE_PRINT | Prints the tree.
XTREE_SRCH | Display windows "Find" dialog.

For example:

SBR=XTREE_EXPOPEN

History

2012 December, A-Shell 6.1.1326: Functions added to A-Shell


SWAPKEY

SWAPKEY=key (or ^key or numeric value)

Examples: SWAPKEY=^] (Control bracket)

SWAPKEY=0xFF47 (F12)

This parameter only applies to A-Shell/UNIX when PolyShell is in use. The specified key functions something like the "POLYKEY", except for three important differences. The first is that the key is not truly "hot;" that is, it can only be used when the process is actually waiting for keyboard input. The second is that rather than swap you to the PolyShell menu, it will swap you directly to the next instance of A-Shell running under the control of PolyShell. (Or, the reverse if PolyShell is launched with the –x switch.) The third difference is that, unlike POLYKEY, the SWAPKEY may be a multi-key sequence generated by a function key. To specify this, you can use octal, hex, or decimal notation to indicate the two byte value which is returned by the function key. Numbers beginning with 0x are treated as hex, those beginning with 0 are octal, and all others are decimal. For your convenience, here are the standard two-byte values for function keys in hex notation:

Key | Hex | Key | Hex
F1 | 0xFF75 | F7 | 0xFF42
F2 | 0xFF74 | F8 | 0xFF43
F3 | 0xFFD3 | F9 | 0xFF44
F4 | 0xFFC0 | F10 | 0xFF45
F5 | 0xFF40 | F11 | 0xFF46
F6 | 0xFF41 | F12 | 0xFF47


SWAPWAIT

SWAPWAIT=<wait in milliseconds>

Example: SWAPWAIT=25

(UNIX only) This statement allows you to specify something other than the default wait within the terminal driver when swapping screens or screen sizes. Currently this only affects the wyse50 driver, and was implemented because the standard wait is a full 1 second, which is apparently necessary on some versions of the terminal but not on terminal emulators. The main downside of the extra wait occurs within PolyShell, where it delayed the repaint of the new screen when swapping sessions. To allow this to remain as flexible as possible, the default value of zero simply causes the terminal driver to use its normal wait time (which in the case of wyse50 is equivalent to SWAPWAIT=1000. So to minimize the wait, set SWAPWAIT=1.

In order to allow this to be set on a terminal by terminal basis, SET.LIT 1.2(129) and up supports a SET SWAPWAIT {#} subcommand. If the {n} value is specified, it sets the SWAPWAIT time, otherwise it displays the current setting.


TRACE

Updated and Reviewed July 2010

TRACE=option {,option} {,option}

This optional parameter can be specified to cause various types of debugging trace messages to be output during normal A-Shell operation. Unless otherwise noted, TRACE messages are output to the log file ashlog.log, typically in the same directory as the miame.ini, or as specified by LOGDIR. This file is automatically "rolled over" when it reaches a certain size (generally 3 MB), with several prior versions archived as ashlog.001, ashlog.002, etc. Trace messages written to the log file may also be output to the Debug Message Window. Some of the traces output directly to the screen, or as noted in the table below.

Most of these settings can be adjusted with the SET.LIT command, and all of them can be set using MX_GETTRACE and the adjacent Set TRACE Flags.

It is recommend that you enable the INOUT, BASERR, and SIGHUP traces by default (e.g. TRACE=INOUT,BASERR,SIGHUP) as they leave a trail of information that is very useful for reviewing system activity and researching errors without creating an excess number of log entries.

The following table shows the options used with the TRACE function. The "Used In" column specifies if the option applies to the TRACE system parameter ("INI") or to the SET TRACE command ("SET").

Option | Used In | Description
AMOS | INI, SET | Logs information related to the use of XCALL AMOS and operations that involve the launching of another ashell session.
AMSORT | INI, SET | Displays information (in a pop-up window) during sorting operations, showing the type of sort, current phase, memory usage, etc. If sorts are talking a long time, this can be very useful for determining what is happening, and how much memory you might need to improve the performance. (For very large sorts, we also offer an add-on "world class" sort module that is much faster and more flexible, but requires a small license fee; contact us for details.)
ATE | INI, SET | Logs details of the GUI commands and responses sent between a server and an ATE client. Note that this command might make sense to activate on both the server and the client, as they have different perspectives. This will result in two log files, one on the server and on the ATE client.and responses.
BASERR | INI, SET | Logs all Basic errors, indicating if they were trapped or not, along with other details typically lost in the translation between the user experiencing the error and the programming investigating it. Highly recommended for nearly all installations.
DEBUG | SET only | This is a catch-all for logging all kinds of information. It should only be used in focused circumstances, since the amount of tracing data quickly becomes overwhelming. May also be activated via the –trace switch on the A-Shell command line.
ERS | INI only | same as "EFS."
EFS | SET only | Traces the A-Shell stream (sequential file i/o) wrappers used when the Encrypted File System (EFS) is enabled. Also sometimes "overloaded" to trace specific unrelated operations for debugging purposes, usually on a temporary basis
EXEC | INI, SET | Traces RUN, CHAIN, command line and XCALL AMOS statements.
FOPENS | INI, SET | Logs information about file opens (both programs and data). Under Windows, this also includes how many microseconds it takes to open the file, which can sometimes be useful in identifying bottlenecks due to network issues.
GDIPRT | INI, SET | (Windows only) Logs and/or displays information about processing of print directives.
GUI | INI, SET | (Windows only) Logs details about various low-level GUI operations. It is quite verbose.
INOUT | INI only | Writes debugging information to ashlog.log as each new instance of A-Shell is opened or closed, indicating the number of jobs running at that point. Highly recommended for virtually all installations. .
ISAM | INI, SET | Logs ISAM operations.
JOBLCK | INI, SET | Causes all unresolved lock/unlock operations on the jobtbl.sys file to be traced in the file jobtbl.lck.
JOBS | INI only | Logs details relating to the job table operations (quite verbose).
KBD | INI, SET | Logs keyboard operations (quite verbose).
LOCKS | INI, SET | Displays debugging information on the bottom status of the window related to record locking operations. In particular, it provides a sense of how many retries or how long the job is waiting for access to a record. In the case of FLOCK, it will also display all of the relevant locking parameters whenever the subroutine is forced to wait and whenever it exits with a non-zero error code.
LP | INI, SET | (Possible in INI context, but not recommended.) Displays on the screen details about printing, including processing of any EZSPL configuration file, plus the printer init commands, plus the actual communication or initialization operations with the printer itself. Extremely useful for debugging printing problems. (SET TRACE LP ON, then using PRINT to print a dummy file, like ERSATZ.INI).
MALLOC | INI,SET | Log details of all memory allocations.
QOP | INI | Logs details relating to queue block operations.
RW | INI, SET | Log all random/isam file reads and writes, INPUT and PRINT file operations, SERCH reads.
SIGHUP | INI, SET | Log receipt of SIGHUP (hangup) and SIGTERM (kill) signals, along with information indicating how the signal was responded to, whether the program and ashell session were shut down, etc. We recommend you set this switch permanently in the miame.ini file (TRACE=SIGHUP) since they should be relatively rare and frequently either worth investigating directly, or they provide an explanation for something else you are investigating.
SIGNAL | INI, SET | (UNIX only) Same as the SIGHUP option, but also displays on the screen the name of any trapped signal received by the process. See Job Terminations for more information relating to handling of incoming signals.
SOCKS | INI, SET | Logs details about TCP (socket) operations.
SQL | INI, SET | Logs information about SQL operations.
SYSERR | INI, SET | Display (in a pop-up window on screen) details about all errors. This is sometimes useful for see the system error details corresponding to a particular A-Shell error, but can also be annoying since it presents the appearance of a serious error having occurred, sometimes in situations that weren’t really very serious at all.
USRMEM | INI, SET | Log details about "user memory" operations – i.e. loading of programs, subroutines, function key translation files, etc.
XCALL | INI, SET | Logs most subroutine calls. Certain extremely common routines, like MIAMEX, are not logged, unless the XDEBUG trace is also activated.
XDEBUG | INI only | Increases the verbosity of several other traces.
XTREE | INI only | Logs XTREE operations.

Subtopics

Debug Message Window

TRACE option EXEC

TRACE Option JOBLCK


Debug Message Window

To open the debug message window, position the cursor anywhere in the A-Shell window except on a GUI control and press Ctrl+Shift+DoubleClick. The A-Shell GUI Control Operations window will open, offering the following buttons:

this is a linked file

Dump Control Info to Spreadsheet outputs a list detailing all the current application-created controls in CSV format. This is mainly useful as an independent way (outside of looking at the application source code) of examining the attributes of the controls that aren't readily visible (bit flags, click codes, etc.)

Dump Menu Info to Spreadsheet is like the previous option but for the application-added menu items.

Change Text Attributes leads to a dialog allowing you to alter some attributes of the standard text used by PRINT statements. This is mostly useful for experimenting with approaches to systematically converting screens from text to GUI.

Show Debug Dialog opens the A-Shell Debug Messages window. See below for additional options once this window is open.

Print/Preview XTREE outputs the currently active XTREE (if applicable) to a variation of the APEX preview/print utility, allowing the entire contents of the tree (not just the visible part) to be printed.

A-Shell Debug Messages window

Right click on the window to get a context menu of options:

• Use the Properties dialog to enable/disable the display of system trace messages

• Activating a checkbox option in the Properties dialog is equivalent to turning on the TRACE of the same name (either in the miame.ini or via the SET command).

• Any enabled system TRACE option will result in the corresponding messages appearing in the ashlog.log file, and, while the Debug Messages window is open, in that window as well.

• Unchecking the Show System Traces option leaves the checked traces in effect (so they output to the ashlog.log) but stops them from going to the Debug Messages window. This might be useful in cases where you want to concentrate just on trace messages explicitly output from your application via TRACE.PRINT or DEBUG.PRINT statements.

• Closing the Debug Messages window does not deactivate any of the currently enabled traces; they continue outputting to the ashlog.log file.

• Clipboard operations: You can select/unselect individual lines in the Debug Messages window by clicking on them, or by using the Select All option from the context menu to select them all. Use the Copy option from the context menu to copy the selected lines to the clipboard. (From there, they can be pasted into other text editors, such as notepad or an email editor.) Since there are no integrated search or editing features, the recommend procedure for such is to select the desired lines (or all), copy to the clipboard, then paste into Notepad or your text editor of choice for further searching and editing.

• The Dump Font Cache option on the context menu outputs details about all the fonts currently used by A-Shell

• The Set Debug Mode option on the context menu is equivalent to the dot prompt command SET DEBUG. Since the DEBUG switch often results in a considerable volume of trace messages, the ability to turn it on and off in the middle of a program is often very useful for obtaining debugging information without being overwhelmed by it.

• Note that for some timing-dependent GUI operations, turning on the Debug Messages window can sometimes affect the timing to the extent that the issue you are trying to track may actually change or disappear. In such a case, minimizing the message window may help; otherwise, closing it entirely (and then extracting the messages later from the ashlog.log) may be the only option.

History

2014 October, A-Shell 6.1.1384: Add "View A-Shell Log File" to the GUI Control Operations dialog and rename the dialog to Developer Control Operations.


TRACE option EXEC

The TRACE option EXEC traces RUN, CHAIN, command line and XCALL AMOS statements. This is particularly useful for tracking user activity. Example trace formats:

Context | Format
RUN PROG1 (from dot prompt or command file) | <RUN:xxx> Exec(CHAIN): c:\vm\miame\dsk0\007006\prog1.run
CHAIN PROG2 (from PROG1) | <PROG1:xxx> Exec(CHAIN): c:\vm\miame\dsk0\007006\prog2.run
XCALL AMOS, "RUN PROG3" (from PROG2) | <PROG2:xxx> Exec(AMOS): Exec(AMOS): RUN PROG3
LOG DSK0:100,150 (from dot prompt or command file) | <yyyy:xxx> Exec(CMDLIN) LOG DSK0:100,150

So essentially you can search or filter for "Exec(" to easily pick up all the command lines and programs executed.

As with other TRACE options, you can set it from/in various contexts:

Context | Statement
In the MIAME.INI | TRACE=EXECUTE
From the command prompt | SET TRACE EXECUTE ON
From within a program | XCALL MIAMEX, MX_GETTRACE, trflags
From within a program | XCALL MIAMEX, MX_SETTRACE, trflags OR TROP_EXECUTE

The symbol TROP_EXECUTE is defined as &h80000000 in ashell.def.


TRACE Option JOBLCK

Added October 2016

TRACE=JOBLCK causes all unresolved lock/unlock operations on the jobtbl.sys file to be traced in the file jobtbl.lck. The intent here is to make it easier to debug and resolve a rogue condition whereby a process has a lock on jobtbl.sys preventing other users from getting in or out of A-Shell. Under Linux you can use the lslk utility to see who has a lock on the file, but under AIX this appears to be nearly impossible, and under Windows it may be difficult.

The jobtbl.lck file is created in the same directory as jobtbl.sys, and consists of human readable ASCII text lines in the following format:

pid,op,recno

where pid is the process id, op is either "lock" or "unlock", and recno is 0 for the jobtbl header, else a number indicating the jobtbl record for that job number. For example:

2415,lock,5

3723,lock,15

2415,unlock,5

3724,unlock,15

The above case indicates the following chronology:

process 2415 locked the jobtbl record for job #5

process 3723 locked the jobtbl record for job #15

process 2415 unlocked the jobtbl record for job #5

process 3723 unlocked the jobtbl record for job #15

Since at this point the locks and unlocks match, on the next operation, the file will be truncated and started over again.

If the option is enabled and you get a "unable to access JOBTBL.SYS" error, you can then display this file to hopefully identify which processes have locks on the file and can then investigate or kill those processes.

History

2016 September, A-Shell 6.3.1526: JOBLCK added to A-Shell. Note that a stripped-down version of this feature was added in 6.2.1428.0.


TRMDEF

TRMDEF=Device, Jobname, Terminal, Driver

A-Shell will automatically generate job and terminal names in the form of TSKAAA, TSKAAB as each new job is launched. For most applications, this is perfectly acceptable (and virtually unavoidable for TELNET connections. But if you want to try to associate TRMDEF and JOB names with particular terminal devices, the TRMDEF facility may help you.

The general idea is that whenever a new A-Shell session is launched, A-Shell first checks the command line switches. If switch –j <jobname> has been specified, then that jobname is used. Otherwise, it determines the device name of the workstation, then checks if there are any TRMDEF statements which reference either all or part of that device name. If a match is found, then the JOBNAME, TERMINAL, and DRIVER specified in the TRMDEF statement will be assigned to the new job. Otherwise, the first available name of the type TSKAAA will be used instead.

As an example, suppose the terminal device (as displayed by the –d switch to ashell or by .SYSTAT/C) is tty3a:5623. The part after the colon will change every time, but since tty3a is a regular serial port (as opposed to a network pseudo port) it will be the same each time. So if you wanted to make that terminal come up with the jobname and terminal name "ship," you could add the following statement to your miame.ini:

TRMDEF=tty3a,ship,ship,am62a

When this statement is processed by an instance of A-Shell whose device name starts with "tty3a", it will cause the jobname SHIP and terminal name SHIP to be assigned to that instance. (You could theoretically make the job and terminal names different, but this doesn’t really accomplish anything other than add to the confusion, since it is not possible to change the attachment between a job and a terminal.) The terminal type am62a will also be assigned, although in most cases it is preferable to omit the terminal type from the TRMDEF line so that the terminal specified in the TERM environment variable will be used instead.

Under Windows , the device name is, in most cases, the workstation’s machine name (or "network ID") with a suffix identifying the window # appended (e.g. "SHIPPING-PC:01".) You could use this as the basis of the following TRMDEF statements:

TRMDEF=SHIPPING-PC:01,SHIP1,SHIP1,PCTDVG

TRMDEF=SHIPPING-PC:02,SHIP2,SHIP2,PCTDVG

The first line above would apply to the first window opened by the PC whose machine name was "SHIPPING-PC", and the second line would apply to the second window opened by the PC. The terminal driver name (PCTDVG) is again optional; if not specified here, the default will come from the CONSOLE statement.

For system administration convenience, you can put all of your TRMDEF statements in a separate file (TRMDEF.INI) which is included into the configuration file using the INCLUDE command. This file should contain one TRMDEF line for each terminal which is allowed to run the MIAME application. You may mark comment lines by starting them with a semi-colon or #.

Note: The following section applies to UNIX-based systems only:

Although UNIX does not have terminal drivers as such, it does have a table-driven equivalent (terminfo), which enables fairly advanced screen handling to be performed in a terminal-independent manner, though it is nowhere near as good at it as AMOS terminal drivers. A-Shell makes use of terminal driver equivalents (written in C) in order to better handle attached screens, though a generic driver (GENERC) is provided which does make use of the terminfo database.

UNIX makes use of an environment variable TERM to indicate the terminal type in order to find the correct terminfo entries. A-Shell also makes use of this variable in order to determine which terminal driver to use. The TERM variable is analogous to the terminal driver name, except that it is not guaranteed to be restricted to six characters, and so is not returned directly by the gettdv() routine. The TRMDEF lines in the MIAME configuration file must therefore be kept in step with the terminal types defined on the system, with six-character equivalents of each terminal’s TERM variable setting.

Note: The following section applies to Windows-based systems only:

There is only one proper terminal driver embedded within the Windows version of A-Shell, although there are several variations:

Driver Name | Notes
PCTDV | Standard Windows.
PCTDVG | Windows version only. Same as PCTDV except certain "GUI enhancements" may be applied, such as displaying XCALL MESAG messages in a dialog box rather than on line 24.
PCUK | Standard UK (national replacement character set) version of PCTDV. The # or £ keys return ASCII character 35, and character 35 is always displayed as £.
PCUKG | Same as PCUK but with the Windows "GUI enhancements" described above.
PCFR | French national replacement keyboard version. Same idea as PCUK
PCFRG | Same as PCFR but with the "GUI enhancements" described above.

Note that TRMDEF statements are entirely optional, and in most cases, are best ignored, since unique job and terminal names of the form TSKAAA, TSKAAB, etc. will be created.

The use of INCLUDE in order to separate terminal definitions is entirely optional. If TRMDEF commands are used, then they can equally well be given in the main MIAME environment definition file.


UMASK

Updated July 2015 ("Note that...")

UMASK=###

(UNIX only) This statement allows you to change A-Shell’s default file creation mask from 111 to something else. If you set UMASK=000, it will use the mask set by the shell. Otherwise it will use the specified mask. Note that the bits in the umask clear the corresponding bits in the file creation mask, which starts at 666 (rw-rw-rw-). So setting UMASK=111 will result in no change to the rw-rw-rw- mask. But UMASK=137 would result in rw-r---- (rw by the file owner, read only by members of the group, otherwise no access.)

Note that although you can't directly set the UMASK to 000, because that effectively sets it to the current default, in some environments you can work around that limitation by setting UMASK=1000.

History

2005 April, A-Shell 4.9.953: UMASK now supports an optional second parameter to set UMASK for directory creation:

UMASK=filemask {,dirmask}

For example:

UMASK=011,002

Remember that the bits in the UMASK cause the corresponding bits in the file or directory permissions to be cleared, so 002 corresponds to drwxrwxr-x.


XONXOFF

XONXOFF=ON/OFF/ALWAYS (default is ON)

This optional command applies to A-Shell/UNIX only. When ON, the ^S and ^Q keys can be used to stop and start rapidly scrolling output (such as from a TYPE or DIR command) as long as the program is not waiting for input, and as long as the current line handshaking discipline supports XON/XOFF. In most cases, while waiting for keyboard input, XON/XOFF is disabled to avoid conflicts with other uses of these keys. (One exception is VUE. In order to access the ^Q and ^S VUE commands, you can use the alternate sequences ^_Q and ^_S.) When XONXOFF=OFF, the ^S and ^Q keys do not do anything special.

XONXOFF=ALWAYS is like ON, except that it leaves XON/XOFF control active even during input operations. This takes away the ability to use ^S and ^Q as input commands, but it eliminates a problem which can happen with some dumb terminals in which the turning off of flow control during the transition from a long output to an input can cause the last few characters of the previous output operation, which had been output by A-Shell but were still buffered by the operating system, to become garbled. The symptom of this problem could be seen in a long DIR/W operation, in which it would handshake correctly up until the last couple of lines at the end, just before returning to the dot prompt.

In most cases, the PAGE.LIT command will accomplish the same thing (only better) for which you were trying to use Ctrl+S and Ctrl+Q.


Printer Configuration

Printing is probably the most complicated and confusing area within A-Shell. There are a couple of reasons for this.

• The print spooling facilities and capabilities vary widely among the platforms supported by A-Shell.

• Network environments impose another layer of configuration complexity beyond what you may have been used to with AMOS.

Perhaps we could have approached this problem by developing an emulation of the AMOS spooler for each platform. However, this would have conflicted with one of the underlying design philosophies of A-Shell, which is to allow your application to coexist with other applications on a given platform, sharing common operating system facilities as appropriate. Therefore, since virtually all Windows applications spool reports via the Print Manager, it makes sense that A-Shell does too. UNIX applications typically use one of the spoolers provided by the operating system, so again, A-Shell does the same.

This approach may make it easier for a system administrator to integrate and manage A-Shell in an existing environment, but it does require that the administrator or installer create printer configuration files which define the interface between the logical printer names used within the AMOS / A-Shell applications, and the corresponding real printers available in the physical establishment. The following sections describe this in detail.

Subtopics

Defining Spoolers

Init File Commands

Troubleshooting Techniques

Supported Printer Interfaces

EZSPL

Send File to Printer or Queue


Defining Spoolers

A-Shell spoolers, like their AMOS counterparts, have names of one to six characters and are defined by means of an initialization (normally abbreviated "ini" or "init") file, which is a small text file containing various configuration parameters. Under AMOS, these files were named <printer>.INI and were stored in the SYS: directory. Although A-Shell supports that method and will find and process those ini files, the recommended and preferred method is to use files named <printer>.PQI which are stored in the ASHCFG: directory. The extension PQI stands for "Printer Queue Initialization" and was chosen to minimize the likelihood of conflict or confusion with other file extensions, as well as other types of ini files. The actual content of .PQI files and .INI files is identical.

The ersatz directory ASHCFG: is typically DSK0:[1,7] but can in fact be anything. By grouping the printer initialization files in a special directory (away from the standard release files) and by using a unique extension, it is easy to identify the available printer configurations on a system. However, when looking for a printer, if the ASHCFG:<printer>.PQI file is not found, A-Shell will continue to look for SYS:<printer>.INI as before.

To allow for a temporary override of the printer init file without actually modifying or changing the active one, A-Shell will first check for <printer>.PQI in the %TEMP% directory. So the complete search path is:

%TEMP%\<printer>.PQI

ASHCFG:<printer>.PQI

SYS:<printer>.INI

For example, if the application wants to spool to a printer called LASER1, then A-Shell will look for a printer init file called %TEMP%\LASER1.PQI or ASHCFG:LASER1.PQI or SYS:LASER1.INI which defines the configuration of that printer.

If no printer name is specified in the PRINT or XCALL SPOOL statement, the default name is determined by the PRINTER statement in the miame.ini file. If there is no PRINTER statement, under UNIX, A-Shell will look for a file $HOME/.PRINTER, from which the printer name will be read from the first line of the file, if found. If no default printer is defined, then A-Shell will attempt to print to the default printer for the host operating system environment.

Unlike AMOS, where the printer initialization files are processed at system boot up, A-Shell ignores these files until you actually make a print request. This is possible because the printer init files only specify interfacing information that can be processed at run time. Thus, any changes you make to a printer init file will take effect with the next print request. Also, because the printer init files are only processed when referenced by a print request, there is no harm in having printer init files that do not refer to actual or available printers.

There is no limit to the number of printer initialization files you may have. Thus, there is no limit to the number of logical A-Shell printers that may exist. There is also no limit to the number of logical A-Shell printers that may actually correspond to the same system spooler. Any given line in a printer init file can be a maximum length of 256 characters.

The exception to the rule requiring the existence of a printer init file is that it is possible to use the Windows or UNIX printer name directly, instead of the AMOS or A-Shell name. In that case, a default printer configuration will be used. For Windows, this consists of DEVICE = <printer>, PASSTHROUGH=OFF and PITCH=AUTO. Under UNIX is would simply be DEVICE = <printer>. This technique is particularly useful under Windows in conjunction the subroutine MIAMEX 120, Prompt for Window Printer, which allows the user to select a printer using the standard Windows printer selection dialog.

Examples of typical printer initialization files for Windows and UNIX are given in the following topic. Note that in all cases, the only mandatory parameter is DEVICE (or alternatively, COMMAND); all others are optional.

Subtopics

Printer INI File Examples


Printer INI File Examples

Following is an example of a typical Windows printer INI file.

DEVICE=\\server\hp1 | HP LaserJet Series II

LPP=66

CPP=80,136

FONT=Courier New

CHARSET=ANSI

WEIGHT=400

PITCH=AUTO

ORIENTATION=PORTRAIT

TMARGIN=1

LMARGIN=0

PASSTHROUGH=OFF

PREFIX=SYS:LASER.PFX

SUFFIX=SYS:LASER.SFX

FORMFEED=ON

DELETE=OFF

BIN=UPPER

The typical UNIX printer INI file is generally simpler:

DEVICE=jet7

PREFIX=SYS:JET7.PFX

SUFFIX=SYS:JET7.SFX

FORMFEED=ON

AUTOFF=ON

STRIPFF=ON

DELETE=ON

BANNER=OFF

Any commands that are not recognized are just ignored. It should be noted that not all commands are interpreted by all implementations of A-Shell, and they are very much at the mercy of the capabilities of the host operating system. Note that the all parameters are optional except for DEVICE or COMMAND, one of which is critical.


Init File Commands

Below is a list of the printer initialization file parameters, followed by detailed descriptions of each parameter, along with usage, syntax, suggestions and warnings. The parameters are listed here in alphabetic order, but may in any order within the init file. The only absolute requirement for printer init files is that they contain one DEVICE (or COMMAND) entry.

Parameters that apply only to Windows or only to UNIX/Linux are so noted at the start of the description for each parameter. If not otherwise stated, the parameter applies to both Windows and UNIX/Linux.

Under Windows, the PASSTHROUGH parameter has a very significant effect on nearly every other aspect of printing, so you may want to review it first.

Command | Description | Command | Description
APEX | Ignore PREVIEW setting on server, execute on client | LMARGIN | Specify left margin
AUTOFF | Add trailing form feed | LPP | Specify number of lines per page
AUTODLGOK | Auto respond to some pseudo printer drivers | ORIENTATION | Specify portrait or landscape page orientation
AUXPCDIR | Specify location of output file | OVERLAY | Add specified file to beginning of each page
BANNER | Add banner to beginning of printout | NOABORTDLG | Disable display of Windows "Abort?" dialog
BIN | Specify paper source | PAPERLENGTH | Set custom paper size
CHARSET | Specify character set | PAPERSIZE | Set paper size
COMMAND | Specify alternate processing of print file | PAPERWIDTH | Set custom paper size
CPP | Specify columns per page, and hence font width | PASSTHROUGH | Set Windows mode
CRLF | Force output lines to have CRLF terminators | PITCH | Calculate font height and width
CRNL | Same as CRLF | PREFIX | Prepend specified prefix file to print file
DATATYPE | Send command to Windows Print Manager | PREVIEW |
DELETE | Delete file after printing | PRTCMD | Same as COMMAND
DEVICE | Associate A-Shell printer with host printer | PRTCOPIES | Select mode for printing multiple copies
DUPLEX | Enhances duplex printing. | STRIPFF | Remove form feed from beginning of print file
FONT | Specify font | SUFFIX | Append specified suffix file to print file
FONTHEIGHT | Specify font height | TMARGIN | Specify top margin
FONTWIDTH | Specify font width | WEIGHT | Specify weight ("boldness") of font
FORMFEED | Enable/disable form feed | XOFFSET, YOFFSET | Make minor positioning adjustments.
HEADER | Add header to page(s) | XORIGIN, YORIGIN | Define offset from paper corner.


APEX

APEX = <Boolean>

This switch is nearly the same as PREVIEW, but is specifically for the ATE case where you want the PREVIEW option to be ignored on the server and only recognized on the client. Otherwise, activating PREVIEW on the server in a non-GUI environment might give you the text-mode preview, EZTYP. See APEX for operations.


AUTOFF

AUTOFF = <Boolean>

(UNIX/Linux only) This option (which defaults to OFF) may be turned on to have A-Shell itself take over the task of putting a trailing form feed on the end of a print file when required by your spooler switches. Note that in order for this to work, you must use a printer filter which never adds a trailing form feed. For SCO we supply one on our web site called dumbnoff (copy it to /usr/spool/lp/model). For most other UNIX flavors, you can simply select a "dumb" or "null" printer filter (aka "driver" or "model").

AUTOFF can be used in conjunction with STRIPFF and FORMFEED (which see) to reconcile different applications’ approaches to form feeds.


AUTODLGOK

AUTODLGOK={class,}<dialog title>

This command makes it possible to automatically respond to a predictable dialog displayed by some pseudo printer drivers like PDF writers. Typically these will default to the same name as the source file, but with a PDF extension, and wait for the user to hit the SAVE button (or possibly to change the directory or filename first.) If you would rather just accept the default and not have to respond to such dialogs, you can this command to your printer initialization file:

Parameters

{class} is an optional Window class for the dialog (which you may be able to get from a Spy utility). If omitted, then the dialog will be recognized solely by its title.

<dialog-title> is the string appearing in the title bar of the dialog.

Example

For example, for the popular PDF995 driver, you could use:

AUTODLGOK=Pdf995 Save As

In this case, after A-Shell sends the file to the printer, it waits a few seconds to see if a dialog pops up with the specified title. If so, it sends an Enter keystroke to it to just accept the default and proceed.

Comments

Note that in most cases, the default directory will be set to match the directory used for the previous Save As operation by that driver. So before creating a thousand PDF files this way, you may want to first use the regular interactive method to establish the default directory.

History

2006 March, A-Shell 4.9.931: AUTODLGOK added to A-Shell


AUXPCDIR

AUXPCDIR=<pc path>

This command may be used in conjunction with DEVICE=AUXLOC: to specify where the output file will be placed on the PC. Normally this doesn't matter much because the file is usually deleted after printing, but in cases where that is not true, and especially for PDF generation, the location is rather important.

For example,

AUXPCDIR=%MIAME%\PDF

If <pc path> does not exist, it will be created (provided that its parent path exists).


BANNER

BANNER = <Boolean>

(UNIX/Linux only) BANNER may invoke a printed banner at the start of each printout if such an option is available. On some UNIX spoolers, a banner is unavoidable. The default is OFF, though this may be overridden by the correct switch to SPOOL.SBR.

Under SCO UNIX, you must use the lpadmin –p<printer> -onobanner command to enable the ability to ask for no banner. Failure to do this may cause the spooler to reject all print requests specifying no banner. You may also want to use the scoadmin utility to set the default number of banners to 0. See Troubleshooting Techniques.


BIN

BIN = bin-ID

(Windows only) This command allows you to specify a particular paper source in a printer that has multiple paper sources. The choices for bin-id are:

UPPER | LOWER | MIDDLE | MANUAL | AUTO
ENVELOPE | ENVMANUAL | LARGEFMT | SMALLFMT |
LARGECAPACITY | FORMSOURCE | USER<#> | <bin ID number> |

Since some of these bin identifiers are rather cryptic, it may not be easy to determine what the appropriate name is for the bin you want to specify. Ultimately, this may require some trial and error, but you can at least get a list of the available bins in a specific printer, by adding one of the above BIN commands to your printer INI, then activating line printer trace mode and printing a sample file:

.SET TRACE LP ON

.PRINT <printer>=SYS:<printer>.INI

This will cause a lot of tracing information to be displayed to the screen, including a list of all of the BIN names for the specified printer.

Notes

Some printers may require that you manually configure them to allow the application to select the bin. See your printer documentation for details on that.

If you specify a bin that the printer does not support, the result will be dependent on the printer driver. It may ignore the request, it may attempt to give you a closest match, or it may do something else.

Some printers may implement "user-defined bins". The first 8 of these can be usually be referenced by "USER1" through "USER8". Note, however, that some printer drivers start the user-defined bins at something other than "USER1". If in doubt, use the tracing technique described above to display the list of available bins.

When a printer supports a bin that is not recognized by name by A-Shell, it will appear in the list of bins (displayed when using SET TRACE LP ON) as a number. You can use any such number in the BIN command just like it was a bin name (e.g. BIN = 265).

For what it’s worth, "USER1" is equivalent to BIN #256, "USER2" to BIN #257, etc.

BIN works with both PASSTHROUGH=ON and with PASSTHROUGH=OFF.

BIN is one of the printer init file commands that has a GDI Printing Directive Equivalent.


CHARSET

CHARSET = <charset name or number>

(Windows only) This optional command works in conjunction with the FONT command to determine the font character set that is selected. Choices are as follows:

Value | Meaning | Value | Meaning
ANSI (or 0) | ANSI character set (default) | 161 | Greek
OEM (or 255) | OEM character set | 162 | Turkish
Symbols (or 2) | Symbol set | 177 | Hebrew
Default (or 1) | Default for selected font facename | 178 | Arabic
77 | Mac | 186 | Baltic
128 | Shift JIS (Japanese Kanji) | 204 | Russian
129 | Hangeul | 222 | Thai
134 | GB2312 | 238 | Eastern Europe
136 | Chinese Big5 |  |

Note that merely specifying an exotic character set does not mean you will get it, because a font with those characteristics has to exist. If you specify both a font name (using the FONT= parameter) and a charset, the character set will become most important if the requested font facename does not exist. This is why the default setting is ANSI rather than DEFAULT, because ANSI is what is expected.

You must set PASSTHROUGH=OFF for CHARSET to be applicable. Also note that you can change fonts in mid report using the GDI print commands; see Print Directive List. Also see FONT and WEIGHT, which work together with CHARSET to determine the actual font selected.


COMMAND

COMMAND may be used in place of (or in some cases, in addition to) DEVICE, in order to specify an alternate command or subroutine for processing the print file, which is also known as a "print filter." This can be especially useful when interfacing to non-printer devices such as faxes, email, archival systems, etc., as well as for performing special filtering operations on print files without having to change the application that created them. There are two forms of the command, named according to which system will be doing the processing."

Only one COMMAND can be specified in a single printer init file.

Subtopics

Host Processing

A-Shell Processing


Host Processing

COMMAND = <executable command line>

This specifies an arbitrary native operating system command to be executed. The command may optionally contain two optional formal parameters: $copies, which is replaced by the actual number of copies requested, and $file which is replaced by the filename requested. If $file is not specified, then the (native) print file name is appended to the end of the command line. Here are two examples:

COMMAND = mylpr –n$COPIES $FILE

COMMAND = notepad.exe $FILE

If the requested print file request was for one copy of SYS:ERSATZ.INI, these would expand to something like the following::

mylpr –n1 /vm/miame/dsk0/001004/ersatz.ini

notepad.exe c:\vm\miame\dsk0\001004\ersatz.ini

The above commands assume UNIX/Linux in the first case, with the default definition of DSK0: as /vm/miame/dsk0, and Windows in the second case, with DSK0: defined as C:\vm\miame\.

Note that in this example, the $file parameter is not necessary since the filename would have been appended to the end of the command line anyway.

Also note that under UNIX/Linux, the host command must be executable from the current command shell—i.e. be either an executable binary or a script.

See the SBR option SUBMIT2 for related information.


A-Shell Processing

Updated February 2015

COMMAND = SBX:<sbxname>{,<optional parameters>}

This form of the command invokes the specified SBX subroutine. In order to use this form of the command, you will have to have an appropriate SBX routine in DSK0:[7,6]. That subroutine will be "XCALLed" with the following parameters:

xcall <SBXNAME>,status, fspec, printer, switches, copies, form {,<optional parameters>}

Status is mapped B,1 and must returned with a positive number if you want the print operation to proceed. Else set it to 0 to cancel the print operation, or a negative number to signify an error. (It gets passed in as -1, so you don't need to set it to abort.)

If status comes back to the print processor set to 1 or more, then it will first check to see if the subroutine has changed the printer name. If so, it starts the print operation all over again with a different printer initialization file. Otherwise, it proceeds to process the current printer request as if the COMMAND had not been executed. (This only has an effect if your printer initialization file also contains a DEVICE statement.)

The remaining parameters are all string format. You can convert switches and copies to numeric variables, but if you want to change them, convert them back to strings before passing the parameters back.

Any parameters that are specified on the COMMAND = SBX: line will be added to the end of the parameter list, to be interpreted by the SBX subroutine. For example:

COMMAND = SBX:EMAILP,4,"Subject","Intro, text…"

In the above example, the subroutine EMAILP.SBX will be called with the following parameter list:

XCALL EMAILP, STATUS, FSPEC, PRINTER, SWITCHES, COPIES, FORM, 4, "Subject", "Intro, text..."

The SBX subroutine may change any of the first six parameters (status thru form), and the changes will take effect before the print operation proceeds (assuming STATUS is set > 0.)

Four sample routines (PFILTR, EMAILP, HTMLP, and GDIPRT) are supplied, with source, in the samples directory. PFILTR just prints out the parameters and allows you to update them before returning to the print processor. (This is very useful for learning/testing.) EMAILP launches the local email client and inserts the print file into the message (either in the body or as an attachment.) HTMLP wraps the print file with a simple HTML header and trailer (using a temporary file) and then displays it in your default browser (as a sort of preview utility). GDIPRT can be used under A-Shell/LINUX or UNIX, to forward the print file to be processed on the local PC. (It requires ZTERM, ATE or A-Shell/Windows on the PC.)

History

2014 November, A-Shell 6.1.1398: Print filter enhancement: The printer init statement COMMAND=SBX:filter,... now supports two optional macro arguments, $PREFIX and $SUFFIX, which evaluate to the current prefix and suffix options. For example, given the following printer init file:

DEVICE=TEST

COMMAND=SBX:PFILTR,$PREFIX,$SUFFIX

PREFIX=TEST.PFX

SUFFIX=TEST.SFX

the print filter PFILTR.SBX would receive "TEST.PFX" and "TEST.SFX" as the 7th and 8th arguments. The first 6 arguments to a printer filter are always preset to STS,FSPEC,PRINTER,SWITCHES,COPIES and FORM.


CPP

Updated December 2009

CPP = <# columns per page> {,<# cols in condensed mode>}

(Windows only, PASSTHROUGH must be off) The CPP (columns per page) parameter works in conjunction with the PITCH=AUTO option (see PITCH) to establish a suitable font width. Note that if any of the first fifteen lines of the file (not counting trailing spaces) are longer than the first parameter specified, the CPP value is automatically switched to the second parameter, or 132 (if no second parameter specified), in order to accommodate applications that use condensed print on some reports. For example, consider the following:

CPP = 80,140

If none of the first fifteen lines of the report are longer than 80 characters (not counting trailing spaces), then a font suitable for 80 characters across the page will be used. However, if any of those first fifteen lines exceeds 80 characters, then it will switch the entire report to a font suitable for 140 characters across the page.

You can also let A-Shell adjust the font size to handle whatever the longest of the first fifteen lines is (again, not counting trailing spaces), by using this syntax:

CPP = AUTO

Or, you can specify a fixed width for reports up to a certain size, and beyond that use the AUTO option:

CPP = 80,AUTO

This might make sense if you print reports with far fewer than 80 columns, which you didn’t want to come out in an extra large font (to expand all the way across the page), but for reports beyond 80 columns, you just wanted them to use whatever font size would fit across the page.

Notes

The main reason for specifying a "non-standard" second value in the CPP statement would be if for some reason your condensed (132 column) font were not quite small enough, resulting in a few columns being truncated. One typical case where this occurs is where a programmer took advantage of a 17 CPI condensed printing option to print 136 columns on an 8 inch line. By specifying a larger number of columns (e.g. 140), you will force a slightly smaller font to be used, eliminating the truncation problem. (This can also happen with printers having limited font scaling capability, although in that case, there’s no guarantee any particular size would have an effect.)

History

2009 December, A-Shell 5.1.1168: "*" (askterisk) is now treated as equivalent to "AUTO." For whatever reason, this was apparently a common mistake or misunderstanding, aggravated by the fact that anything other than "AUTO" or a number was effectively treated as 132 (making CPP=80,*) appear to work, until you tried a file with more than 132 columns. In addition to recognizing "*", essentially anything non-numeric now results in the equivalent of AUTO.

2002 June, A-Shell 4.7.816: Previously, A-Shell/Windows computed the required font width to satisfy the CPP requirement and assumed that the font mapper would deliver. Now, it double checks the font selected by the font mapper to make sure that it can fit the specified size across the page, and if necessary, uses trial and error to shrink it until a font that actually fits is selected. So if you are using a version prior to 4.7.816 and are having problems with the last few columns of a line being truncated, you can either manually increase the CPP specification or update to a new version of A-Shell.


CRLF, CRNL

CRLF = <Boolean>

(UNIX only) CRLF=ON may be used in conjunction with DEVICE=AUXLOC: to force the output lines to have CRLF (aka CRNL) terminators. This may be handy to eliminate the "stair step" problem that occurs under UNIX when the printer does not automatically add a CR to each LF or NL character.

To deal with the "stair step" problem in printer devices other than AUXLOC:, you typically select a printer filter to translate NL characters to CRNL during output. Or, you would configure the printer to automatically supply its own carriage return.

A related option in miame.ini is OPTIONS=CRNL, which causes all sequential output files created by A-Shell to have CRLF terminators instead of the UNIX-standard LF terminators. This would eliminate the need for special CRLF handling in your printer INI, but may cause confusion with the ability of some other UNIX utilities to act on those files, due to the non-standard line terminators.


DATATYPE

Updated and Reviewed November 2009

DATATYPE = <string>

The command DATATYPE=RAW prevents A-Shell from doing any special processing relating to the CR, LF, and FF control characters.

This may be necessary in order to embed raw graphics into print files, as may be needed with certain EPF (e.g. Zebra label printer) and PCL protocols.

Otherwise, even though PASSTHROUGH mode sounds like it "passes everything through", in reality, you still get conversion of isolated LF into CRLF, and it still identifies page breaks by FF (i.e. chr(12)), calling a standard GDI printing routine to inform the printer of the start of a page. The LF to CRLF conversion would obviously alter any graphic image, and the page break call may have had unknown results, depending on the driver.

Old Documentation, superceded

(Windows only) This parameter is passed to the Windows printer manager when preparing to spool a file, and may or may not be interpreted by the printer driver. Prior to A-Shell build 715, A-Shell always specified "Text". Then, from builds 715 thru 719, it specified NULL. From builds 720-732 it specified "RAW" if PASSTHROUGH=ON, else "EMF". These changes were made per suggestions by Microsoft to attempt to work around various printer driver bugs.

In any case, DATATYPE allows you to experiment with this setting if you are encountering mysterious Spool32 errors. It was mainly added to eliminate the need to go back to a prior version of A-Shell in order to test it. (Some people claim that the Spool32 errors did not occur prior to build 714.) Note that if you do not specify DATATYPE, it defaults to the current behavior (RAW or EMF.)


DELETE

DELETE = <Boolean>

The DELETE switch controls whether the file is deleted after printing. (Default is OFF.)

Under Windows, this option is under A-Shell’s control, and works reliably. However, under UNIX, unless A-Shell is building a temporary file to pass to the spooler (which it does to implement certain features, such as STRIPFF, AUTOFF, PREFIX and SUFFIX), A-Shell has to rely on the spooler itself to delete the file when it is done being printed. This is accomplished by passing a switch to the line printer request command (e.g. lpr, lp, enq). In some cases, particularly with Linux, this option may be "deprecated" and may not even work, due to the security issues that arise when a user is allowed to indirectly delete files via the line printer daemon (which typically operates under a different security environment than the original user.) Refer to the documentation (or "man" page) for the line printer for your operating system for more details about this if it is found to be a problem.

One way to overcome an inability of your spooler to delete files is to add the –c switch to your DEVICE command to cause the spooler to make its own local copy of the print file before printing it. This would allow your application to immediately delete the print file after sending it to the spooler, using the BASIC KILL command.

Another workaround would be to create an empty SUFFIX file, which will force A-Shell to create a temporary file combining your original file with the empty suffix. In this case, if you specify the DELETE option, A-Shell will delete the original file immediately after constructing the temporary file. The temporary files are located either in the same directory where the miame.ini exists, or in a directory specified by defining an environment variable ASHTMP (e.g. export ASHTMP=/vm/tmp). You could then create an automated procedure (using cron) to remove all of the undeleted temporary files from this directory, say, every midnight.


DEVICE

Updated and reviewed September 2011

Windows:

DEVICE = <printer device>

DEVICE = <printer device> | <alternate name>

Linux:

DEVICE = <printer device> {optional switches}

This defines the host printer queue or device to be used for the given A-Shell printer whose name matches the name of the printer initialization file. The syntax and semantics of the device specification vary with the host operating system. Note that in addition to actual printers, A-Shell supports the pseudo-devices DEVICE = AUXLOC:, DEVICE = PROMPT:, and DEVICE = DISK:.

Windows 95/98/ME: You can specify one or two names (separated by a vertical bar) where each is either a descriptive name or a hardware device name. The format and usage of these names varies between different versions of Windows. For W95/W98/ME, the descriptive name is the name that appears under the printer icon (e.g. "HP LaserJet Series II") and it can be changed by right clicking on it and selecting the rename option. The hardware device name for local printers is the port that the printer is attached to (e.g. LPT1:), and for remote printers, it is the UNC (Universal Naming Convention) share name (e.g. \\server\hp2.)

NT/W2000/XP: The descriptive and hardware device names for local printers are just as they were for earlier versions of Windows. But for remote printers, the descriptive name is actually the UNC share name (e.g. \\server2\hp2), although it will appear under the icon formatted something like "hp2 on server2". You cannot change this kind of printer name (except by redefining the share name on the system which owns the printer). The hardware device name will be a network port name like Ne02:.

Because of these semantic differences, A-Shell allows you to specify two device names separated by a vertical bar, as shown here:

DEVICE = HP LaserJet | \\server2\hp2

In this case, if the first name cannot be found, the second name is used. This can be useful in heterogeneous networks where it might be difficult for every workstation to refer to a particular printer by the same name.

Notes

Network printers do not need to be locally defined as long as the local machine can access the target printer by means of the \\machine\sharename of the printer. To take advantage of this, the DEVICE statement must specify the \\machine\sharename by itself, or as the second choice (after the vertical bar) if there are two names (as in the example above).

If it is not possible for all workstations in a network to refer to a shared printer by the same device name (or by either of a pair of alternate names under Windows), and if it is not possible for the application to allow different users to refer to the same printer by different names, then you may have to arrange for these workstations to have their own private ASHCFG: directory (or DSK0:[1,4]) so they can have different versions of a particular <printer>.PQI (or <printer>.INI) file. Refer to the miame.ini DEVICE statement.

If you are having difficulty figuring out the proper DEVICE specification for your printer, turn on line printer tracing (see Troubleshooting Techniques) and then print a sample file. It will display information showing you which printer names from the Registry it is trying to match against your device.

Printer names given in the DEVICE statement under Windows are not case sensitive, and do not need to be complete. For example, "DEVICE=HP" will match "hp LaserJet" (but not "jet HP"). Be careful, however, to make the name long enough to be reasonably unique, because A-Shell will stop on the first printer that matches. (So in the case of "DEVICE=HP", if you had both an "HP LaserJet Series 4" and an "HP DeskJet", it would match whichever one appeared first in the Registry.)

As of A-Shell build 1148 of May 2009, Windows printer names can be up to 100 characters in length. The previous limit was 50.

As of A-Shell build 1150 of June 2009: If a printer is known to exist but A-Shell fails to find it in the matching logic, you can set the first character of the printer name in the DEVICE statement to lower case (e.g. DEVICE = hP Laser), in which case if it fails to find it in the directory, it will trust you and just try to open it blindly. (This has long been the procedure for printers using share names like \\server\name.)

Linux: You must specify a valid printer queue name. These are the names that can be specified in the P switch of the lpr (Linux) or enq (AIX) commands. (A-Shell submits the file to the printing subsystem by creating and then executing an lpr or enq command line based the specified, file, printer, and other options.)

A copy of the actual command line created and submitted for each print request, along with any error response, is written to the log file OPR:SPOOL.LOG.

Because Linux spool commands may support additional switches that are not directly analogous to PRINT or XCALL SPOOL parameters, or otherwise not supported by A-Shell directly, you may add any such parameters after the spooler name, as shown here:

DEVICE = laserque 1 -c -o sides=two-sided-long-edge

In this example, the spooler name is laserque1, and the additional arguments -c -o sides=two-sided-long-edge are added to the command line created which is automatically generated, based on the file, operating system, and other parameters passed to the A-Shell spool request. (The -o sides=two-sided-long-edge option illustrates a way of implementing duplexing under Linux, even though the DUPLEX printer init command is not supported except under A-Shell/Windows.)

The –c switch generally causes most UNIX spooler commands to make a local copy of the file before printing it, thus eliminating conflicts which might otherwise occur if the application then proceeded to erase or modify that file before it was done printing. See the discussion about deleting files (DELETE) for more comments on this topic.

Subtopics

DEVICE = AUXLOC:

DEVICE = PROMPT:

DEVICE = DISK:


DEVICE = AUXLOC:

Updated September 2008

This causes the file to be redirected to the auxiliary port on the current terminal (which hopefully has been set up to further redirect the printout to an appropriate printer attached to the terminal or to the PC on which the terminal emulator is running.) Note the trailing colon.

Under Windows, DEVICE=AUXLOC: only makes sense when the Windows machine is acting as a telnet server (i.e. running ATSD), in which case, the client terminal or emulator would handle auxiliary port request the same as if the host was a UNIX machine.

If the client is ATE, the application can override the client's auxiliary port printer choice at runtime by sending the extended TAB command AG_SPOOLCFG prior to printing a file to the AUXLOC: device; see AG_SPOOLCFG for details. Or, it can use the following syntax:

DEVICE = AUXLOC:<printername>

For example, DEVICE = AUXLOC:LASER would send the file to ATE client and then tell ATE to print it to the printer named LASER (overriding the current ATE printer configuration). Note that this would require that there either be a printer visible to the ATE client whose name started with "LASER", or that there was a SYS:LASER.INI or ASHCFG:LASER.PQI file already installed on the ATE client, containing the printer initialization commands to be used.

Note that the <printername> could itself be a pseudo-printer specification, such as DEVICE=AUXLOC:PROMPT:, in which case ATE would prompt for the printer choice, even if ATE had previously be configured to print to a specific printer without prompting.

Another ATE-only variation is the ability to force the PASSTHROUGH option on or off, but otherwise accept the existing ATE printer configuraiton. This is accomplished with the following syntax:

DEVICE = AUXLOC:+GDI

or

DEVICE = AUXLOC:+PASSTHROUGH

It is also possible to set the mode (GDI or Passthrough) in the printer name; see the topic Set Printer Mode Using Printer Name for more information.

Note on Multiple Copies

See PRTCOPIES for information on how copies are handled with AUXLOC: printing.

Subtopics

Set Printer Mode Using Printer Name


Set Printer Mode Using Printer Name

Added May 2009

Beginning with A-Shell 1149 of May 2009, it is possible to combine the +G{DI} or +P{ASSTHROUGH} option with a printer name (whether a printer init file or a raw Windows printer name) in the DEVICE = AUXLOC: statement. For example:

DEVICE = AUXLOC:\\SERVER\SHARE NAME+PASSTHROUGH

DEVICE = AUXLOC:HP Laserjet Series 37+PASS

Previously all three of the above would have been interpreted as printer names (e.g. INVOIC+GDI, etc.) and would have therefore failed to find a match. Now, the +G{DI} or +P{ASSTHROUGH} will be recognized (in order to specify the associated mode) and not treated as part of the printer name.

Notes

· Prior versions of A-Shell on the server side were limiting the total length of the printer name (+ optional mode) specification to 32 bytes.

· The mode may be specified with a few as 2 characters (e.g. +G or +P). (The downside of this is that those pairs of characters cannot appear within the printer name itself.)

· When printing to a printer by its raw Windows printer name or share name (i.e. not via a printer init file), the default mode is GDI, so there is no particular need to specify +GDI in that case.

· When printing to a printer via a printer init file, the printer init file will override any mode specified in the DEVICE=AUXLOC: statement. (Even if the printer init file has no PASSTHROUGH statement, that is equivalent to PASSTHROUGH=ON).


DEVICE = PROMPT:

Updated March 2013; see History

The second special pseudo-device is PROMPT: and applies only to A-Shell/Windows. Instead of specifying the printer device, it causes a standard Windows printer-selection dialog to be invoked, allowing the user to select any available Windows printer. Again, note the trailing colon.

The PROMPT: device should only be used with PASSTHROUGH=OFF, since it cannot be guaranteed that all printer drivers support PASSTHROUGH mode.

When using the PROMPT: device, many of the other parameters within the printer initialization file may be overridden by the selection of the printer in the dialog.

A print request sent to a printer named PROMPT, will, if no printer init file is found, be treated as if DEVICE=PROMPT: and PASSTHROUGH=OFF. (This makes "PROMPT" a very useful default spooler name under A-Shell/Windows.)

The printer selection dialog triggered by DEVICE=PROMPT: must be executed in a client A-Shell/Windows context. If it occurs in the context of an ATE connection to an A-Shell/Windows server (using ATSD), it will be automatically re-interpreted as DEVICE=AUXLOC:PROMPT: so that it gets forwarded to the ATE client where the printer selection dialog can be displayed. This however, defeats the effect of most other printer init commands in the printer init file on the server, overriding them with options set in the ATE client Connection Properties > Printer dialog. To force the other options in the original (server-side) printer init file to be processed on the client side, replace the DEVICE=PROMPT: in the server-side printer init file with an explicit DEVICE=AUXLOC:printername where printername is the name of a printer init file installed on the ATE client. (i.e. SYS:printername.INI or ASHCFG:printername.PQI). That printer init file should be a copy of the original printer init file on the server, with only the DEVICE statement changed to DEVICE=PROMPT: .

Beginning with A-Shell 6.1.1342 of March 2013, the Windows default printer may be specified with the DEVICE statement:

DEVICE=PROMPT(DEFAULT)

This is identical to PROMPT:, except that it ignores the last used printer and instead defaults to the system default printer. This is useful in places where printers come and go, and defaulting to the last used printer can cause confusion or worse when the last used printer is no longer present.

Warnings

The printername can be PROMPT, but if so, be careful not to include the trailing colon in the DEVICE=AUXLOC:PROMPT statement. While both PROMPT and PROMPT: will result in the printer selection dialog being displayed, PROMPT: (with a trailing colon) is a pseudo-device which does not have an associated printer init file, while PROMPT (without the colon) is a logical printer name that can be associated with a printer init file (which was the whole point of the exercise just described above).

Although it is possible for the server-side and client-side printer init files to have the same name, this is probably not a good idea. For one reason, you may confuse the two files when transferring them. And for another, if the server and client happen to share the same DSK0: (either because they are the same physical machine, or share a network drive on a LAN), then it would be impossible for the two variations using the same name to coexist.

History

2013 March, A-Shell 6.1.1342: Add support for Windows default printer with DEVICE=PROMPT(DEFAULT.

2008 September, A-Shell 5.1.1124: When attempting to print to the PROMPT: device in a non-local Windows, the DEVICE is automatically changed to DEVICE=AUXLOC:PROMPT: to forward to the PC client. This should eliminate a number of tech support issues that relate to attempting to print to the PROMPT: device on an ATSD server. It may also eliminate at least one cause of a file being left in-use after a failed attempt at printing.


DEVICE = DISK:

The third special pseudo-device is DISK:, which as its name implies, leaves the file on disk, and it works under both A-Shell/Windows and A-Shell/UNIX. There are two variations of this device as shown here:

DEVICE = DISK:

DEVICE = DISK:g:\vm\miame\dsk0\301222

DEVICE = DISK:%ATECACHEDIR%

In the first example, the file is simply left in place rather than being sent to the spooler. In the second example, the print file is moved to the specified directory. (It must be an existing directory in the native host directory format.) In the third case, the file would be copied to the the ATE Cache directory rather than printed.

Case is not significant for Windows, but is for UNIX.

Beginning with A-Shell 1152 of June 2009: when printing to the DISK: pseudo-printer (including via ATEAPX.SBX), the target directory will now be created if necessary. Note, however, that the parent directory must exist


DUPLEX

Updated September 2011

DUPLEX = <option>

(Windows only, but see final paragraph below) This function enhances duplex printing. Option may be H{orizontal} or S{hort} for short edge binding, or V{ertical} or L{ong} for long edge binding. Anything else disables duplex printing.

DUPLEX is one of the printer init file commands that has a GDI Printing Directive Equivalent.

Note that although DUPLEX is only supported directly by A-Shell under Windows, you can effectively support a duplex option in Linux by creating multiple versions of your printer init command which include the required lpr command line options in the DEVICE statement.


FONT

FONT = <font name>

Example: FONT = Courier New

(Windows only, PASSTHROUGH must be off.) This command applies only to laser or graphics printers under Windows, and is used to specify the font face name in which output is to be printed. The default is for a fixed-pitch OEM-character-set font suitable for the printer. Note that Windows font selection is a "best match" affair, meaning that if the "perfect" font does not exist for your request, the closest available approximation will be selected instead. But this may not always be that close to what you wanted.

Note that you can change fonts in mid-report using embedded Print Directive List.


FONTHEIGHT, FONTWIDTH

FONTHEIGHT = <# points>

FONTWIDTH = <# device units>

(Windows only, PASSTHROUGH must be off.) These two commands allow you to specify the height and width of the font to be used. They apply to Windows graphics printers only, and are largely superseded by the newer PITCH=AUTO and CPP commands, which are much easier to use in most cases. The FONTHEIGHT units are points (1/72") but do not include the vertical leading (between line spacing), and only integers are allowed. FONTWIDTH, on the other hand, is expressed in "device logical units" which are somewhat difficult to fathom, and may be relative to the font and device. The FONTHEIGHT and FONTWIDTH are not always independently selectable. Thus, some trial and error may be required. As an example, on most modern HP LaserJet printers with a built-in scalable Courier font, you can get a font suitable for 132 column 6 lines-per-inch printing with the following:

PASSTHROUGH = OFF

FONT = Courier New

FONTHEIGHT = 12

FONTWIDTH = 18

Notes

You can change fonts in mid report using the embedded Print Directive List.

See the PITCH=AUTO command for a much simpler way to select a font size.

FONTWIDTH and FONTHEIGHT override and thus effectively disable the PITCH command, so use only one method of selecting a font size or the other (preferably PITCH) within a single printer init file.


FORMFEED

FORMFEED = <Boolean>

Form feeds after each print job may be either enabled (ON) or disabled (OFF) after each print job. This command is identical to its AMOS equivalent. The default is ON, though this may be overridden by the correct switch to SPOOL.SBR.

Note that under Windows printers and UNIX/Linux, it can be tricky to avoid a form feed at the end of a printout. This is because both operating systems, in contrast to AMOS, tend to think of a spool requests as wholly autonomous, and thus it seems to make little sense to allow a report to just end in the middle of a page, since there is no way of knowing what the next report will expect. Under Windows, you may need to use PASSTHROUGH=ON to get FORMFEED=OFF to work. Under UNIX, you can usually apply a filter to solve the problem. Refer to your operating system documentation for more information on printer setup and filters.

The AUTOFF option (UNIX/Linux only) provides a nearly foolproof way of dealing with optional trailing form feeds.


HEADER

HEADER = <Boolean>

(UNIX/Linux only) HEADER may invoke a printed header at the top of the first page or all pages. Like BANNER, its actual implementation is up to the spooler, and may require that additional switches be passed after the printer device name (see DEVICE above.) The default is OFF.


LMARGIN , TMARGIN

LMARGIN = <# columns>

TMARGIN = <# lines>

(Windows only; PASSTHROUGH must be off.) These commands define the left margin in characters and the top margin in lines. The actual physical size of the margin will therefore depend on the selected font pitch and line spacing. Note that the margins count towards the number of lines or columns per page. For example, if the LPP value is 66 but the TMARGIN value is 10, there will only be 56 printed lines per page.


LPP

LPP = <# lines per page>

Example: LPP = 62

(Windows only, PASSTHROUGH must be off.) The LPP command defines the number of lines to be printed on each page, and interacts with the PITCH setting. When LPP is specified and PITCH is not set to AUTO, the vertical line spacing (but not font size) is adjusted to squeeze that many lines onto the page. However, when PITCH=AUTO, the LPP value (defaulting to 66 if not specified) determines the height of the font selected. If LPP is omitted and PITCH is not AUTO, LPP will be computed based on the font and page size. Also note that the top margin (TMARGIN) will be included in the LPP value, so if LPP=66 and TMARGIN=4, then there will be only 62 printable lines per page.


NOABORTDLG

NOABORTDLG = <boolean>

By default, when A-Shell is printing, it displays a typical Windows printing abort dialog, which allows the user to abort the printing operation before it completes. Although this is typical Windows practice, the abort dialog could be inappropriate for a couple of reasons. One is that all but the largest printouts are generated so quickly that the abort dialog is an annoying flash that appears and disappears before the user has a chance to even see what it said. The other is that you might not want to make it so easy for the user to accidentally abort a printout. Whatever the motivation, you can eliminate the dialog by specifying the NOABORTDLG = TRUE option.


ORIENTATION

Updated December 2011; see History

ORIENTATION = LANDSCAPE

(Windows only, PASSTHROUGH must be off.) The page orientation (portrait or landscape) may be specified for Windows laser or graphics printers. The default is PORTRAIT.

The ORIENTATION statement overrides both the current printer default setting and any setting made by the user in the interactive printer selection/configuration dialog. It can only be overridden programmatically (by LANDSCAPE and NOLANDSCAPE switches in XCALL SPOOL. If you want to allow the user to have control over the orientation, omit the statement from the printer init file and don't specify either of the related switches in the spool request.

Note that paper orientation must be set at the time the printer context is initialized, so it cannot be set within the print file itself.

Also note, however, as explained in the Defining Spoolers topic, that printer init files are processed at the time reports are sent to the printer. This means that you can switch between landscape and portrait printing on a given printer, but you must have that printer identified twice to A-Shell: once as a portrait printer, once as a landscape printer. So when printing a landscape-oriented report, you would send the report to the printer called, for example, "HPland." When producing and printing portrait-oriented reports, they would be sent to the "HPport" printer. "HPland" and "HPport" are, of course, the same printer, which have only different (a) printer init file names, and (b) ORIENTATION = lines.

History

2011 December, A-Shell 6.0.1241: Windows printing refinement: The orientation in the printer dialog is now initialized based on the specification in the printer init file or passed in the print request, rather than from the current printer settings. For related details and further explanation, see the A-Shell forum discussion PROMPT: Printer Preferences not taking place.


OVERLAY

OVERLAY = <amos filespec>

Example: OVERLAY = ASHCFG:INVOIC.OVL

(Windows only, PASSHTHROUGH must be off.) If specified, the corresponding file is printed at the start of every page. The overlay file must be limited to a single page (with no form feed characters.) Typically, overlay files consist of GDI print commands (see Print Directive List) to create the background of a form, or perhaps letterhead. This is logically equivalent to you including the same text at the start of every page of your report, but obviously, this way is much cleaner and simpler. Note that if you want to reset the printer "cursor" to the top of the page after processing the overlay, you can append a //MOVETO,0,0 command to the end of the overlay file.

The filespec specified with the command assumes a default file extension of ".OVL."

When converting from a pre-printed form printed in PASSTHROUGH mode to a laser generated form using OVERLAY, you’ll probably need to use PITCH=AUTO and CPP=80,132 to simulate the original printer font, and you may want to use the XORIGIN and YORIGEN commands to make up for the loss of ability to move the paper in the printer.

See Also

• The forum dicussion "Generating forms on demand" for more information on strategies for replacing pre-printed forms.


PAPERLENGTH, PAPERWIDTH

The printer init commands PAPERLENGTH and PAPERWIDTH allow you define custom paper sizes, if the driver supports it (which is a big IF!). See related topics PAPERSIZE and Custom Paper Sizes.

PAPERLENGTH = ###

PAPERWIDTH = ###

where ### are tenths of millimeters. Unfortunately, support for this feature varies widely among printer drivers. Some drivers do not support it at all. Others may support it only if you first set the driver default properties to "Custom" or "User defined" page size (which pretty much undermines the value of being able to set it from the software). In other cases, the feature is only supported in the latest version of the printer driver from the manufacturer. (This is a good general rule: whenever there is a problem with a printer, start by downloading the latest driver from the manufacturer website or the Windows update site.)

If you attempt to set the paper length and width, and the driver does not support it, A-Shell will first try to set the paper to the PAPERSIZE value specified in your printer init or print file. (If you didn't specify one, then it will try PAPERSIZE=0.) If after that change, the driver still does not indicate support for individual page length and width, it will try again with PAPERSIZE=CUSTOM (aka 256). Finally if that doesn't work, it will log a trace message (regardless of the TRACE settings) which looks something like:

Custom paper width/length not supported by printer driver!

If you SET TRACE LP ON, you'll get more detailed trace messages showing the individual steps in the process.

For printer drivers that don't support PAPERLENGTH and PAPERWIDTH settings in all modes, the most common workaround is to first set the printer to its "custom" paper size, which may then allow the application to override it with a different custom size. This is why A-Shell tries PAPERSIZE=256 (CUSTOM) automatically.

HOWEVER, some drivers may indicate support for PAPERLENGTH and PAPERWIDTH, but in reality it only works when the printer is first set to CUSTOM. This problem can be detected in the LP TRACE as follows:

DEVMODE Device:Brother HL-5250DN, Ver:793, Size:156, Extra:2360, ...

Requesting paperwidth override to 150.0 mm (5.9 in)

Requesting paperlength override to 140.0 mm (5.5 in)

Updated page size: 5100 x 6600 pixels

...

Final page size: 5100 x 6600 pixels (600 x 600 dpi); print area: 150,100,4950,6500

The clue here is that there was no attempt to set the paper size prior to requesting the paperwidth override, combined with the fact that the updated page size (5100 x 6600 pixels at 600 x 600 dpi, or 8.5 x 11 inches) doesn't match the requested size.

In such a case, you should try adding PAPERSIZE=CUSTOM to the printer init file to see if that resolves the problem, which in the case of this printer, does, as shown in this trace:

DEVMODE Device:Brother HL-5250DN, Ver:793, Size:156, Extra:2360, bin=1, duplex=1, paper=1, orient=1, copies=1, dmFields=0x1ff1f

Requesting papersize #256

Requesting paperwidth override to 150.0 mm (5.9 in)

Requesting paperlength override to 140.0 mm (5.5 in)

Updated page size: 3532 x 3300 pixels

For more details and tips, see this case study of working with custom paper sizes on our forum.

Note that unlike PAPERSIZE, PAPERLENGTH and PAPERWIDTH have no corresponding //GDI commands (primarily because the support for them seems to vary so much between printer drivers that the benefits of a non-printer-specific GDI command seem negligible, at least at the moment.


PAPERSIZE

Updated March 2011

PAPERSIZE = <size>

where <size> can be any of the following standard size names, listed here alphabetically:

10X11 | A6 | ENV_C3 | JENV_KAKU3 | PENV_10_ROTATED
10X14 | A6_ROTATED | ENV_C4 | JENV_KAKU3_ROTATED | PENV_2
11X17 | B_PLUS | ENV_C5 | JENV_YOU4 | PENV_2_ROTATED
12X11 | B4 | ENV_C65 | JENV_YOU4_ROTATED | PENV_3
15X11 | B4_JIS_ROATED | ENV_DL | LEDGER | PENV_3_ROTATED
9X11 | B5 | ENV_INVITE | LEGAL | PENV_4
A_PLUS | B5_EXTRA | ENV_ITALY | LEGAL | PENV_4_ROTATED
A2 | B5_JIS_ROTATED | ENV_MONARCH | LEGAL_EXTRA | PENV_5
A3 | B5_TRANSVERSE | ENV_PERSONAL | LETTER | PENV_5_ROTATED
A3_EXTRA | B6_JIS | ESHEET | LETTER_EXTRA | PENV_6
A3_EXTRA_TRANSVERSE | B6_JIS_ROTATED | EXECUTIVE | see Won't Fit 4 | PENV_6_ROTATED
A3_ROTATED | CSHEET | FANFOLD_LGL_GERMAN | LETTER_PLUS | PENV_7
A3_TRANVERSE | see Won't Fit 1 | FANFOLD_STD_GERMAN | LETTER_ROTATED | PENV_7_ROTATED
A4 | see Won't Fit 2 | FANFOLD_US | LETTER_TRANVERSE | PENV_8
A4_EXTRA | DSHEET | FOLIO | NOTE | PENV_8_ROTATED
A4_PLUS | ENV_10 | ISO_B4 | P16K | PENV_9
A4_ROTATED | ENV_11 | JAPANESE_POSTCARD | P16K_ROTATED | PENV_9_ROTATED
A4_TRANSVERSE | ENV_12 | see Won't Fit 3 | P32K | QUARTO
A4SMALL | ENV_14 | JENV_CHOU3 | P32K_ROTATED | RESERVED_48
A5 | ENV_9 | JENV_CHOU4 | P32KBIG | RESERVED_49
A5_EXTRA | ENV_B4 | JENV_CHOU4_ROTATED | PENV_1 | STATEMENT
A5_ROTATED | ENV_B5 | JENV_KAKU2 | PENV_1_ROTATED | TABLOID
A5_TRANSVERSE | ENV_B6 | JENV_KAKU2_ROTATED | PENV_10 | TABLOID_EXTRA

"Won't Fit" notes in table: 1 = DBL_JAPANESE_POSTCARD; 2 = DBL_JAPANESE_POSTCARD_ROTATED; 3 = JAPANESE_POSTCARD_ROTATED; 4 = LETTER_EXTRA_TRANSVERSE

If that list is too limiting, you can also specify the numeric code corresponding to the paper size. You can retrieve the list of supported paper sizes in symbolic and numeric format by printing with the LP trace turned on. See the Tracing note, below. Also see Custom Paper Sizes.

PAPERSIZE acts as a kind of alternative to the BIN command, in that A-Shell passes the request to the printer with the hopes that the printer will select the bin which contains the requested size. Most printers claim to support this capability, although the degree of support is questionable, and it may require that you first activate the feature through the printer's control panel or properties dialog. Similarly, it is almost always necessary for you to inform the printer of the size of paper you have in each bin (although perhaps there are some higher-end printers which have bins containing sensors to auto- detect the size.

As with the BIN command, the printer may indicate "support" for more bins (and more paper sizes) than are actually "available", and A-Shell doesn't do much enforcement.

So the main effect of specifying PAPERSIZE in the printer init file is to force A-Shell to use that paper size to base any size-dependent calculations affecting the format or spacing of the output (as will APEX).

PAPERSIZE is one of the printer init file commands that has a GDI Printing Directive Equivalent.

Subtopics

Custom Paper Sizes


Custom Paper Sizes

Added March 2011

Beginning with A-Shell 1209 of March 2011, it is possible to select a custom paper size by its name, rather than just its number, assuming that the paper shows up in the trace list of available paper sizes. This saves the step of running a test print with TRACE LP to see what number the custom paper was assigned, and also provides a degree of printer independence, since it isn't clear that the same number would be assigned to the custom paper by each printer.

Warning: custom paper sizes is an area in which there is considerable variation between printer drivers. In some cases the driver properties dialog will allow you to define a custom paper size. In others, you may need to use the common Devices and Printers > Print Server Properties dialog to define a custom "form" (which may, or may not show up in the list of available paper sizes for a particular printer. But if it does show up, then you should be able to select it via PAPERSIZE=<name>.

For more and related information, see PAPERLENGTH, PAPERWIDTH and this discussion on the A-Shell forum.

History

2011 March, A-Shell 5.11209: Added capability to A-Shell


PASSTHROUGH

PASSTHROUGH = <Boolean>

(Windows only) This command applies only to A-Shell/Windows, and has valid values of ON or OFF (or YES/NO, TRUE/FALSE, etc.) with a default of ON. The terminology is somewhat confusing, so it may be better to think of the two options as follows:

• "GDI Mode" (PASSTHROUGH=OFF)

• "RAW Mode" (PASSTHROUGH=ON) (default)

Windows applications normally use "GDI Mode", meaning they print via the Windows Graphic Device Interface (GDI), which in turn routes text and logical commands through the printer driver to produce text and graphic output on the printer device. GDI mode has several advantages:

• Device Independence – the GDI presents a single, reasonably consistent virtual printer interface to the application, while the printer drivers supplied by the printer manufacturers takes care of the problem of making the printer act accordingly. (The ideal of device independence is limited, however, in the real world, by the differing capabilities of physical printers. But as long as we are dealing with laser or ink jet devices, i.e. "raster" printers that can address individual pixels, and we don’t get too exotic, we can expect reasonable uniformity.)

• Easy font selection using the Windows font mapper and font rendering facilities, without having to worry about which fonts are internal to the printer.

• Automatic font sizing via the PITCH=AUTO and CPP / LPP options in the printer initialization file.

• Easy methods of producing graphic output (lines, rectangles, circles, images) using a set of high level, human readable text commands.

• Ability to select arbitrary colors using the RGB system.

• GDI printing is the only way you can print to the new breed of low cost "Windows only" printers (which includes most inexpensive ink jet printers.)

The following printer initialization commands are limited to GDI mode only: FONT, WEIGHT, CHARSET, CPP, LPP, FONTHEIGHT, FONTWIDTH, PITCH, TMARGIN, LMARGIN, and ORIENTATION (and possibly others.)

Therefore, GDI mode (PASSTHROUGH=OFF) would in most cases be the preferred approach. However, this method is substantially different in style from the way "normal" AMOS applications print, which is much closer to RAW mode. Most importantly, GDI mode does not support the use of embedded escape sequences within the print file to set printer features (such as condensed print), which is common in applications being ported from AMOS. (This is the main reason why RAW mode, i.e. PASSTHROUGH=ON, is the default.) Another factor in the decision to make RAW mode be the default is that the vast majority of AMOS reports are "plain text", and a fair percentage of them are specifically intended for dot matrix printers with tractors (often with pre-printed forms.) For these kinds of print applications, most of the features of GDI mode are not only irrelevant, but they can get in the way. (And, RAW mode is certainly faster and more efficient, since it eliminates the need to "render" or "rasterize" the text, and greatly reduces the amount of data that must be sent down the wire to the printer. However, with the speed of modern PC’s, this may not be much of an issue any more.)

As you might suspect, RAW mode printing (PASSTHROUGH=ON) is not very common in the Windows world. In fact, most printer drivers don’t even support it (and as mentioned above, neither can many physical printers, regardless of the driver.) Fortunately, there is a generic driver present on virtually all versions of Windows from W95 and up, which does support PASSTHROUGH printing (provided the printer hardware supports it.) It is listed under the manufacturer name "Generic" and model name "Text Only". You should use this driver whenever using RAW (PASSTHROUGH=ON) mode printing.

PASSTHROUGH (raw mode) is required in the following cases:

• Whenever the print file contains ESC codes into the printfile to access features of a specific printer (such as condensed print)

• For all PCL reports containing PCL or Postscript commands

Notes

When using PASSTHROUGH=ON, it is sometimes necessary to set the "spool format" for "RAW" (instead of the default, "EMF".). To accomplish this, click the Start button, then Settings, then Printers, and then right click on the printer icon(s) you are using with A-Shell. Click Properties, click on the Details tab, and then the Spool Settings button. Finally, change the Spool Data Format to RAW. For network printing, it may be necessary to do this for both the local and remote printers. The symptom of not doing this when it is needed is that when you print, you may hear the printer "hiccup" but nothing comes out.

Although one generally settles on either PASSTHROUGH=ON or PASSTHROUGH=OFF for a particular printer, it is possible to override the PASSTHROUGH setting established in the printer initialization file. One way is to use the PASSTHROUGH and NOPASSTHROUGH flags in the SWITCHES parameter to XCALL SPOOL|document=2zconref\3xcall.docx;bookmark=SWITCHESINEZSPL or to use the /PASSTHROUGH or /NOPASSTHROUGH switch with PRINT.LIT. Another is to embed the command in the print file itself, since PASSTHROUGH is one of the printer init file commands that has a GDI Printing Directive Equivalent.

You can use both PASSTHROUGH (RAW) and non-PASSTHROUGH (GDI) modes on a single printer (provided the printer hardware supports RAW mode) but not within the same print file. Also, you would probably want to create two Windows driver configurations in this case, one using the Generic / Text Only driver for the RAW mode, and one using the specific driver for that printer model for the GDI mode.


PITCH

(Windows only) This command may be used as an alternative to FONTWIDTH and FONTHEIGHT to control the way A-Shell selects a suitable font size for the report. There are two variations:

PITCH = ##

PITCH = AUTO

The first form is equivalent to FONTHEIGHT=##, but is largely superseded by the much more convenient second form, which auto-selects a suitable font size based on the printable area of the current paper in the printer as reported by the driver, the width of the longest line of the report, and the CPP and LPP values.

Comments

PITCH is compatible with the FONT command (which only specifies a font face, not a size), but it is generally preferable to omit the FONT command and let Windows and the printer driver select the most suitable font face. It is not compatible with FONTWIDTH and FONTHEIGHT, both of which override and effectively disable PITCH.

History

2004 August, A-Shell 4.5.776: A-Shell now ignores trailing blanks in the length of the first 15 print lines used to determine if we needed to switch to the condensed font. Previously, they were not ignored.


PREFIX, SUFFIX

PREFIX = <amos filespec (default PFX extension)>

SUFFIX = <amos filespec (default SFX extension)>

Example: PREFIX = SYS:JET.PFX

If either PREFIX or SUFFIX or both are specified, the corresponding file is sandwiched as a prefix or suffix to the main file to be spooled, and the resulting sandwich is passed to the printer as if it were one file. (This prevents the possibility of another printer job slipping in between the prefix and main file if they were spooled as separate reports.) These optional commands provide a lot of flexibility in maintaining different logical versions of the same physical printer. Also note that the PREFIX and SUFFIX arguments on SPOOL.SBR override these parameters in the printer INI file. PREFIX and SUFFIX apply to both Windows and UNIX.

Under UNIX, several printing options, including PREFIX and SUFFIX, involve the creation of temporary files. By default, these are stored in the same directory as miame.ini (which must therefore have write privileges for all users.) To put these files in another location (perhaps in a directory mapped to a PPN, create an environment variable ASHTMP and set it to the desired path (e.g. ASHTMP=/vm/miame/dsk0/001002)


PREVIEW

PREVIEW = <Boolean>

This option forces the SSW_PREVIEW flag (524288 or &h80000) to be set in the switches, provided that the SSW_NOPREVIEW flag (1048576 or &h100000) has not already been set. This is equivalent to passing the /PREVIEW switch to PRINT.LIT, or setting the SSW_PREVIEW bit in the switches parameter to XCALL SPOOL.


PRTCOPIES

Updated March 2011

PRTCOPIES = <Boolean>

This switch affects the way multiple copies are printed. When the switch is OFF, A-Shell passes the copies request to the spooler and lets it generate the copies. When ON, A-Shell itself generates the copies, either submitting the print request multiple times (under UNIX) or just concatenating the copies into one combined document (Windows and aux port printing). The default is OFF for UNIX and whenever outputting to the AUXLOC: device; the default is ON for local Windows printing.

The OPTIONS=PRTCOPIES switch in the miame.ini will override
the PRTCOPIES=OFF option in the print init file (i.e. force it ON), except when
DEVICE=AUXLOC:. So if you want the ability to control this on a
printer-by-printer basis, do not include OPTIONS=PRTCOPIES in the miame.ini.

The motivation for setting PRTCOPIES=ON would primarily be to avoid some kind of problem with the way that the print spooler or driver handles requests for multiple copies. Note, however, that in the case of auxiliary port printing (see DEVICE = AUXLOC:), having the server side generate the copies (i.e. sending the print file multiple times over the aux port channel) has some potential downsides:

• the data has to be sentover the wire, potentially taking longer and/or using more shared bandwidth.

• it may confuse the user into requesting multiple copies in the local printer dialog, thus ending up with copies on top of copies.

This is why PRTCOPIES defaults to OFF whenever DEVICE=AUXLOC:. But, in order for the remote client PC to be able to generate the copies on its end, we need a way to communicate the copies request to it. Since no such feature is included in the standard auxiliary port implementation of terminals and terminal emulators, A-Shell can only support PRTCOPIES=OFF on the server side of auxiliary port printing if the client is ATE and both the server and client versions of A-Shell/ATE are 5.1.1208 or greater. If any of those conditions is not met, the server side will revert to PRTCOPIES=TRUE and send the print file over the aux port channel multiple times. If the conditions are met, then the server will add the copies parameter to the AG_SPOOLCFG command that it sends to ATE prior to sending the data over the aux channel.

History

2011 March, A-Shell 5.1.1208: PRTCOPIES now supported in conjunction with aux port printing. Previously the entire print file was always sent multiple times to effect the multiple copies, since there was no way to tell the client to generate the copies. See discussion of DEVICE = AUXLOC: above for more details.

2011 March, A-Shell 5.1.1208; "Tracing": The OPR:SPOOL.LOG (UNIX) or ashlog.log (if Windows or the LP TRACE activated) now gives two values for copies (e.g. C=1/2), where the first number (1 in this case) indicates the number of copies processed locally by A-Shell, and the second number (2) indicates the number of copies requested to be generated by the remote agent (whether the spooler or a terminal emulator client). The LP TRACE also indicates the version edit number of the ATE client, if applicable (e.g. "edit=1208"). Together these may help debug issues relating to how copies are handled (particularly after the copies-handling enhancement described above).

2010 July, A-Shell 5.1.1187: PRTCOPIES statement in the printer init file now supported under A-Shell/Windows. Previously the init file setting, if any, was ignored, and the effective setting was set to OFF if the printer selection dialog was used; otherwise ON. .


STRIPFF

STRIPFF = <Boolean>

This option was added to deal with a peculiar artifact of many AMOS reports: a form feed at the beginning of the print file. Under AMOS, the spooler had a feature to ignore such a leading form feed character if the last character received, at the end of the previous print request, was also a form feed. This apparently helped deal with a situation in which some reports may have ended in mid-page, without advancing to the top of form. This concept, however, is unheard of in the world of Windows and UNIX/Linux (where the underlying printing philosophy is that each print job should stand entirely on its own, and not be affected or influenced by previous print jobs.) So, to avoid getting an extra blank page at the start of reports that have such a leading form feed character, you can either adjust your program to remove the extra form feed, or add STRIPFF=ON to your printer initialization file.


WEIGHT

WEIGHT = <weight value (0 – 900)

(Windows only) This optional command applies to Windows printers only and affects the weight (boldness) of the font that is selected. The range of possible values runs from 0 (don’t care) to 900 (heavy) in increments of 100. The default is 400 (normal.) Note that, like CHARSET, not all possibilities may be supported; the information is merely a suggestion to the font selector which may or not be able to give you exactly what you are asking for.


XOFFSET, YOFFSET

Added May 2008

XOFFSET = ###

YOFFSET = ###

XOFFSET and YOFFSET are among the printer init file commands that have a GDI Printing Directive Equivalent and to which, except for syntax, they are identical. See the GDI commands XOFFSET, YOFFSET for more information.


XORIGIN, YORIGIN

Updated May 2008

XORIGIN=###

YORIGIN=###

XORIGIN and YORIGIN are among the printer init file commands that have a GDI Printing Directive Equivalent and to which, except for syntax, they are identical. See the GDI commands XORIGIN, YORIGIN for more information.


Troubleshooting Techniques

When debugging printer problems, including those relating to problems in your printer init files, there are two general-purpose troubleshooting techniques that you should familiarize yourself with.

Tracing

This technique applies under all A-Shell environments, and consists of activating "line printer trace mode". You can do this from the A-Shell command prompt (aka "dot prompt") as follows:

.SET TRACE LP ON

Or, you can activate it in the miame.ini file by adding a line containing "TRACE=LP" anywhere after the first line of the file (typically near the bottom.)

When line printer tracing is active, each time you print something, you will see a bunch of debugging information displayed on your screen which, hopefully, may help you identify the problem. Note that since most such problems are not specific to the particular print file, you would typically just use the PRINT.LIT command to print a sample file. A good sample file to print is the printer INI file itself, e.g.:

.PRINT LASER1=ASHCFG:LASER1.PQI

After resolving the problem, you can turn line printer tracing off with:

.SET TRACE LP OFF

There are several other trace options. See the information for TRACE or for SET.LIT. Or just type: SET TRACE from the dot prompt to get a list of the status of the currently available tracing options.

SPOOL.LOG

The second general-purpose printer troubleshooting technique applies only to UNIX and consists of a file OPR:SPOOL.LOG which logs information about every print request. Along with the time, date, and various information identifying the user, file, program, etc., it contains the actual UNIX print request command and any response (error message or acknowledgement) returned by the command. This often makes simple errors (like "destination unknown") as well as much more subtle ones, which might otherwise take hours of debugging, immediately obvious.


Supported Printer Interfaces

A-Shell supports both of the "normal" printing interfaces: XCALL SPOOL (or EZSPL) and PRINT.LIT (or EZPRT.LIT). The former is used by applications, while the latter may be used in CMD/DO files or typed interactively at the A-Shell command prompt. A-Shell also contains an implementation of the EZSPL spooler enhancement package, described in the following section.


EZSPL

EZSPL ("EZ-SPOOL"), originally developed by MicroSabio as a front-end to the AMOS spooler, provides some printing-related convenience features such as printer selection menus and file preview. The A-Shell version of EZSPL is quite similar to the AMOS version, but with some limitations and some extensions. Perhaps most importantly for those not interested in these features, they remain silent and hidden unless you go out of your way to activate them. Such people may safely ignore EZSPL. For those that are interested, this section briefly describes how EZSPL is configured under A-Shell.

EZSPL (EZSPL.SBR) is hooked into the front end of the spooler interface by substituting for SPOOL.SBR. Under A-Shell, this is accomplished through the subroutine ALIAS facility within the miame.ini file. In fact, A-Shell does not contain an ordinary SPOOL.SBR, so you have to use the EZSPL version. However, as mentioned above, the EZSPL version acts just like the ordinary one unless you create the necessary configuration files.

Subtopics

EZSPL Config File

EZSPL Commands


EZSPL Config File

The first thing EZSPL.SBR (SPOOL.SBR) does upon being called is it looks for configuration files. The A-Shell version of the configuration file search path is much more abbreviated than the AMOS version, consisting only of the following:

EZ:<printfilename>.SFL

EZ:<programname>.SPG

EZ:<printername>.SPR

EZ:<termname>.SPL

MEM:SYSTEM.SPL

SYSTEM.SPL[p,pn]

SYSTEM.SPL[p,0]

EZ:SYSTEM.SPL

If none of these are found, then printing proceeds as if EZSPL did not exist. Otherwise, it opens the first file it finds and process the parameters contained within.

Each of the statements in the config file must be in all upper case, with no spaces, except within a description field (e.g. "MENU = ON" and "menu = On" are invalid). Standard rules apply for Boolean Arguments in INI Files.

Individual sections may also be added to the configuration file according to user name.

User name is determined by the native operating system logon procedure, and can be seen in the SYSTAT display or retrieved with GETUSN.SBR. It is not case sensitive in this context.

EZSPL Sample Config File

MENU=OFF

TYPE=OFF

ASKPRT=OFF

PRTSPL=PDFX,PDF Printer

[jack]

MENU=ON

TYPE=ON

ASKPRT=ON

DEFAULT=JET2

PRTSPL=JET2,Jack's Jet Printer

[always]

PRTSPL=JET1,Common Jet Printer

PRTSPL=DRAFT,Oki draft

[default]

DEFAULT=JET1

In the above case, the first four lines are always processed. They could have been preceded with another [always] header, or combined with the other [always] section. The five lines under [jack] are only processed if the user is jack, in which case the boolean options would override the previously set ones, the DEFAULT printer would only apply if no printer had been previously specified (by the application or in the miame.ini), and the PRTSPL line defining the JET2 printer would be added to the previous set of printers (currently containing only PDFX). The [always] section always gets processed. The [default] section would only be processed for users other than jack.

This capability of adding sections for individual users allows a great deal of flexibility for large systems.


EZSPL Commands

See EZSPL.SBR for a list of the EZSPL configuration file commands.


EXTOPT

Argument is a sum of zero or more of the following flags values:

Flag | Description
&h0004 | Disable screen save/restore
&h0020 | Allow exit from EZVUE with LeftArrow
&h0040 | Allow exit from EZVUE with Tab
&h0080 | Allow exit from EZVUE with F1-F16
&h0100 | Don’t ask questions on PRINT command from within file viewer. (This is mainly useful in conjunction with the SBR=EZPRTX option in the miame.ini file, which causes EZVUE to XCALL EZPRTX instead of XCALL SPOOL when printing from the viewer. Since you can customize EZPRTX.SBX, you may not want EZVUE to ask about starting and ending pages, or even about the printer choices.
&h0200 | Hitting the HOME key before any other cursor motion keys while in the file viewer will act like the print command. This is a bit obscure, but apparently there are some people who feel it is just the ticket.


SWITCHES

Added January 2008

The EZSPL configuration file command:

SWITCHES = {+/-}#####

allows you to add, remove, or replace the SWITCHES passed in the XCALL EZSPL, xcall SPOOL, or even XCALL EZTYP.

For example, SWITCHES = +&h80000 would force EZSPL (including EZTYP) to act as if the &h80000 (GUI PREVIEW) switch had been set by the caller, and thus would launch the new GUI Preview utility instead of the text preview.

The main value of this switch is that it allows you to force EZTYP to use the APEX preview utility, provided you are running under A-Shell/Windows.

(Please ignore the "a" on the end of SWITCHES. It is there only to resolve a naming conflict with another heading.)


Send File to Printer or Queue

The last step in the process of printing a file is the actual submission of the file to the operating system’s print service (according to the DEVICE or COMMAND parameters of the printer initialization file.) The details for this final operation are vastly different depending on the A-Shell platform; see the following discussions on A-Shell/Windows or A-Shell/UNIX.

For some tips and ideas about on printing PDFs under Linux, see this discussion on the A-Shell Forum.

Subtopics

A-Shell/Windows

A-Shell/UNIX


A-Shell/Windows

A-Shell/Windows relies on the Print Manager to handle the physical spooling operation. Immediately after it hands the file off to the Print Manager, you should be able to see the file in the Print Manager’s queue, and from that point forward, it can be manipulated exactly like any other Windows report.

The way in which the report file created by your application is handed off to the Print Manager depends on the PASSTHROUGH parameter in the spooler init file. With PASSTHROUGH=ON, the print file is sent in raw form, which is similar to the way traditional AMOS applications sent files to the spooler. This method, however, may not be supported by newer "Windows-only" printers. If PASSTHROUGH=OFF, A-Shell reprocesses your print file through the Windows GDI system, which is similar to the way 99% of typical Windows applications work. This method gains you more flexibility (via the FONT, PITCH, ORIENTATION, and MARGIN printer init file statements, as well as the ability to use A-Shell’s Print Directive List), but doesn’t allow you to embed ESC sequences into the print file. (Instead of, for example, using an ESC sequence to select 17 pitch, you would instead use the FONT or PITCH statements in the printer init file, or the SETFONT directive within the print file.

Notes

Support for PASSTHROUGH mode varies from printer to printer. If you have trouble getting printouts to work at all, try toggling the PASSTHROUGH option in your printer init file.

If PASSTHROUGH doesn’t work with your particular printer driver, you may want to try using the "Generic / Text Only" driver.

See Print Directive List for details on embedding GDI directives in your print files.

History

2009 May, A-Shell 5.1.1150: Whenever a printer is selected from the printer selection dialog, that printer becomes the default, for this user, for any subsequent A-Shell printer selection dialogs. Previously, the printer selection dialog always started at the global Windows default printer for this workstation. Besides being more convenient and intuitive for the user, this also means that any special configuration saved for the printer in the printer driver properties will be used as the default configuration (rather than the default printer's configuration).


A-Shell/UNIX

The various flavors of A-Shell/UNIX complete the spooling process by executing some form of UNIX system line printer command:

SCO OpenServer (-R = delete):

lp -dprinter {-R} {-onobanner} {-onofilebreak} {-ncopies} file

The –onobanner switch will be ignored by OpenServer (leading to annoying banner pages) unless you specifically enable it in the configuration screens (scoadmin) or via an lpadmin command line.

AIX2 (-nb0 = nobanner, -rm = delete):

print -printer {-nb0} {-rm}

AIX/3 thru AIX/5 (-r = delete, -Ban = banner, -Bnn - no banner):

enq -Pprinter {-Ban|Bnn} {-r} {-Ncopies}

Linux (-h = nobanner, -r = delete)

lpr -Pprinter {-#copies} {-h} {-r} file

Others (-h = nobanner, -r = delete)

lpr -Pprinter {-h} {-r} file

Notes

Normally A-Shell does not display the line printer command that it submits, but for troubleshooting purposes, you can force it to by setting TRACE=LP in the miame.ini file, or with SET TRACE LP ON from the dot prompt.

A log of all spooler requests is kept in the file OPR:SPOOL.LOG). This log gives information about the context of the print request (time, date, user, program, etc.), the actual command line executed, and any response received from the print subsystem. When the file reaches 3MB, it is renamed to SPOOL.00# (# ranges from 1 to 4, for 4 archive copies) and a new one started.

If your flavor of UNIX requires something different from the above, then you can use the COMMAND statement in the printer init file to specify an arbitrary command line.


Launching A-Shell

This section provides details on the command line options available for launching A-Shell and its related commands from the host operating system.

Command | Purpose
ASHELL | Launches the A-Shell environment—i.e., the dot prompt.
COMPIL | Launches the native host version of the ASB compiler.
PSHELL | (UNIX only) Launches PolyShell, which in turn can launch and manage multiple A-Shell sessions on a single workstation.
VUE | (UNIX only) Launches the native host version of the VUE editor.


ASHELL

UNIX

ashell {-switches}

Windows

ashw32.exe {-switches}

This command is used to enter the A-Shell environment, and responds with the default A-Shell prompt "." (period).

All Command Line Switches are optional, and all begin with "-" (hyphen) followed by the switch. If the switch takes a parameter, that follows the switch and a single space. For example:

ashell -min -j job99

In addition to the pre-defined switches, you may optionally append a standard command (e.g. MAIN.CMD) to the end of the command line, which would be automatically executed on entering A-Shell. This command may be any of the standard .LIT programs, or a .DO or .CMD command file, for example:

ashell run dsk0:menu[7,6]

or:

ashell menu

where menu could be any AMOS-format command file loaded into the path corresponding to DSK0:[2,2]. Note that the first format would only work if the user was pre-logged into an A-Shell mapped directory; otherwise the run command will fail due to not being logged in. Use of a command file (as in the second example) can eliminate this problem if the command file starts with a LOG command.

A-Shell remembers the previous command line that launched it, on a user-by-user basis. This means that if you launch it without any arguments, it will use same command line as it used last time it was launched. Also, if no previous command line known, and no command line passed, and no MIAME environment variable defined, it will default to looking for miame.ini in the path above the executable. Both of these are mainly intended to be useful in conjunction with auto-update routines, as well as possibly with ShellExecute and HOSTEX.

The A-Shell application can terminate the session by simply chaining to the program HOST.LIT, or by just returning to the A-Shell Command Prompt if the –e switch was specified on the startup command line.

Subtopics

Command Line Switches

Command Line File

Command Line File Option CLX

Virtual Command Files

Initial Window Settings

Launch Background Process on Boot

Update A-Shell While Running


Command Line Switches

Updated February 2016; see History

Below is a list of the A-Shell startup command switches, followed by extended descriptions where needed. Note that if A-Shell/Windows is launched with no command line arguments, and there is no Command Line File defined, it will repeat the command line from the previous launch.

Switch | Action | Switch | Action
b | Buffer Name: Change default name of screen snapshot buffer file | n | Suppress the A-Shell splash/license/welcome screen
ba | Buffer and Snapshot: Activate snapshots, append to specified file | nc | Removes the caption bar, creating a caption-less main window.
bc | Overwrite Buffer File if necessary, activate auto-snapshot mode | nm | No Menu: Hides the A-Shell menu bar
c | Change Directory on exit | noclx | Disables search for .clx and .cl files. Must be the FIRST argument
cgi | CGI (web programming) mode | nrs | Removes the resizing border of the main window
d | Display Device Name | o | Specify alternate Settings File
debug | Set Debug mode; equivalent to SET DEBUG on startup | q | Quiet Mode
e | For A-Shell Exit | r | Specify Memory
g | Specify Alternate Icon | s | Force Standalone mode
h | Ignore Hangup Signal signal | t | Background Task
hd | Hangup Delay | td | Use specific Terminal Driver
hei | Hangup Error Immediately | -trace | Debugging trace mode
hetcki | Hangup error on tcki | ua | Unattended Mode
hp | Hangup Parent | uo | Override User Name
i | Specify INI File | v | Version
j | Force the use of specified Jobname | w | Obsolete. though still supported; use -o
k | Prompt for security key | z | Invisible operations
m | Maximize: Force window to remain maximized | zi | Invisible with Icon
min | Minimize: Force window to start minimized | zt | Same as -z, except that task appears in Windows task list (Alt+Tab)
mntsys | Define a device that will be searched ahead of SYS:, CMD:, BAS: | 2 | Child Session
mx | Remove Menu Buttons: Remove buttons from title bar of window |  |

History

2016 February, A-Shell 1506: Added mntsys and noclx.

2013 December, A-Shell 1371: Added nc and nrs.


Buffer Name

b <buffer file name>

The -b switch allows you name the screen picture buffer file something other than the default of <jobname>.BUF. Specify the buffer file name in AMOS format. The default extension is BUF, and the default directory is MEM0:[1,1] (if it exists) or else the current directory.

The screen picture buffer file is used for storing screen snapshots, which can be generated via one of the following methods:

The Ctrl+P command pops up a dialog which gives you the option of displaying the current screen buffer (which may contain several screen snapshots appended together), the option of which printer (if any) to print it to, and the option to clear the current screen buffer contents after printing. Accumulating many snapshots in a single screen buffer file may be useful for auditing or documentation purposes, or even as a way of allowing the user to refer back to prior screen in a multi-screen process.

The INFLD TYPE code |S will automatically take a screen snapshot on exit from the field (without asking any questions.) This can also be useful for auditing or documentation purposes (but will quickly create a very large screen buffer file.) You can add this globally using the SBR=INFDEF parameter in the miame.ini, although it may be more convenient to use the –ba or –bc command line switches instead of –b (see next).


Buffer and Snapshot

ba <buffer file name>

The -ba switch is identical to –b except that it also turns on the auto-snapshot feature. This is equivalent to adding |S to every INFLD call as described above, but is certainly more convenient, particularly when used with specific background tasks. (Otherwise you would either need to modify all your programs or to use a separate copy of miame.ini, one with SBR=INFDEF: |S and one without.)


Overwrite Buffer File

bc <buffer file name>

The -bc switch is identical to –ba except that if the specified buffer file already exists, it is deleted and a new one created in its place.


Change Directory

On exiting A-Shell/DOS, you are normally returned to the original DOS working directory, regardless of any PPN changes which occurred while A-Shell was running. If you wish the working directory to be set according to the last A-Shell PPN, then the -c switch should be specified. Thus a batch file to actually change the current working directory, via the LOG command would contain both switches:

ashell -e -c log sys:


CGI

The –cgi switch invokes a number of features which simplify the use of A-Shell and AlphaBASIC CGI (Common Gateway Interface) or web programming.One feature of the –cgi switch is an automatic 7 second inactivity timeout. (CGI processes should be quick, usually completing in less than a second, but in any case there wouldn’t be any purpose in the process being inactive this long.)

More importantly -cgi swaps stdout and stderr so that normal screen output goes to stderr instead of stdout. The purpose of this seemingly senseless trick is to allow your CGI programs to continue to use PRINT statements (possibly for debugging, or possibly because you were converting a normal program to CGI use and didn’t get rid of all the PRINT statements) without interfering with the web output. By sending such output to the stderr channel, not only does it stay out of the way of the web page but it can also be redirected to a file (convenient for debugging.) In order to output to the new web page, you must then use CGIUTL.SBR.

Stdout and stderr refer to the "standard output" and "standard error output" streams of UNIX / Linux programs. See CGIUTL.SBR and the section on web programming for more details.


Device Name

Each instance of A-Shell is assigned a unique console device name. An instance may be a user terminal, or a window, for example. This console device name is used in conjunction with the TRMDEF commands in the MIAME configuration file in order to determine the AMOS-style job and terminal name to be assigned. When networks are involved, or Microsoft Windows, the console device name is not necessarily fixed, and can be assigned dynamically by the operating system. In order to assist in the construction of the TRMDEF entries, the -d switch may be used, which causes A-Shell to display the currently assigned console device name. (Note that you can also display device names using .SYSTAT/C.)


Exit

The -e switch is used in conjunction with the optional command name and forces A-Shell to exit to the host shell prompt on completion of the command. This is useful for preventing users from ending up at the A-Shell command prompt (where they might be lost or even do damage) if the application terminates unexpectedly. It is also useful for creating utilities that act like standalone native operating system commands but which require the A-Shell environment.

As an example of the latter, imagine a UNIX shop where the system administrator wants to be able to check on the status of A-Shell sessions, but doesn’t want to otherwise know anything about A-Shell (how to launch or terminate it.) You could create a shell script (call it ashstat) that contained the following command:

ashell -e do astat

This would execute dsk0:astat.do[2,2], which would log the user in and then launch ASTAT, something like:

:R

LOG OPR:

ASTAT

Note that if input is piped into the ashell command by redirecting standard input, then the -e switch is assumed, and may not be overridden.

The other way to auto-terminate an A-Shell process on the completion of a command is to have the command chain to HOST.LIT (if it is a BASIC program), or to use a CMD or DO file that ends with the HOST command. In the ASTAT example above, you could have eliminated the –e switch from the ashell command line and instead added HOST to the end of the ASTAT.DO file. However, the –e switch is more convenient and more robust, since there is no way to accidentally get around it via some kind of program abort.


Alternate Icon

Updated November 2015; see History

The –g switch is used to force A-Shell/Windows and ATE to use an alternate icon. This icon appears in the About box, on the title bar, and on the task bar. Syntax may be any of the following.

-g ####

Allows you to specify the internal numeric ID of an icon already embedded within the ASHW32 executable. These are in the range of 1001-1050, but this typically isn’t very useful without some insider knowledge.

-g resname

Similar to the first, except it allows you to specify the icon by its resource name. Again, you would need to have special knowledge about which icons are available.

-g resname::dllname

This third option allows you to specify an icon by its resource name and the name of the DLL within which it resides. In this case, the DLL should be in the same directory as ASHW32.EXE was loaded from, or at least in the PATH.

-g filename.ico

This fourth option is the easiest for most people to use, as it only requires that you supply an ico file. The file should be placed in the %MIAME%\icons subdirectory. The %MIAME% directory is set automatically to the directory where the miame.ini was loaded from, unless manually set in your Windows configuration.

NOTE: This capability/feature was added in A-Shell build 1176 of March 2010. Prior to that version, the –g switch specified an icon such as "ashell25" that was embedded in the A-Shell executable. Below are notes describing the impact the new method may have on your programs, followed by the old documentation on this topic.

History

2015 November, A-Shell 6.2.1421: Revise search for icon specified in -g command line switch to look specifically in the %MIAME%\icons directory before doing a more general search, so as to reduce the chance of finding an unexpected match.

2010 March, A-Shell 5.1.1176: Add filename.ico option.

Prior to this version, the –g switch specified an icon such as "ashell25" that was embedded in the A-Shell executable.

The new method eliminates nearly all of the need to embed application icons into the ashw32.exe, so we have removed them. Temporarily, we will include in the standard release copies of all of the icons previous embedded, so no particular action is required. However, at some point in the near future, we will probably drop them as well, and leave it to individual developers to add their own custom icon(s) to the package.

The one problem which can be foreseen is that desktop shortcuts which now use an icon embedded within the ashw32.exe will be subject to having their icon reset if Windows (or the user) decides to update the shortcut. In that case, you'll need to just use the "Browse" button in the shortcut properties to browse the %MIAME%\icons directory to locate the standalone copy of the desired icon.

To prevent that from happening, you can reset the application icon using MX_SHORTCUT : Create Shortcut so that it points to the new discrete copy of the icon file.

Hopefully, all will agree that this is a relatively minor inconvenience compared to the benefits of decoupling custom icons from the executable.

Note: because of the need for the standalone icon file to exist in order for a custom icon to work within A-Shell, this update is best done by running the full install package (rather than just updating the ashw32.exe).


Ignore Hangup Signal

The -h switch applies only to A-Shell/UNIX and remote sessions connected via modem or telnet. When specified, the SIGHUP (hangup) signal is simply ignored. This was historically useful to allow a program (such as a posting program) to keep running even if its terminal connection was lost. However, its usefulness has been superceded by the new (as of A-Shell 4.7) default handling of SIGHUP, which properly turns the process into a background daemon.

Note that regardless of the way you choose to handle the hangup situation, you can also have A-Shell produce a trace log documenting when it receives such a hangup signal and what it did about it. See the discussion of the miame.ini TRACE statement for more details.


Hangup Delay

The -hd switch is similar to the –h switch described above and applies only to UNIX. It suppresses the basic error #250, which would normally be generated, but removes and cleans up the process as soon as it goes into a terminal input wait state.

This historic switch is probably no longer useful. If you don’t want to get an immediate error on receipt of the SIGHUP signal, just don’t specify any of the –h* switches.


Hangup Error Immediately

The -hei switch causes a BASIC error #250 to be generated immediately upon receipt of the SIGHUP (hangup) signal. The typical reason for receiving this signal is that the modem or telnet connection has been dropped, although it could also have been sent manually by another process using the kill command. The error will either cause your program to go to its trap routine, or if there is no trap routine active, to abort to the A-Shell command prompt. In either case, if the process doesn’t exit, A-Shell will terminate itself as soon as it stops to wait for terminal input. The idea here is to allow the process time to do any program-controlled housecleaning that it cares to do, before being forcefully terminated. Note that -hei may be used in conjunction with –hetcki.

If none of the –h* switches are specified, the default response to receipt of the SIGHUP signal is for the A-Shell process to become a background daemon but otherwise keep running normally, until such time as it stops to wait for keyboard input. Then, it will get the error #250, just as if –hei had been specified.


hetcki

The -hetcki switch causes A-Shell to treat "tcki" (check for keyboard input without waiting) operations equivalently to normal wait-for-keyboard operations, when deciding whether to terminate a session that has previously lost its terminal connection. Without this switch (or any other switch starting with –h), a process that has lost its terminal connection (due to a modem or telnet disconnect) will become a background daemon and continue to run until it stops to wait for input. (At that point, a BASIC error #250 will be generated.) Merely checking for keyboard input without waiting (aka performing a "tcki"), would not have any effect on the program.

Since the decision on whether a tcki operation should abort a program which has lost its connection may depend on the program, and therefore change during a session.


Hangup Parent

The -hp switch is another variation on the –h switch described above. When specified, A-Shell performs the default handling of hangup conditions (as if no -h switch was specified) but then forwards the hangup signal to the parent process immediately before exiting. This has been found to be useful in certain UNIX environments to force the telnet session to close properly, but should probably be avoided on the general principle that it is better to not to confuse the issue by sending signals that are normally managed by the operating system.

The –hp switch is ignored by A-Shell if it is specified on the PolyShell command line.

The "standard" technique for forcing a clean and total shutdown of a telnet session on exit from A-Shell is to launch A-Shell directly from the user’s login .profile, and follow that with an exit command. Thus when A-Shell exits, it returns to the .profile where it executes the UNIX exit.

Another technique is to use the ashgetty utility in place of the normal getty to handle the initialization and login on the terminal. Ashgetty allows you to make A-Shell take the place of the normal login shell, thus eliminating the possibility of normal operating system shell access outside of A-Shell.


Specify INI File

The -i switch allows you to override the default ini file, which is normally miame.ini in the path specified by the MIAME environment variable. Particularly in a development or support environment, it can be useful to have several different versions of A-Shell installed simultaneously in different directories, or to have multiple virtual machines set up. These could be complete copies of customers’ systems, with identical logical device configurations. In order to execute A-Shell on a specific virtual machine, it is either necessary to first set the MIAME environment variable, for example:

SET MIAME=\VM\MACHINE1

ASHELL

or to override it with the -i switch:

ASHELL -i C:\VM\MACHINE1\MIAME.INI

Note that unlike the MIAME environment variable, the parameter is the actual name of the configuration file, and does not represent a directory.


Jobname

Updated August 2012; see History

j <jobname>

The -j switch forces A-Shell to use the specified jobname, provided it is not already in use. Otherwise A-Shell generates jobnames TSKAAA, TSKAAB, etc. (or uses the TRMDEF statements).

The -j switch supports two optional suffixes:

# will be converted into digit 1-9 to make the job name unique. Example: -j jack# will generate job names of JACK1, JACK2, etc.)

% Same as #, above, but does not allow jobs originating from different workstations to share the same base jobname. This requires ATE to enforce the workstation identification aspect of that.

History

2012 August, A-Shell 6.0.1255: Add optional suffixes as described above


Maximize

(Windows only) The -m switch forces the A-Shell/Windows window to launch in maximized mode, and it also eliminates the min/max/close buttons and system menu from the window title bar. The idea is to make it very difficult for the user to unilaterally or accidentally resize or close the window. This can be useful in situations where you want to, er, minimize, the windows-ness of the application.


Minimize

(Windows only) The -min switch forces the A-Shell/Windows window to launch in minimize mode. This is similar to the –z and –zi switches, except that there will be a normal icon on the task bar, which you can click on to make the window visible.


Remove Menu Buttons

(Windows only) The -mx switch is similar to –m (see above) except that it does not force the window to be maximized, and it even allows the window to be resized (by dragging the border.) Like –m it removes the min/max/close and system menu buttons from the title bar, making it somewhat more difficult to accidentally "lose" the window.


No Menu

(Windows only) The -nm switch hides the A-Shell menu bar. This may be useful in conjunction with -m and/or -mx to limit the end-user possibilities for getting themselves into things they shouldn't.


Settings File

o <settings file>

(Windows only) The -o switch allows you to specify a "settings file" other than the default (default.ash). An A-Shell "settings file" contains the options that are otherwise configurable via the Settings menu items (e.g. color definitions.) To make changes to those settings permanent, you can use the File menu Save Settings As dialog to save a new copy of the default settings file (default.ash) or create a separate settings file of a different name. In the latter case, you would need to use the -o switch to specify the alternate settings file's name.

If only a filespec (with no directory) is given, then the directory is assumed to be the same directory as the miame.ini was located in. And if no extension is given, ".ash" is assumed.

This switch was previously –w, which is still supported but –o is preferred in order to avoid confusion with the –w switch of vue.

If the full filespec of the settings file contains spaces, then you must enclose it in quotes. For example: -o "c:\My Documents\my ashell settings.ash"

History

2006 July, A-Shell 4.9.961: The -o <settings file> specification may now contain embedded %env% variables. For example, when sharing a single %MIAME% directory between multiple users that may want to have independent settings without having to change the settings file name, you could use a standard -o parameter of something like:

-o "%USERPROFILE%\Application Data\A-Shell\myapp.ash"

If the specified file is not found, A-Shell will also look for it in the %MIAME% directory, and that isn't found either, it will look for %MIAME%\default.ash. Regardless of which (if any) is found, when the user uses the Settings...Save option to save the settings, they will be written to the location specified by the -o switch. The effect of this is that users may start out sharing their window settings, but as they customize them, they start using their own private settings.


Quiet Mode

The -q switch tells A-Shell to silence its screen output. This is normally only applicable under UNIX when you want to launch a child session (using XCALL HOSTEX) to perform some quick operation and you don’t want the user to see the resulting screen output. The normal approach, however, to this type of thing is to use the "Q" option in XCALL AMOS, which internally uses the -q switch under UNIX and alternate techniques under Windows.


Memory Size

r <memory size>

The -r switch allows you to specify the memory "partition" size (in kilobytes) for this instance of A-Shell, overriding the MEMORY parameter in the miame.ini file. You can specify one or two values, such as:

-r 800,500

-r 600

The first example specifies 800K for the initial partition, and a minimum of 500K for execution of XCALL AMOS and SBX subroutines. The second example specifies 600K for the initial partition, and leaves the default—or previously specified—size for subroutines alone.


Standalone

(Windows only) If the node license is greater than two, i.e. A-Shell is running in a networked environment, then it requires that each PC has a NetBIOS computer name set. If some standalone testing of an application is required, perhaps with the PC disconnected from the network, then the -s switch may be used, which does not require a NetBIOS computer name to be set.

Running in standalone mode on a network voids the A-Shell license agreement. In addition file locking will not function correctly. Corruption of the A-Shell multi-user queuing file, QFLOCK.SYS, is also likely to occur.


Background Task

(Windows only) The -t switch causes A-Shell to operate in a pseudo background mode which simulates the way a program would run under the AMOS Task Manager (except no log file is created.) This switch is used internally by SUBMIT.LIT when running under Windows. Under UNIX, you can use the normal shell syntax for running a program in background (i.e. by placing an "and" at the end of the command line.) Note that this option was previously implemented as –b.


Terminal Driver

The -td switch allows you to force A-Shell to use the specified terminal type. Under UNIX and Linux, this overrides the TERM environment variable, which would otherwise be used to determine the terminal type. Under Windows, it only applies in conjunction with ATS (A-Shell Telnet Server), in which case it overrides the terminal type negotiation that would normally be worked out between A-Shell and the telnet client.


-trace

The -trace switch is only useful in troubleshooting situations. It causes an enormous amount of information to be written to the log file (ashlog.log) which can help in debugging difficult problems.

Note that although the normal location for the ashlog.log file is in the same directory as the miame.ini (or in the directory specified by the LOGDIR= statement in the miame.ini), certain trace operations may occur before A-Shell has established either of those locations. For those traces, it uses the TEMP directory to create ashlog.log. This can be particularly useful in debugging problems relating to not being able to access the miame.ini (such as networking problems).

So if A-Shell fails to launch correctly and you can't figure out why, try adding "-trace" to the command line (in the properties of the shortcut) and then look at the copy of ashlog.log that will be found in the TEMP directory for the user. For windows, this is typically: "c:\Documents and Settings\<username>\Local Settings\Temp\ashlog.log"

For UNIX, it will be "/tmp/ashlog.log".

Note that if the launch proceeds to the point where it starts to process the miame.ini file, subsequent log entries will go to the regular ashlog.log file in the directory where the miame.ini is (or as specified by LOGDIR=).


Override User Name

Added August 2009

-uo launchname

When specified, it creates a new entry in the existing hierarchy of user names:

APP user (name specified by app via MX_SETUSRNAM)

LAUNCH user (name specified on command line with -uo)

REAL user (the name used to login in to the OS*)

Note that under UNIX, the REAL user could also be the "effective" effective" user (i.e. the owner of the A-Shell executable if the +s flag is set). See OPTIONS=EFFUSR for information on how the various routines that return user name decide between those two.)

The REAL user name is always defined (since you need it to log in to the host OS. The other two levels are optional, but default to the level below it. For example, if you don't specify the -uo switch, then the LAUNCH user will be the same as the REAL user.

To bypass the normal hierarchy and retrieve the LAUNCH or REAL user name directly, you can pass either "!" or "!!" to GETUSN.SBR, e.g.:

USER$ = "!"

XCALL GETUSN,USER$ ! returns LAUNCH user in USER$

USER$ = "!!"

XCALL GETUSN,USER$ ! returns REAL user in USER$

(The "!!" option is new as of A-Shell build 1156 of August 09; the "!" was introduced previously.)

Note that MX_SETUSRNAM, (reset application user name, will effectively reset it to the LAUNCH user.

The only way for an application to force the APP user name to the REAL user (overriding the LAUNCH user) would be to retrieve the REAL name with the GETUSN "!!" method, and then use MX_SETUSRNAM to set the APP user to match the REAL user.


Version

The -v switch displays the current version of A-Shell. This is displayed prior to any automatically executed command. A typical output might be:

==== A-Shell/32 Ver. 4.9(925)c-2 running under MIAME Version 1.2(214) ====

(c) MicroSabio 1990, 2000

Note that the -v switch is entirely superfluous with recent versions of A-Shell, since the standard license message (which displays every time A-Shell is launched) includes all of the information shown by the switch.


Invisible

(Windows only) The -z switch causes the A-Shell session to be totally invisible (not even showing up in the task list.) It will still show in SYSTAT though. This can be useful for special situations such as background daemons, CGI commands, etc.

To make an invisible window reappear, the job itself can execute XCALL MIAMEX,77,FLAG (where FLAG is anything between 1 and 11, covering the various ways in which a window can be displayed; see the MIAMEX.BAS sample program for more details.) Or, you can remotely force the job to reappear using SEND <jobname> ! (that is, send it a message consisting of a single exclamation point.) This latter method uses the InterJob Communication (IJC) system which operates on a frequency set by the IJCFREQ=<seconds> parameter in the miame.ini.


Invisible with Icon

(Windows only) The -zi switch is similar to –z except that it also adds an A-Shell icon to the taskbar notification area (aka "system tray"). You can thereby make the window visible by double-clicking on the icon.

See the A-Shell evelopment Guide for notes on how an application can move itself to the system tray.


Child Session

2 <parent jobname>

The -2 switch is normally only used internally (e.g. by AMOS.SBR) to indicate that the session being launched is a "child" of the specified parent jobname. The main consequence of this is that the PLYJOB and GETJTB subroutines will be able to identify the parent in the JOBATT field.

The miame.ini parameter SBR=AMOSJOB1 will cause JOBNAM.SBR to return the parent jobname specified by the –2 <parent jobname> switch, rather than the child job name.


Unattended Mode

This is useful for running programs unattended but not fully in background. The main effect is to convert any message boxes which would otherwise require user input to trace messages in the debug message window or on the screen.


mntsys

Added February 2016

This switch allows defining a system logical device that will be searched ahead of SYS:, CMD:, and BAS:

-mntsys dev:=path

For example:

ashell -i /vm/miame.ini -mntsys asr63:=/vm/miame63/dsk0 log sys:

Assuming the specified path /vm/miame63/dsk0 existed and contained 001004, 002002, and 007006 directories, these would be search prior to the corresponding dsk0:[1,4], dsk0:[2,2] and/or dsk0:[7,6] directories.

This can be useful in situations where you want to test a new version of A-Shell without overwriting your existing DSK0: directories.

History

2016 February, A-Shell 6.3.1307: Function added to A-Shell


Command Line File

Although there are a lot of possible A-Shell command lines switches, and it would be inconvenient to have to type them every time, there are multiple ways to store one or more sets of them in a file, to be invoked later without having to retype them. Under Windows, the simplest approach is to store them all in the properties of the icon(s). Under UNIX, you can create multiple script files that contain different complete command lines.

Even with the above options, sometimes it is most convenient to be able to execute A-Shell simply by invoking the executable name (e.g. ashell or ashw32.exe). For this kind of situation, we offer "cl" (command line) files. A cl file contains just the command line switches, not the name of the ashell executable. They work as follows.

If A-Shell is invoked with no arguments, or if the first argument does not start with a "-", or if the A-Shell executable is not the standard one (ashw32.exe or ashell), THEN it looks for a file in the same directory and with the same name as the ashell executable but with an extension of ".cl" (e.g. ashell.cl or ashw32.cl). If found it is expected to contain a single line of command arguments to A-Shell. The first line is thus parsed into tokens, and the tokens are inserted into the command line prior to any arguments which were on the original command line. This allows you, for example, to specify the "-i <inifile>" parameter even when it is not possible to have it supplied explicitly on the A-Shell command line. An example may make this clearer.

Let's take the case of CGI, in which you can specify an arbitrary executable path for the CGI program in the web form, but you may not be able to specify any arguments. Previously, the only way to use A-Shell as a CGI engine in this case would be to create a front-end script that in turn contained the full A-Shell command line. Now what you can do is put a copy (or just a link) of the A-Shell executable in new directory, say, /vm/web. Give its path as the CGI executable spec in the web form (i.e. /vm/web/ashell). Then create a /vm/web/ashell.cl file that contains the rest of the command line, e.g.:

-i /vm/web/miame.ini -cgi cgigo 2>/tmp/cgi.err

When /vm/web/ashell starts up, since it was not passed any arguments, it will see the /vm/web/ashell.cl file and insert the contents (line 1 only) into its own argument list. Another example would be where you have some kind of existing module that is capable of invoking arbitrary external commands of the form:

<command-executable-path> <file-arg>

The makers of this program perhaps expected you to use this facility to launch your own file editor, or print utility. But you want to use A-Shell to operate on the <file-argument> using your own custom logic. Previously, it would have been awkward to work with this command line, due to the need to predefine the MIAME environment variable, not to mention the problem of using a native filespec argument where A-Shell would have been expecting an AMOS command file name. Now, by setting up a cl file in the same directory as the ashell executable, you can invoke your own program on the <file-argument>, perhaps something like this:

-i c:\vm\miame\miame.ini myprog

The assumption here is that 'myprog' is actually a DO file which will then receive the <file-argument> as its parameter, allowing you to then pass it on to a BASIC program, using one of these basic techniques:

;myprog.do

:R

log myppn: ; you must log somewhere

run myapp $0 ; myapp will use LSTLIN.SBR to get $0

or

run myapp

$0 ; myapp will use INPUT to get $0

Note that in the above example, the complete ashell command line after processing the ashw32.cl file would be:

<ashell path>\ashw32.exe -i c:\vm\miame\miame.ini myprog <file-arg>

The important thing to see there is that the contents of the cl file got inserted into the command line after the name of the ashell executable but before the <file-arg> which was on the original command line.

The other thing to note here is that the cl file must have the same name as the A-Shell executable and be in the same directory. If you have only one such special need, then it can probably share the same A-Shell executable and directory as your regular A-Shell users (since the regular users, at least under Windows, would presumably always be passing one or more -switches on the A-Shell command line, and thus would not use your .cl file.) But if you have need for multiple cl files, or you are launching A-Shell under UNIX with no switches at all, then you will have to create one or more copies of (or links to) your A-Shell executable, each of which can then have its own cl file.


Command Line File Option CLX

Added February 2016

New command line file option: <executable>.clx e.g. ashell.clx or ashw32.clx

Similar to the .cl file, the .clx file may be optionally placed along side the ashell executable in order to supply an alternate command line. But unlike the .cl file, which is only used if the original command line does not contain any switches, the .clx is used regardless of the original command line. This is useful in situations where you want to modify the ashell command line for all the users, without having to track down and modify all the individual user startup command or shortcut files.

Also unlike the .cl files whose contents always augment the original command line arguments, the .clx command line may either replace the original command line, or be inserted prior to the original. To get the latter effect, add a " +" to the end of the .clx command line.

For example, if the original command line is:

ashell -i /vm/miame/miame.ini log bas:

and there is an ashell.clx in the same directory as the ashell executable, containing:

-mntsys asr63:=/vm/miame63/dsk0 +

then the new effective command line will be:

ashell -mntsys asr63:=/vm/miame63/dsk0 -i /vm/miame/miame.ini log bas:

If the "+" was removed from the end of the .clx file, then the new effective command line would simply be the executable followed by the contents of the .clx file, i.e.

ashell -mntsys asr63:=/vm/miame63/dsk0

History

2016 February, A-Shell 6.3.1307: Function added to A-Shell


Virtual Command Files

A-Shell startup command line commands can also be assembled into a virtual command file, consisting of multiple commands separated by '\n'. For example:

ashw32.exe -e LOG BAS:\n:T\nJOBALC\nTIME\nEL -CFG

The above command line (after the -e) is equivalent to the following command file:

:R ; (this is automatic)

LOG BAS:

:T

JOBALC

TIME

EL -CFG

Note that the \n is case sensitive (must be lower). Also note that if using this technique under a UNIX shell, you'll need to 'escape' the backslashes by preceding them with a backslash, i.e.:

ashell -e LOG BAS:\\n:T\\nJOBALC\\nTIME\\nEL -CFG

Notes

A-Shell attempts to analyze whether any \n characters occur in something that looks like a filespec. If so, it treats the \n as literal; else it treats it as a line break. For example:

xcall HOSTEX,"$ASHELL log ashtst:\nvue c:\notes \nsize c:\notes.txt"

The above command line contains 4 \n sequences. The first and third are considered not part of filespecs and thus are converted to line breaks. The second and fourth, which are contained in the token "c:\notes.txt", which is interpreted as a filespec because it starts with what could be a drive letter.

Note the following tricks and considerations when trying to get "\n" to be treated as a line break:

• If you want to follow a filespec with "\n", precede it by a space, as we did in the example above for the "\n" following "vue c:\notes". A trailing or leading space does not usually interfere with the interpretation of a filespec, so that shouldn't cause a problem. Without the space, in the example above, "c:\notes\nsize" would have been considered a single filespec.

• Quoting the filespec doesn't help, since the quotes are generally removed by the shell or other command line parser before we get to the code that looks for "\n".

• A token is considered to be a filespec if it starts with \\ or with a letter followed by a colon.

History

2005 April, 4.9.927: Virtual command file handling added to A-Shell


Initial Window Settings

Reviewed October 2008

Prior to build 1128 of 23 Oct 08, A-Shell looked for %MIAME%\default.ash unless a settings file was specified via the -o switch on the command line. In that case, if the specified filespec started with "%USERPROFILE%\Application Data\ATE" directory, and the file was not present, it would have looked in %MIAME%, but the File>Save function would have saved it to the %USERPROFILE% directory.

Beginning with build 1128, the new scheme is that if no -o switch is specified, the search path is:

%APPDATA%\<appname>\<cfgname>.ash

%APPDATA%\<appname>\default.ash

%MIAME%\<cfgname>.ash

%MIAME%\default.ash

where <appname> is "ATE" or "A-Shell" depending on the context. For ATE, <cfgname> is the name of the connection profile; for A-Shell it is the name of the ini file, or "default" if the ini file is miame.ini.

If a -o file is specified, then it overrides the above rules, although if the file has no directory, the search path will be %APPDATA%\<appname> and then %MIAME%. This matches the prior search path when -o was used without a fully qualified path, except that %APPDATA% works better (and resolves differently) under Vista.

The File>Save and File>Save As menu items have been merged into a single File>Save... dialog, which now allows you to save the current settings to one of the four locations/names above, and in addition contains a Save As button for more exotic options. It also contains a Delete button as a convenience for deleting a saved settings file (although it does not allow deleting the %MIAME%\default.ash file). And, it shows the filespec of the settings file that the current settings were loaded from.

The objectives of the above changes were:

• To better support Vista, which has a different location for which the %APPDATA% directory is not the same as %USERPROFILE%\Application Data directory;

• To make it easier for dealers, site managers, and individual users to manage their personal window settings without having to manually adjust their shortcut command lines.

The new scheme is as security-lax as the old one (allowing anyone to overwrite the shared %MIAME%\default.ash), but the save function does always default to one of the %APPDATA% options (hopefully eliminating some of the accidental overwrites). The next step will probably be to allow the shared copy to be password protected.


Launch Background Process on Boot

Added March 2009

A common question is how to launch an A-Shell background process on system boot. Essentially the concept is the same as launching any kind of independent background process, except that we need to insert our command somewhere that will get it executed automatically by the system boot process. Unfortunately, the details of that vary from one UNIX platform to another, but to take an example, most Linux distributions have a script /etc/rc.local which gets executed towards the end of the boot process, and which is intended for launching application-level processes like A-Shell.

Although you can put as many entries as you like into /etc/rc.local, I would recommend consolidating all your A-Shell related startup processes into a single script kept in the A-Shell bin directory (we'll call it bgprocs) and then have rc.local execute it. (That way, when you set up a new system, or overwrite your rc.local, it's easy to reconfigure it. For example, you could insert into rc.local something like:

echo "Launching A-Shell background processes..."

/vm/miame/util/bgprocs

(I recommend you create a special subdirectory below the $MIAME directory where you keep your own scripts, nice and separate from A-Shell stuff. In this case we're calling it /vm/miame/util)

Your bgprocs script should reference a separate script for each of the processes you want to launch. This may seem like overkill, but it allows you to execute the individual scripts again later, as needed, to re-launch a background process by itself. So let's say we have two background processes we want to launch:

# launch background process #1

/vm/miame/bin/bgpro1

# launch background process #2

/vm/miame/bin/bgpro2

Finally, each of the individual process launching scripts could look something like this...

echo "Starting Background Processor #1..."

/vm/miame/bin/ashell -n -e -td DUMB -j BGPRO1 -i /vm/miame/miame.ini BGPRO1 >> /vm/miame/dsk0/444123/bgpro1.lst 2>&1 &

Important: Remember to mark all of these scripts as executable (using chmod +x)!

A few notes about the command line in the example above:

-n will eliminate the splash message, which isn't very useful in the background process

-e will cause the job to exit A-Shell if it drops back to the dot. (This is usually helpful for detecting whether the job is running, particularly in conjunction with the -j switch to set the jobname. If it stops running, you could probably just launch your bgprocs script again to restart it.)

-td DUMB will tell it to use the DUMB terminal emulation, which will minimize the amount of escape sequence garbage that will appear in the output log

-j BGPRO1 forces the job to be named BGPRO1 in this case. That is of course optional, but is sometimes helpful for making it easy to spot whether a particular background server job is running.

The BGPRO1 following the ini file spec is the startup command. In order to get your background process running, you'll probably need a command file (here it's CMD:BGPRO1.CMD) to log the job to the right location and start the program running.

>> /vm/miame/dsk0/444123/bgpro1.lst causes the output of the process to go into that file (useful for checking what happened later, and to keep it from going somewhere undesirable, like into the mail queue.) I recommend putting the output file in the same ppn where the process runs, although you have to specify it in native notation here.

2>&1 forces the stderr output (file descriptor 2) to go to the same place as descriptor 1 (stdout), so that any error messages coming from the operating system relating to the launch of A-Shell itself will also be captured there.

As for keeping tabs on the background processes, I recommend that they output their own status information to some kind of text file. The SOSLIB procedure SysLog() does a nice job of this, but if you do your own, make sure you add a timestamp to each entry. Also see the SOSFUNC: function Fn'Sprintf$() which is very handy for outputting formatted messages and has a simple code for time stamping.

Then you can create a relatively simple utility monitor program that uses SYSTAT/L to get a list of the jobs running (from which it can determine if each of the background jobs is running, either from their jobname or the program name column). So you display a little list, and provide some way to request to see the log for any one of them. (You can use EZTYP, or perhaps TAIL <file> for that.) If the job is not running, you can re-launch it by using xcall HOSTEX,"/vm/miame/util/bgpro#" or something like that.

Example

Here's an example of such a screen that I set up for a customer with several background processors. It just has a one-character INFLD field for each process, where you can enter a code to display the activity log, reset the job, or ESC. Of course you can get much fancier with a GUI screen, perhaps creating a continuous multi-window monitor.

SENSORS - Status and Maintenance of scales & scanners

Program Job Status Action (A=Activity log, R=Reset, ESC=exit)

------- ------ -------- ------------------------------------------

ACOUNT ACOUNT [OK] A

ASCALE ASCALE [OK]

ASCAL2 ASCAL2 [OK]

CMBSCL CMBSCL [OK]

KSCALE KSCALE [OK]

CSCALE CSCALE [OK]

CARCAM CARCAM [OK]


Update A-Shell While Running

Added March 2009

A common situation is the desire to install a new A-Shell executable, but you have several people still running the old one. The question is:

Can you install a new version of the A-Shell executable without first getting all the old users to log out?

The answer is yes; you can install the new version of the A-Shell executable while users are still running the old version without much difficulty at all.

Unlike Windows, which identifies program modules by their file or module name, under UNIX, program modules are identified by the inode (numeric id associated with the directory entry). So, even though all users will typically share a single copy of the "code" part of the A-Shell executable in memory, since it is identified by the inode and not the name, we can introduce a new version of the same executable without disturbing the existing version on disk or in memory.

The cleanest procedure is to rename the existing A-Shell executable. I recommend renaming it to ashell_xxxx where xxxx is the edit number; this makes it easy to go back to the old version for testing or if you change your mind. Then copy the new A-Shell executable into the normal bin directory.

As soon as you complete the step above, any new user launching A-Shell will get the new copy, and since the new copy has a different inode than the original, the new copy will be loaded, and then shared by all subsequent users, such that it is completely independent of the old copy.

The above all assumes that the two versions are "close enough" to each other that they don't create compatibility issues between them. In general, as long as you are on the same major and minor version (5.0 or 5.1), there should be no problem.

Of course you may still end up introducing confusion if the purpose of the update was to fix some bug, or to enable some new feature in your application, since it will be difficult to tell from the outside which user is running which copy. You can get a pretty good idea though by using the SYSTAT/W switch (wide mode, which shows how long the job has been logged in). If you note the time when you did the switch, and can do time clock arithmetic in your head, you can probably figure out which users are running which version. (This also points out one of the various reasons why it's good practice to not leave idle jobs logged in indefinitely.) Note that if you want to kill users, you can use KILL.LIT, or perhaps send them a message with SEND.LIT.

It's easy to tell from inside an application which version of A-Shell you're running, using one of the XCALLs which returns the version, such as MX_GETVER. Whenever you incorporate a newly introduced A-Shell feature into your application, it is good practice to check the version in the application before trying to use the feature, perhaps warning the user to update or avoiding the feature if the version is too old.


COMPIL

compil {-switches} file

Example:

compil -x:2 -m -a source.bas

The native OS compil executable is equivalent to the COMPIL.LIT program, except that it runs directly from the OS level rather than from within the A-Shell environment. All of the switches and other behavior for the native executable and LIT versions are the same, except for the following subtleties:

• In the native executable version, the switches must each be preceded by a dash (rather than a slash as in the LIT version), and they must all precede the source file name (rather than follow it as in the LIT version). This is consistent with the normal conventions for switches in UNIX and Windows command lines.

• In the native executable version, the switches are case sensitive and must be given in lower case. (They are case insensitive in the LIT version.)

• Rather than offer three named variations (compil, ocmpil, complp) as with the LIT version, there is only one native executable version (compil). You must use the -13 switch to get the equivalent of OCMPIL, or the -x:1 switch to get the equivalent of COMPLP.

• The default amount of memory available for the native executable version is 2MB, whereas in the LIT version it is based on the job's memory partition. Use the -w:#### switch to increase it.

• The native executable outputs messages to stdout, allowing it to be redirected to a file. Note, however, that in most situations where this might be useful, the -b (background) switch is even more useful, especially when executing the compiler from within an integrated editor environment.

Because the native executable version of the compiler is not commonly used, it is not included in the typical distribution packages but is available on request. Contact MicroSabio for more information.


PSHELL

pshell {-a ashell cmd}{-hp}{-j jobname}{-l}{-l2}{-t}{-u}{-x}{-f optionfile}{-1} {other ashell args}

Note that PolyShell is an extra-cost option available for A-Shell running in non-Windows environments.

PolyShell is a multi-tasking "shell" that allows a user to run and switch between multiple instances of A-Shell on a single workstation. It does not currently support running anything other than A-Shell. This can be considered both a limitation and an advantage. It is almost certainly too limiting for power users and system operators who may prefer a multi-tasking mechanism, such as multiple X windows, or the multi-screen console, that allows anything to be executed in any of the windows. On the other hand, it may be just perfect for users who are only interested in running an application under the control of A-Shell, since it effectively forces each window to run just that application.

One other advantage of PolyShell over more "powerful" multitasking mechanisms is the low amount of processing overhead. Since A-Shell already tracks the screen contents, there is no additional overhead required for maintaining and restoring screen contents. In fact, when a process is in background, its output is simply sent to /dev/null (i.e. thrown away) since it has already passed through the A-Shell/TRACKER screen mapping system anyway. This is considerably more efficient that installing a pseudo-terminal and directing output through a "reverse terminal driver" to maintain a logical map of the screen's contents.

Furthermore, by using the "job control" signal mechanism built into most versions of UNIX (it is contained in the POSIX.1 and FIPS 151-1 standards) there is no additional overhead for filtering of keyboard characters to watch for the hot key(s). However, one disadvantage of this approach is that you cannot run PolyShell under the control of a UNIX shell that traps job control signals, because such shells interfere with PolyShell's ability to trap those signals. The standard Bourne shell (sh) does not trap job control signals; while the Korn (ksh) does (but may be turned off using set +o monitor.) The C shell (csh) may or may not, depending on the version. (Consult your shell documentation or local UNIX guru for information on how to disable the job control signal handler in shells that support it.)

The bash shell under Linux does not appear to allow you to turn off trapping of job control signals. So we recommend using the Korn shell instead.

One additional advantage of PolyShell in an application environment is that it permits certain A-Shell utilities, such as SEND.LIT and CHAT.LIT to be more effective by automatically routing the messages to the job that is in foreground. (In contrast, if you wanted to SEND a message to another user who had multiple telnet sessions running, you would have no way of knowing which one of those was actually occupying the foreground context for that user.) Messages sent via SEND.LIT to a user running under PolyShell are intercepted by PolyShell; the current process is switched into background (where it can continue to run unbothered by the message), and the user is switched to menu mode where the message is displayed. This way the recipient cannot fail to see the message, and yet it does not interfere in any way with a running process.

Operationally, PolyShell is more or less self-explanatory. The menu options are limited to opening, closing, switching among, and displaying the status of the child instances. The only non-obvious operation is the hot key used to switch back to the menu or between instances. This is defined via the POLYKEY and SWAPKEY parameters of the miame.ini file.

Subtopics

PolyShell Command Line Switches


PolyShell Command Line Switches

Since PolyShell is responsible for launching the individual instances of A-Shell, you can pass all of the normal A-Shell command line switches and arguments to PolyShell. In addition, the following arguments have special meaning to PolyShell.

Switch | Action
a | Define executable to launch A-Shell with
f | Read command line arguments from a file
h (or ?) | Display help message
l | Auto-launch first instance
l2 | Auto-launch first two instances
j | Define base job name to use for A-Shell instances
t | Validate terminal type
x | Reverse Poly and Swap Key
1 | Limit to one child


Define executable

a <ashell executable name>

The -a switch allows you to define an alternate executable name (besides ashell) for launching the instances of A-Shell. This is only useful when for some strange reason you have one or more custom versions of A-Shell with custom names. Note that although it is technically possible to plug any executable file name in with this option, PolyShell will not work correctly except with A-Shell.


Read command line arguments

f <optionfile>

The -f switch forces PolyShell to read its command line arguments from the first line of specified file. For example:

pshell –f /vm/miame/pshell.cfg

If the specified file (/vm/miame/pshell.cfg in this example) contained the following:

-x –l2 –t menu

then the first command would have the same effect as if it were:

pshell –x –l2 –t menu

The point of such a redirection, which may not be obvious at first, is twofold. First, it allows you to change the parameters on a global basis by modifying just one file, rather than by modifying each user’s startup profile. Second, even though you could accomplish nearly the same effect by launching pshell from within a script, this method is more efficient since it eliminates the need for a copy of the shell to be launched and then maintained in memory while it waits for the pshell command to exit. This would take up about 60K-100K per user on average, which is perhaps not that significant but is still a complete waste. By using the –f switch as shown above, you get all the benefits of central administration of the pshell startup switches without any of the extra overhead of using a script.


Display help message

The -? switch (or alternatively, the -h switch when it is the only switch) causes PolyShell to display a brief help message documenting the command line options. This help message consists of all the lines codes as category #4 in the SYS:PSHMSG.<lan>, allowing you to customize it if desired.


Auto-launch first instance

The -l switch (that’s the letter ell, for launch, not the numeral one) forces PolyShell to automatically launch the first instance of A-Shell, so that launching PolyShell has the same effect (for an unknowing user) as launching A-Shell. Otherwise, PolyShell starts at its own command menu, from which you can then launch instances of A-Shell. This switch also has the effect of automatically shutting down PolyShell when the last A-Shell child instance is closed. (Otherwise, closing the last A-Shell child instance just returns you to the PolyShell menu, where you can then issue a command to exit entirely or to open up an new child instance.)


Auto-launch first two instances

The -l2 switch is identical to the -l switch, except that the first time the user hits the "swap" key from within the first child, a second child is automatically launched (using the same command that was used to launch the first instance.) This is useful in environments where it is "normal" for users to have two "windows", since it saves the user from having to manually open up either of the windows, but also defers the overhead of opening the second window until it is actually going to be used. Additional windows can still be opened by using the "menu" key to bring up the PolyShell menu and then using the normal "open" command.


Define base job name

j <jobname base>

The -j jobname switch forces A-Shell to use the specified job name (assuming it is available.) When passed to PolyShell, it works similarly except that PolyShell appends a numeric digit to the end to distinguish each of the child instances from each other. For example, psh -j fred will generate child instances with job names of FRED1, FRED2, etc. Otherwise, the generated job names will be of the form PSHxxx. (See the discussion of the TRMDEF statements in the miame.ini file for information on another way to force the use of predefined jobnames.)

The –j switch understands the special macro \$USER, interpreting it as the login user name. The preceding backslash is required to prevent the shell from pre-processing the $USER macro before PolyShell sees it. (Typically, shells interpret $USER to be the effective user name, not the login user name.)


Validate terminal type

The -t switch causes PolyShell to present the user with the option of changing terminal types before proceeding with the session. It does this by first displaying the license banner and then asking the user to either confirm that it looks ok, or to specify a new terminal type. If a new type is specified, PolyShell changes the TERM environment variable to the new type, and then repeats the process until the user accepts the result. This can be a handy way to allow many users to share the same logon profile even though they have different terminal types.

Note that it is not possible to increase the length of your TERM environment variable definition. Thus, you can change it from "am62a" to "vt420", but not from "am62a" to "wyse50". Therefore, if you are using the –t switch, you should always start with a TERM setting whose length is at least a long as any of the other possibilities you are interested in. As a convenience along these lines, A-Shell will support "am62aa" as an alias to "am62a", and the standard am62a.tis TERMINFO definition we supply will as well.


Reverse Poly and Swap Keys

The -x reverses the action of the "Poly Key" and the "Swap Key."

PolyShell uses two special keys which are defined in the miame.ini by the POLYKEY and SWAPKEY statements. The key defined by POLYKEY is "hot", meaning that it will work regardless of what the application is doing (provided it hasn’t shelled out.) The default action of the POLYKEY is to bring up the PolyShell menu, which seems reasonable since you can do any of the other PolyShell operations from there. The other key, defined via the SWAPKEY statement, is only active when the application is waiting for input, and its default action is to switch directly to another instance of A-Shell.

Some people feel that we should have made the "hot" key do the direct swap option rather than bring up the menu. For them, we have the –x switch, which switches the action taken by the two keys. Even with –x, the POLYKEY is still the only hot key, but now it will swap directly to the next session rather than to the PolyShell command menu.


Limit to one child

The -1 switch (that’s the numeral one, not the letter ell) effectively cancels out most of the point of PolyShell by limiting the number of child sessions to one. Why would anyone want to do such a silly thing? One not-too-farfetched reason might be that you like the way PolyShell intercepts SEND.LIT messages without overwriting the current screen comments, but you don’t want certain single-tasking users to get confused by launching more than one session.


VUE

vue {-r} {-t} {-w} {-y} filename

The vue command is a reasonably complete implementation of a powerful text editor with a similar look and feel to AlphaVUE version 3.0 (as available under AMOS 1.4 and later). It is available in standalone versions for UNIX, as a convenience to those old-timers who prefer it over more popular native editors. Its operation is identical to that of the A-Shell command program, with the exception that the search path for ini.vue is expanded to include /etc/ini.vue (with priority over any other copy of ini.vue.) The available switches are as follows:

Switches

r: read only mode

The -r switch invokes read only mode. All functions work normally except you cannot save the file.

t: trace ini file processing

The -t switch causes certain details relating to the locating and processing of the INI.VUE file to be displayed on the terminal. This can be useful when trying to figure out why your INI.VUE parameters do not seem to be working properly.

w: start in wide (132 column) mode

The -w switch will cause vue to switch immediately to 132 column mode (if the terminal supports it.) You can also switch between 80 and 132 column display from the vue command mode using the WIDE and NARROW commands.

y: create file if not already existing

The -y switch will cause the file to be automatically created if it doesn’t already exist. Otherwise, vue will ask you if you want the file created.

Comments

It is not necessary for the MIAME environment variable to be set in order to use AshellVUE. Function keys, however, will not work unless the VUX file can be located in DSK0:[7,0], which does require that the MIAME environment be set up. Similarly, the help files are expected to be found in the directory corresponding to DSK0:[7,1]. The typical way to take care of this in standalone UNIX implementations is to store all of the VUE-related files in /usr/lib/ashellvue, either add that to the PATH or define the MIAME environment variable to point to that directory, and then create a miame.ini (in the same directory) which contains the following lines:

LANGUAGE=/usr/lib/ashellvue/englsh.ldf ; LDF file

DEVICE=DSK0:[7,0] /usr/lib/ashellvue/ ; location of VUX files

DEVICE=DSK0:[7,1] /usr/lib/ashellvue/ ; location of HLV files

Under UNIX, you can establish VUE as your standard editor by setting the EDITOR environment variable.

Under UNIX, file names are typically lowercase, and thus VUE will fold a specified filename to lower case if it doesn’t already exist in upper case. A simple way to force it to use upper case is to prepend a relative or absolute directory specifier such as "./" to the filename (e.g. $ vue ./README.TXT)

If you would like a Windows standalone version of VUE, the best approach is to create a DO file (call it AVUE.DO) that logs you in and executes "VUE $0 $1 $2 $3 $4". You can then associate particular file extensions (e.g. LST, TXT, etc.) using the Windows explorer with an A-Shell command line that might look something like: c:\vm\miame\bin\ashw32.exe –e –i c:\vm\miame\miame.ini "%1". Then when you double-clicked on a file with the proper extension, Windows would launch an A-Shell session and bring up the file in VUE. Alternately you could create a BAT file to launch A-Shell with the specified argument.


Switching Between Sessions

If you are running A-Shell/Windows or ATE, and you are using multiple instances of ATE or A-Shell, you may use the keyboard combination Ctrl+Tab to toggle between those sessions.

In the event that you are using A-Shell with PolyShell (an A-Shell add-on that you don't need to know about unless you are using it) and your miami.ini file contains the phrase POLYKEY=` (grave), then you may also switch between ATE sessions by use of the grave key. This option has been thoughtfully added for those dexterity-challenged users who can't master the multi-finger coordination necessary for Ctrl+Tab, or who might be used to and prefer to use the typical Polyshell hot key.

Note also:

• Minimized windows are re-displayed by Ctrl+Tab, and skipped by ` (grave) .

• The grave key is now activated only by the server for ATE; for local Windows sessions, it depends POLYKEY=` in the local miame.ini.


Scrollback

A-Shell includes a handy and useful feature called scrollback which enables the viewing of lines that have scrolled off the top of the screen. If you perform a DIR command, for example, and A-Shell outputs 50 or 100 lines, only the last 24 lines are visible; the others have scrolled off the top of the display. In the absence of scrollback, those lines are lost to you. With scrollback, however, you simply move the screen "backwards" or "up" to reveal the missing lines.xe "Scrollback"

Rather than being a fixed, 24-line display, in other words, your screen can be a "scrolling window" on everything that has recently been written to it.

Use Ctrl+Shift+UpArrow to turn scrolling on and off.

Once it it turned on, you can scroll up and down by:

• holding down the Ctrl key while using the UpArrow and DownArrow keys

• holding down the Ctrl key while rolling up/down with the mouse wheel

• clicking in the vertical scroll bar on the right edge of the window

Also note the following:

• The scrollback buffer holds approximately eight screens (200 lines) of text.

• The scrollback buffer is always on. The actual scrollback of the buffer may be turned off and on, but the buffer itself is always active. This means that when you first turn it on, the existing scrollback buffer text (i.e., the last 200 lines of screen output) can immediately be displayed.

• There is no disadvantage to leaving scrollbuck on. So it make sense to turn it on the first time you need it, and then just leave it on for the rest of your session.

A-Shell includes a handy and useful feature called scrollback which enables the viewing of lines that have scrolled off the top of the screen. If you perform a DIR command, for example, and A-Shell outputs 50 or 100 lines, only the last 24 lines are visible; the others have scrolled off the top of the display. In the absence of scrollback, those lines are lost to you. With scrollback, however, you simply move the screen "backwards" or "up" to reveal the missing lines.xe "Scrollback"

Rather than being a fixed, 24-line display, in other words, your screen can be a "scrolling window" on everything that has recently been written to it.

Use Ctrl+Shift+UpArrow to turn scrolling on and off.

Once it it turned on, you can scroll up and down by:

• holding down the Ctrl key while using the UpArrow and DownArrow keys

• holding down the Ctrl key while rolling up/down with the mouse wheel

• clicking in the vertical scroll bar on the right edge of the window

Also note the following:

• The scrollback buffer holds approximately eight screens (200 lines) of text.

• The scrollback buffer is always on. The actual scrollback of the buffer may be turned off and on, but the buffer itself is always active. This means that when you first turn it on, the existing scrollback buffer text (i.e., the last 200 lines of screen output) can immediately be displayed.

• There is no disadvantage to leaving scrollbuck on. So it make sense to turn it on the first time you need it, and then just leave it on for the rest of your session.


Menus

This section briefly discusses the various menu selections that appear in the standard A-Shell/Windows environment.

Note that it is possible that some or even all of these menu selections have been disabled or removed by your application software, and that many others have been added or substituted in their place. You would need to consult the application documentation for details in such a case.

The menu-bar options are set according to the LANGUAGE option in the miame.ini.

As with other Windows programs, A-Shell menus can be selected either by the mouse, or by holding down the ALT key while typing the underline letter in the menu item name. This will cause the associated drop-down menu to appear, at which point you can again select the menu item with the mouse or by typing the underlined letter, or by using the UpArrow and DownArrow keys to move the selection bar and hitting Enter to select the item. The only deviation here between A-Shell and some other Windows programs is that A-Shell does not support the Control key shortcuts that you might be familiar with. For example, Ctrl+V works as a shortcut in many windows programs to select the Paste option on the Edit menu. A-Shell doesn’t support these shortcuts because by convention, virtually all of the Control key sequences have been assigned to another purpose, typically editing operations within the current input context. (Ctrl+V, for example, was the traditional command to delete a word from the current input line.)

Subtopics

File Menu

Edit Menu

Settings Menu

Help Menu


File Menu

The File menu contains options to control the loading and saving of A-Shell configuration settings. These settings are normally kept in a file called default.ash, and mainly relate to options configurable on the various Settings menus (colors, fonts, etc.) In addition, it also stores the size and position of the A-Shell window (to be used as the default on the next launch.) Note that if a configuration file other than default.ash is to be used, it must be specified on the command line used to launch A-Shell. (See the Settings File switch in Launching A-Shell.)

Menu | Description
Load Settings | Allows you to load a new configuration file.
Save Settings | Saves the current settings to the current configuration file.
Save Settings As | Saves the current settings to a configuration file, which you can name. This is useful when individual users want to have their own configuration settings independent of other users. In that case, you would need to use the –o command line switch to specify the configuration file when you launch A-Shell.
Default Settings | Causes the current settings to revert to the defaults.
Print Screen | Provides a means to graphically capture anything being displayed inside the A-Shell window.
Exit | This is only active when you are at the A-Shell command prompt. In that case, clicking Exit will force the command "HOST" into the keyboard buffer, which in turn will cause the A-Shell session to terminate.

Subtopics

Print Screen


Print Screen

Selecting the print screen option from the file menu will display a large dialog box similar to the one below. Within the gray background is a preview of the image being saved. Select the options and choices you wish, and then save, print or email the results.

Subtopics

Configuring Print Screen

Emailing Log File


Configuring Print Screen

Although Print Screen is customizable (and easily removed), a default behavior and place on the menu is set to reduce the confusion that has historically surrounded the print screen function.

The behavior of the print screen utility is determined by a configuration file, BAS:APRNTSCRN.CFG; see the following topic Sample APRNTSCRN.CFG.

That sample APRNTSCRN.CFG configuration file is included in the installation/update packages, but will not overwrite an existing copy.

The APRNTSCRN.SBX file (and its source, APRNTSCRN.BP) will be supplied (and overwritten) during installation/update. So if you want to modify the default print screen behavior, you should supply your own SBX and plug its name into the Command= line of the APRNTSCRN.CFG file.

To remove the item from menu, just comment out (or remove) the Command= line from the APRNTSCRN.CFG file. To accomplish this for many ATE clients in one step, you can use ATSYNC.LIT in a startup command file to update the individual copies of APRNTSCRN.CFG from the server. Or, even simpler, just send a command to delete the APRNTSCRN.CFG file, e.g.

? TAB(-10,AG_WINEXEC);"$DEL %MIAME%\DSK0\007006\APRTNSCRN.CFG";chr(127);

or, using the AGCMD.EXE:

.AGCMD WINEXEC $DEL %MIAME%\DSK0\007006\APRNTSCRN.CFG

As an alternative to calling an SBX to perform the print screen function, you can specify an arbitrary Windows command line (removing the "SBX:"), e.g.:

[MENU]

Command=super-print-screen.exe -arg1 -arg2 -arg3

Note that the APRNTSCRN.CFG file is only processed by the menu subsystem the first time you click on the menu bar. So removing it or changing the Command= line after the menu has already been accessed will have no further effect until you close and re-launch the session.

2011 May, A-Shell 6.0.1215: Print screen function added to A-Shell.

Subtopics

Sample APRNTSCRN.CFG


Sample APRNTSCRN.CFG

;A-Shell Print Screen utility configuration

[MENU]

Command=SBX:APRNTSCRN

;Command=$ASHELL -zi -e RUN APRNTSCRNR

;Sample winexec command line:

;Command="C:\Program Files (x86)\TechSmith\Snagit 10\snagit32.exe"

[IMAGE]

FilePrefix=img

;capture directory

SaveDir=%miame%\captures

;image type (png,bmp,jpg,pcx,tif)

ImageType=png

Comp=0

ConvertToGray=0

InkSaver=0

Negate=0

;SourceWindow is same as IMGOP_CAPTURE winid param

SourceWindow=-2

ClientOnly=0

[OUTPUT]

Printer=

Orientation=Portrait

Title=A-Shell Print Capture

EmailTo=support@microsabio.com

;following will stifle attachment of ashlog.log

EmailLog=

;Use notes for email subject? (else use Title)

UseNotesForSubj=1

;Following identifies a non-standard ashlog.log (to attach to email)

;EmailLog=%miame%\dsk0\001002\mylog.log

;Following stifles the attachment of any log file (comment out for default ashlog.log)

EmailLog=

[UI]

;User interface (1/0)

UI=1

DlgTitle=A-Shell Screen Capture


Emailing Log File

Added July 2014

Print Screen includes the ability to email a copy of the ashlog.log (or other log file) along with the screen capture. The feature is active by default, provided that the ashlog.log file is in /vm/miame/ashlog.log (on the ATE server) or %miame%\ashlog.log (for local Windows). In the case of ATE, the print screen utility will attempt to FTP the ashlog.log file from the server.

If your ashlog.log file does not match the default location, you must add the following item to your BAS:APRNTSCRN.CFG file to enable/configure it:

[OUTPUT]

EmailLog=<log spec>

where <log spec is the fully qualified file spec for the log file (on the server for ATE, or local for local Windows). Note that this doesn't have to be ashlog.log - you could use this feature for your own application log file.

To disable the feature set the <logspec> to blank.

Note that since the aprntscrn.cfg file exists on every client PC, updating it requires either transmitting entire new copies to each PC (perhaps with ATSYNC), or you can update just that one field using:

? TAB(-10,AG_XFUNC2);"INIX,BAS:APRNTSCRN.CFG,1,OUTPUT,EmailLog,";logspec$;chr(27);

History

2014 July, A-Shell 1387: Feature added to A-Shell


Edit Menu

The Edit menu contains options related to the mouse and the clipboard. Also see Mouse Operations for further notes on using the mouse.

Subtopics

AutoMouse

Copy and Paste


AutoMouse

The AutoMouse selection on the Edit menu allows you to enable or disable the "AutoMouse" feature of A-Shell. When active, a check mark will display next to the menu selection.

AutoMouse is a feature (similar to ZTERM’s "Smart Mouse") which allows the mouse to be used for some kinds of inputs, in applications that otherwise have no particular support for the mouse. When active, AutoMouse gives you the following mouse capabilities:

• Double-left-clicking on a "token" anywhere on the screen will generally cause the text of that token to be transmitted into the input buffer. A "token" is a string of characters delimited on either side by a space or punctuation character. If you have the Beveling option set to Automatic (or ON via program control) then the token will be briefly "buttonized". (The rectangle surrounding the token will have the appearance of being depressed and then released.)

• Double-left-clicking on any empty area of the screen will simulate the Enter key.

• In data entry fields (which are managed by INFLD, which is usually the case), single-left-clicking immediately to the left of the field will transmit a Backspace character. This is often interpreted by applications as a command to back up to the previous field or screen.

The above built-in AutoMouse functions may be supplemented by an application defining its own special "tokens". For example, an application may allow you to click on the word "Help" to transmit some kind of command that brings up a help screen. Consult your application documentation to see if any such thing is supported.

AutoMouse will be automatically disabled by certain applications, like INMEMO (memo editing) or VUE (text file editing) in which the potential for harm is greater than the likely benefit. Also, it will be disabled whenever an application requests "Cursor Reporting", which is a lower level protocol in which all cursor actions are reported to the application via coded data bytes.

You can also disable AutoMouse explicitly using XCALL MX_AMOUSEXLT, opcode 4. See that topic for more details and information on related AutoMouse configuration options. }


Copy and Paste

Like most other Windows applications, the Copy menu item becomes enabled whenever text has been marked for selection on the screen. The selected text is copied to the clipboard when the Copy menu item is clicked. Under A-Shell, you can select text on the screen via the usual technique of holding down the left mouse button while dragging it (down and/or to the right) over a rectangle. Once you have selected such a rectangle, you can also copy it to the clipboard by hitting Enter or Ctrl+C (a common shortcut supported by many other Windows applications.)

As with most other Windows applications, the Paste menu item becomes active when there is text available on the clipboard (whether from the current A-Shell application or any other Windows application.) Clicking on the Paste menu item will force the clipboard text into the keyboard buffer. Exactly how that will be interpreted depends on the state of the application. (In general, pasting a multi-line selection only makes sense in a context that understands multi-line input, such as the memo or text editor.)


Settings Menu

The Settings menu allows you to view and change many of the configuration settings for your A-Shell session. These may then be saved or recalled via options on the File menu.

Subtopics

Scheduling

Beveling

Colors Menu

Font

Misc Settings

Dialog Sizing

Preview Preferences

Status Lines


Scheduling

The Scheduling menu brings up a small dialog that allows you to tinker with the way A-Shell shares the CPU with other applications on your PC. The default foreground and background priority is "13", which is measure of how long A-Shell will "hog" the CPU before intentionally yielding to another application. In general, you can ignore all of this, particularly NT, W2000 and XP, since all but the most CPU-intensive applications will yield to other applications due to the need to wait for peripheral operations.


Beveling

Beveling refers to the shading of graphic lines (typically used as borders) to give them a three dimensional (or "beveled") appearance. This can be classified as nothing more than visual "gingerbread", but it can also make certain applications more pleasing to the eye (and thus perhaps more enjoyable to work with). The menu selection brings up a dialog box, which has beveling options of "disable", "automatic", or "program control". Predictably, the first one disables the effect while the second option causes it to be turned on automatically. The last option allows applications the option of turning it on or off at their own discretion.

The SET.LIT command line SET TERM BEVEL <option> can be used to change the beveling setting within an CMD or DO file. Available <option> choices are OFF, AUTO, PROGRAM-ON, and PROGRAM-OFF.


Colors Menu

The Colors menu and associated dialog box allows you to redefine A-Shell’s color palette. By default, A-Shell uses the same 16-color palette used by AMOS, as shown in the table below:

Color # | Color Name | Color # | Color Name
0 | Black | 8 | Dim Black (Dark Gray)
1 | White | 9 | Dim White (Light Gray)
2 | Blue | 10 | Dim Blue
3 | Magenta | 11 | Dim Magenta
4 | Red | 12 | Dim Red
5 | Yellow | 13 | Dim Yellow
6 | Green | 14 | Dim Green
7 | Cyan | 15 | Dim Cyan

As the table suggests, the color numbers 8 thru 15 are normally just dim versions of the corresponding colors 0 thru 7, and in fact, are normally not specified directly. Instead, an application typically selects dim or bright (via TCRT commands 11 and 12) and a pair of foreground and background colors from the range of 0 thru 7. (The foreground color is used for displaying text and other non-space characters, while the background color applies to the space behind and between the characters.) Setting dim mode is effectively equivalent to adding 8 to the color numbers.

When an application outputs to the screen, A-Shell responds to, and stores, the color palette index numbers rather than the colors themselves. It translates the numbers into colors using the current palette definition. Therefore, there are two ways to change the colors used in an application. One is to change the color numbers themselves that are used by the application and the other is to change what the numbers mean (i.e. change the palette definition which associates actual colors with the color numbers.)

There are several ways to change the color numbers used by an application, including SET.LIT, INI.CLR, and Tab(-2,x) and Tab(-3,x) commands within BASIC programs. In contrast, this menu/dialog allows you to change the just the meaning of the color numbers.

The dialog expresses the color palette in terms of three sets of eight colors: one for normal intensity (aka bright) foreground colors, one for reduced intensity (aka dim) and one for background colors. To change any of these, just click on the button next to the number, and choose a new color. The subsequent dialog box presents a selection 48 "stock" colors, plus a button allowing you to define a custom color.

The official names associated with the color palette numbers will not change. Thus, you can redefine color 2, which is normally "Blue", to something more like lavender, but the button next to color 2 will continue to read "Blue".

After you choose a new color, the effect will be immediate when you return to normal A-Shell/Windows run mode. However, you will only notice a change if parts of the current screen are using the color number(s) which you redefined. Consider, for example, a typical "green screen" monochrome application, which uses color 6 (green) for foreground text and 0 (black) for the background. If you redefine color 2 to be lavender, you will not see any change in the application display because it wasn’t using color 2. If, however, you redefined color 0 to be maroon instead of black, then the application display will immediately change from green on black to green on maroon.

After changing the color definitions, the effect will only last for the duration of the current A-Shell session, unless you use the File..Save or Save As menu selections to save them. Note that unless you want your color definitions to affect all other users, you may want to save them in a private settings file and adjust your icon shortcut to reference that private settings file. (See the –o switch in the A-Shell command line reference for further information.)

Because of the multiple techniques available for customizing colors, it would probably be a good idea not to overboard in redefining colors on the Colors menu/dialog. For example, you might want to go for a more sophisticated look by choosing more pastel versions of the standard colors. But if you redefine color 2 (normally blue) to yellow (normally 5), and color 6 (normally green) to magenta (normally 3), the resulting confusion will likely hamper any efforts to use any of the other color configuration techniques.

To achieve the most "Windows-like" look, we recommend using the SET TERM SYSBCOLOR 1 command to associate background color 1 (normally white) with the current default Windows dialog box color (typically gray). If you then arrange for the application to select background color 1 (perhaps via a SET TERM BCOLOR 1 command in a command file or by changing the SCNCLR parameter of the INI.CLR configuration file) and a suitably contrasting dark foreground color (such as 0 or 2), even a legacy "green screen) application can take on a more Windows-like look. As an added bonus, by tying the background color to the standard Windows colors, it will adjust automatically to a change in the Windows desktop palette (accomplished via the Control Panel.)

It is also possible to redefine the colors associated with the color palette numbers using AG_PALETTE, Define or Query Color Palette.

See Also

• Color Customization


Font

The Font menu item actually has three sub-items, each allowing you to define a default font for a particular aspect of A-Shell:

Although font selection is familiar to most Windows users, the following comments may help clarify the particulars.

System (Fixed Pitch): This is the font that A-Shell uses for its "normal" text-mode display. The font size that you choose in the dialog is meaningless, since A-Shell computes the font size based on the window size and the defined number of rows and columns (which is typically 24 x 80). As you resize the window, the fonts are automatically resized accordingly. Note that you must select a fixed-pitch font for display compatibility with most legacy applications, since they often use spaces for positioning and assuming that a space is the same size as any other character.

For more information on fixed pitch fonts, see the FONT discussion in the System Parameters section.

Control (GUI): This option only applies to applications that use the Graphic User Interface (GUI) display mechanism (i.e. look more like "typical Windows" programs.) And it only determines the default GUI font. (The application may well ignore this setting since every bit of text output can theoretically have its own font specification.) The default GUI font is equivalent to the font that Windows uses in its dialogs - something called MS Shell Dlg, which is similar to Arial or Helvetica.

Grid: This option only applies to the A-Shell grid control (aka "XTREE"), and as with the GUI font above, only determines the default font. Each individual grid, and indeed the cells within the grid, and have their own custom fonts, according to the application's desires. The default grid font is the same as the default GUI font (MS Shell Dlg), which works reasonably well, except that it doesn't scale particularly well. If you like to use the XTREE font scaling feature, you may want to change your grid default font to something like Tahoma, which scales better.

As with the Color settings, you must use the File..Save (or Save As) option to save your font selections for subsequent A-Shell sessions.


Misc Settings

These settings all relate to adjustments to the screen layout and appearance. Also see the related Dialog Sizing options.

Scroll over regions of the image below and click on them for links to the indicated topics.

Force Standard Colors in Edit BoxesAllow Edit Boxes to Use Leading SpaceProportional Font ScalingExternal Font LeadingMinimum Margin When MaximizedSet Active Background ColorBackground Fill ColorForce Edit Boxes to Match Combo HeightUsed Fixed Pitch in Edit Boxes


External Font Leading

The term "leading" (pronounced "ledding") is a carryover from the old manual typesetting days when lead (as in the metallic element Pb) wafers were used to insert space between lines of text. Thus line spacing became known as "leading". There are two types of leading: internal and external. Internal leading is the space between the visible bottom of a character and the bottom of the character cell. (Characters with descenders, like "j", have less internal leading than those without them.) External leading is the space between the bottom of the character cells in one row and the top of the character cells in the next row. Typically, whether on a dumb terminal, a terminal emulator, or A-Shell/Windows, the screen is divided up into character cells with no external leading between the rows. (The apparent space between the rows is due to the internal leading within each cell.)

The motivation for increasing the external leading is that most Windows applications tend to have a lot more vertical space between fields than text applications do. (It is quite normal for a text application to have data entry fields on each line, whereas you will rarely see a Windows form in which the edit boxes are so close together.) To help achieve a more spacious look without modifying the program to actually skip rows, you can just add leading. The more leading you add, the shorter the fonts become for a given screen size.

The effect of changing the leading is immediate, so it is easy to experiment with. It is saved along with other settings by the File..Save or File..Save As menu options, and loaded automatically when A-Shell is launched.


Background Fill Color

When lines of text are output to the screen, if the leading is non-zero, there will be space between the lines that is not filled in by the background color associated with that PRINT statement. This is generally not a problem if your application doesn’t use reverse video or different text background colors for more than one line at a time, but if so, you may need to adjust the Background Fill Color option. The choices are:

• A fixed background color # (0-15): This is the simplest and cleanest, but requires that your application stick with a fixed background color and doesn’t create multi-row blocks of highlighted text using reverse video or a different background color.

• Automatic fill (-1): In this case, the space below each line of text output is filled with the background color of the text. The left and right margins of the screen are filled with the background color which seems to be most predominate on the screen.

• Passive fill (-2): The space below each line of text output is left alone, only being updated during screen clearing operations, such as TAB(-1,0) or TAB(-1,10).


Proportional Font Scaling

This controls how proportional fonts are scaled, and only applies to GUI extensions (buttons, edit boxes, checkboxes, static text controls, etc.) which may or may not be present in your application. (As of build 974, it also only applies to GUI font objects on the main window; those inside of dialogs are controlled by a corresponding option on the Dialog Sizing dialog.) The standard fixed pitch fonts are always scaled according to the window size, but this is not necessarily desirable with the proportional GUI fonts. It is actually quite rare for Windows applications to change the size of the fonts according to the size of the window. In fact, it is rare for Windows applications to even adjust the spacing of controls when changing the window size. In the case of A-Shell, in order to keep GUI objects (including static text controls) synchronized with the fixed pitch character grid, we always adjust the spacing of objects when the window is resized. But the question is whether to adjust the font sizes as well.

For the most Windows-like effect, set the scaling to 0. This will result in the standard Windows control font (a sans serif font similar to Arial or Helvetica, which is called MSDialog in WindowsXP and Segoe UI under Vista). Since its size will not change with the window size (if the scaling factor set to 0), while the size of fixed pitch text and certain container objects, such as buttons and edit boxes will change, you will probably want to adjust your Window size until the fonts seem to fit best. (The larger the window becomes, the more space the fonts will have to fit into their containers, but at the same time, the difference between the size of the proportional fonts and any fixed pitch fonts will increase. Once you determine the most desirable window size, save your settings (File..Save).

If you want to be able to make the fonts bigger on demand simply by maximizing the Window, then set the scaling factor to something in the range of 80 to 100. This will cause the proportional fonts to scale up and down according to the window size. Note, however, that font scaling is not totally linear, so you may find that with large window sizes, you need a smaller scale factor, say 80 to make things fit, than you do at smaller window sizes. (Again, the idea is tinker with the scale factor and window size until you get a pleasing combination, then save it.)


Minimum Margin When Maximized

(WINDOWS/ATE) This resolves the conflicts relating to adjusting the sizing of maximized windows. The normal, default setting is 0, which means that if the number of columns divides evenly into the screen width, when maximized there will be no left or right margin at all. (This happens, for example with 800x600 and 1280x1204 at 80 columns.) On some PC's however, this may cause the first and last column(s) to be clipped (due to over scan). Previously, we just subtracted a fudge factor from the screen width to prevent this problem, but now you can just set the minimum margin parameter. The margin units are pixels, but in most cases, setting the minimum margin to just 1 pixel will actually result in a considerably larger margin since font widths generally come only in integer pixel widths. For example, in the 800x600 case, the font width would be 10 pixels at 80 columns. But if you introduce a 1 pixel margin, the font width will have to be reduced to 9, which means that 80 columns only occupies 720 pixels (leaving a margin of 40 on either side).

Note that in the Windows and ATE environments, you can increase the number of columns in the window grid to put some of the margin space to work. For example, in the 800x600 case, if the font width is going to be 9 pixels, you could increase the number of columns from 80 to 88 and still a 4 pixel margin on either side.

The margin is ignored in non-maximized mode, because in that case, first of all, over scan is not likely to be a problem, and secondly, if it were, you could just adjust the window width with the mouse.


Use Fixed Pitch in Edit Boxes

This applies only if your application uses Windows-style edit boxes for editing data fields. If so, they will normally use the standard Windows proportional font for the data characters. Some people don’t like the fact that this makes it difficult to see what the maximum number of characters for a field is. (With fixed pitch characters, the field size relates exactly to the number of characters allowed, but with proportional fonts, it depends on the widths of the individual characters.) One way to minimize (but not totally eliminate) that confusion is to set this option, which will force the edit boxes to use a fixed pitch font. The actual font will be scaled so that the maximum number of characters allowed will approximately fill the field space, but due to the idiosyncrasies of font scaling, it will never be quite as exact as it is with fixed pitch. (You may be able to set a switch in your application to get it to use the old-fashioned text-oriented input style rather than Windows-style; "Neo-Luddites" should contact their application developer for details.)


Force Standard Colors in Edit Boxes

This option overrides the application’s color parameters for edit boxes. Some applications will assign various fancy color schemes to editing, for example, using one color while editing, another for display, a third for redisplay of updated fields, etc. These enhancements can be quite effective in a text environment, but may not work so well in a GUI environment. Setting this option will cause A-Shell to ignore the application’s color specifications and just use the standard Windows ones for any edit boxes. (This is essentially mandatory when XP Visual Themes are in effect.)


Set Active Background Color

This option is used to define a special background color to be applied to INFLD edit controls when they are active. The theory is that by defining a light color that is nonetheless distinguishable from the standard white, it will be easier for users to detect which edit field is active. Note that the effect only works for INFLD controls that are based on the standard Windows edit control (i.e. includes combo boxes and up-down controls, but not check boxes, radio buttons, or date/time controls.) Note that the button and feature is not active unless the Force Standard Colors in Edit Boxes option is checked.


Allow Edit Boxes to Use Leading Space

This only applies if the External Leading option (above) is non-zero. If so, it allows edit boxes to extend approximately half way into the leading area below the current row. This is often useful to allow sufficient space for the characters to fit within the box. (Depending on your scaling options, window size, etc., you may find that your edit boxes are clipping off the bottoms of the characters. If so, this is one way to deal with it.)


Force Edit Boxes to Match Combo Height

This option deserves an award for being especially cryptic. It can be safely ignored if your application does not use drop-down combo boxes, date pickers, or any other field editing control which includes a little down arrow button on the right side which opens the field up. If it does, then there is a potential problem in that Windows, in its infinite wisdom, does not allow those edit boxes to be scaled, while normal edit boxes can be. Thus, if you have a mixture of the two types of edit boxes and you adjust the window size, the edit boxes will change in height, but the combo boxes will not. If this effect bothers you, then set this option, which will force the edit boxes to remain at the same height as the combo boxes. (That, however, overrides the previous option, as well as undermines the ability to adjust the ratio of font sizes to their containers by adjusting the window size.) So, like so many other factors in the GUI environment, it’s a tradeoff.


Dialog Sizing

This dialog contains options which control the sizing of dialogs created at runtime by A-Shell applications, rather than embedded into A-Shell, as this dialog itself is.

this file is NOT linked

Subtopics

Dialog Grid Units

Font Scaling %

Grid Unit % Adjustment

Include Caption in Dialog Height


Dialog Grid Units

The three radio button choices allow you to choose which of the two dialog grid systems (described below) you want to use. The first two choices force all dialogs to use the specified grid. The last choice (choice left to program) allows the applications to determine it on a dialog-by-dialog basis (by whether or not the MBF_ALTPOS flag is specified; see AUI Control for programming details.)

The Dialog Grid Units setting allows the user to control what kind of metric units (or grid units) to use for defining the size of dialogs and the positioning of objects within them. The two choices are as follows:

Main window grid size

This is equivalent to the grid used in the main A-Shell window—e.g., the 24x80 grid. The size of this grid unit is exactly the size of a single fixed-pitch character, plus the external leading, and it will vary based on the physical size of the window and the currently defined number of rows and columns. Note that this grid system is always used for main windows. The main problem with this grid system is that it makes your dialog sizing dependent on the size of the main window at the time the dialog was created. Thus, if a user likes to have several applications running at the same time, and makes the main window relatively small, your dialogs may be too small. Meanwhile, another user may like to maximize the main window, causing your dialogs to be huge. (This is very unlike the way a typical Windows application sizes its dialogs.) A related problem is that because there may be such a huge discrepancy between the main window grid size and the typical GUI font used in dialogs, the row/column units used to position and size controls in the dialog may be nearly meaningless, making it hard to visualize the dialog while programming. A third problem is that when the dialog is created, the coordinates specified are for the total size, including the caption. Because the caption height may be more or less than one logical row, depending on the size of the main window, this makes it hard to know exactly how many usable rows are inside the dialog. For these reasons, the traditional grid is not recommended.

Windows desktop font size grid

This is based on the standard Windows desktop font (i.e. the font used for the text beneath desktop shortcut icons). This is also the same font that is used for the standard menu bar options in Windows programs, and for the text in most standard Windows dialogs. This grid system solves the problems discussed above. First, it is independent of the size of the main window. Second, since it is based on the standard Windows GUI font size, it adjusts automatically to changes in the Windows desktop settings (i.e. the resolution and font DPI). In other words, if the user doesn't like the typical tiny Windows font and adjusts the font DPI to make everything in the Windows environment bigger, your A-Shell dialogs will get bigger right along with everything else. Third, since the units are based on the same standard GUI font that is the standard in dialogs, the units are more meaningful in the sense that they relate more closely to the amount of text you can display. (Obviously, it is impossible to have a one column equals one character ratio with proportional fonts like you have with fixed pitch fonts, but the grid unit width is based on the "average" character width, with a little extra to allow for text that may consist of above-average widths.)


Font Scaling %

The Font Scaling parameter in the Dialog Sizing dialog is equivalent to the Proportional Font Scaling option on the Misc Settings dialog, except that the form applies only to dialogs, whereas the latter applies only to the main window. Also, the scaling basis is somewhat different between the two. In both cases, 0 indicates the standard Windows font size (i.e. no scaling). Any other percent value for the Font Scaling factor in the Dialog Sizing dialog is relative to that same standard Windows default font size. So 100% in this case is equivalent to 0; 125% would give you fonts that are 25% larger than the standard Windows default font. (In contrast, the font scaling factor on the Misc. Settings dialog is relative to the size of the main window grid.)

For dialogs using the Windows desktop font size grid, increasing the font scale factor also increases the size of the grid units and thus increases the size of the dialog and all the controls within it. The overall effect is similar to what happens when you change your Windows desktop font DPI, except that here the effect is only limited to A-Shell dialogs. In contrast, for dialogs using the A-Shell main window grid, changing the font scaling factor does not affect the size of the dialog; it only affects the size of the text, and the height of combo box controls. (If the Misc Settings option to force edit box height to match the combo box height is set, then changing the font scale factor also changes the edit box height.)


Grid Unit % Adjustment

These two options apply only to dialogs using the Windows desktop font size grid, allow you to adjust the height and width of the grid unit without affecting the font size. This is a somewhat exotic technique, but might be handy if you find that your dialogs are either too spacious (in which case you specify numbers less than 100%), or two crowded (causing some of the text inside controls to be clipped), in which case you can increase the percentages. Or, a third situation would be that you feel that all your dialogs are either too tall and skinny or too short and fat, in which case you can adjust the percentages to get the desired aspect ratio. Note however that these adjustments are global (i.e. they affect all dialogs using the Windows desktop font size grid), so are of no use in adjusting just a couple of dialogs. (For that you need to modify the dialog design itself.)


Include Caption in Dialog Height

This rather obscure option only applies to dialogs that were forced to use the Windows desktop font size grid because of the radio button options at the top of the dialog. (In other words, dialogs that were designed to use that grid will not be affected.) The option is probably only useful as a visualization tool, to be used temporarily, when considering the choice to migrate from the traditional main window grid to the newer Windows desktop grid. Since the height of dialogs created using the desktop font size grid does not include the caption (title bar) height, switching from the traditional grid to the desktop font size grid has the effect of making your dialogs taller, which initially makes them look "funny". Although the real solution is to adjust the internal layout of the dialog, this option can be a useful expedient.


Preview Preferences

These settings control the behavior of A-Shell's print preview system, which is a quasi-independent module called "APEX." APEX is an extra-cost option with A-Shell, and it may therefore not be available for your use. See the section of this document on APEX for information on Preview Preferences.


Status Lines

Updated May 2011

Use these options to turn on/off the top, bottom and session status lines. Note that turning on status lines does not cause information to appear on the lines, nor does it provide any additional space for normal terminal operations. Status lines are accessible only by program control, and are optionally used by programmers for, well, status information.

The session status line, added in A-Shell 1213 of April 2011, displays a session clock (how long this session has been active) and, during host-client file transfers, a progress indicator.


Help Menu

The contents of the Help menu are frequently modified by the application, and by the doc\ashelp.mdf configuration file, so it is quite possible that yours will look different from the selections described here. However, typically you will have a Windows-standard "About" box, and various document links.

Menu Item | Description
About | The About box displays information about A-Shell in general (copyright), this running copy (version, memory usage, font, etc.), and this particular license (nodes, serial number, etc.).
Doc Links | Among the document links, you will usually have a link to this document (A-Shell Setup Guide), plus a link to the documentation page on the MicroSabio website. You may also have links to additional local documentation resources for both A-Shell and your application. See Help Menu Links in the Configuration section of this document for notes on customizing these items.


Mouse Operations

Although AlphaBASIC applications were, in most cases, originally developed for dumb terminals (without mice), A-Shell/Windows does support a number of mouse capabilities.

Copy and Paste

You can copy text from the A-Shell display to the clipboard, and paste it from the clipboard into the current application’s input context, more or less as you would with any Windows application. See Copy and Paste on the Edit menu for further details.


Print-to-Email

Aside from the various developer-level options for outputting to email (see the Email discussion), there is also a user level-option which only requires that a logical printer be set up whose init file contains the statement COMMAND=SBX:EMAILP. (See Printer Configuration for further instructions on setting that up.) The only other requirement is that your application software provides a way to choose a printer. (See the EZSPL configuration notes in Printer Configuration for information on how to add printer selection to an application that uses hard-coded printer names.) Once you have the ability to select a printer, you can then print any ordinary (text only) report to email, using the MAPI interface that is included with most versions of Windows. When such a printer is selected, it will launch your email client (e.g. Outlook, Eudora, etc.) with the printed document embedded into the body of the text message, and allow you to address it as you would any other email message.


Print Preview

There are several ways you may have reports that were created within A-Shell displayed on the screen before (or perhaps instead of) sending them to a printer. See APEX plus the following topics.

Subtopics

EZSPL Print Preview

Other Preview Options


EZSPL Print Preview

A-Shell includes an implementation of MicroSabio’s EZSPL printer enhancement package, which was original developed for AMOS. One feature of EZSPL is the ability to preview any print file before, and perhaps in lieu of, sending it to a printer. The option to preview the file may be configured via the EZSPL configuration files (which are described in the Configuration section of this document.) The preview utility itself (which goes by the name of EZTYP or EZVUE) allows you to scroll or page through the file, or to go direct to individual lines, pages, or to search for text strings. You may also print excerpts from the print file. The available keyboard commands may be displayed by entering "?" (question mark) at the EZTYP command prompt, and are briefly described in the table below:

Command | Action
Right Arrow | If the current screen width is normal, and the terminal device supports wide (132 column) mode, the right arrow key will cause it to switch into wide mode. If already in wide mode, or the terminal does not support wide mode, it will increase the left margin by 4.
Left Arrow | If the current screen width is wide, the left arrow key will switch the terminal back into normal (80 column) mode. If the screen is already in normal mode, and the left margin is greater than 0, then it will decrease the left margin by 4.
Up Arrow | Scroll up one line
Shift Up | Switch display to short (24 row) mode. (Also see T command.)
Down Arrow | Scroll down one line
Shift Down Arrow | If supported by the terminal device, switch to tall (42 row) mode. (Also see the T command.)
TAB | Increase left margin by 8.
Shift TAB | Decrease left margin by 8
+# | Go forward # pages (paper pages, not screen pages)
-# | Go backward # pages
=# | Go to page #
0-9 | Scroll; the number determines the scrolling speed. Stop scrolling with any other keystroke.
B | Go back one page
E | (End) Go to the end of the document
F | To forward one page
H | (Home) Go to the start of the document
L# | Go to line #
M# | Set left margin to #
N {string} | Search for next occurrence of string specified, or if no string specified, of the string specified in a previous S (search) or N (next) command
P | Print current page or a range of pages.
R | Recalculate pages (see notes below the table)
S <string> | Search for the first occurrence of the specified string
T | Toggle between tall (42 row) and short (24 row) display format. (This is only possible under A-Shell/Windows and with certain ZTERM-specific terminal drivers under A-Shell/UNIX.)

The EZVUE utility displays on the bottom status line (if supported by the terminal device), the filename, plus the current line and total number of lines (L # / #) and the current page and total number of pages (P # / #). If the document is reasonably large, EZVUE will not initially scan all the way through the document to determine the total number of lines or pages. In that case, it will display a question mark next to its estimate of the total number of lines and pages. To force it to scan through the entire document to compute the number of lines and pages, you can use the R (recalculate) command. It will do this automatically if needed to carry out specific commands.

If the document being displayed contains formfeed characters, then "pages" will refer to pages as printed (i.e. paper pages). Otherwise, "pages" will refer to screen pages.


Other Preview Options

In addition to the EZTYP/EZVUE print preview utility as described previously, under A-Shell/Windows there are several possibilities for previewing report files using third-party graphical tools.

The simplest approach, since it uses only components which come with Windows or with A-Shell, and which works well as long as your report file consists only of plain text, is to view it in a browser. You can create a pseudo-printer, which will wrap the report file with the necessary HTML codes for fixed-pitch display and launch the browser to display it, by setting up the following printer init file:

COMMAND=SBX:HTMLP

The HTMLP.SBX (and BASIC source) files are included in the [7,376] directory of the standard release. Just copy HTMLP.SBX to BAS: to use it. See Printer Configuration for further details on the COMMAND statement and on printer configuration in general.

Another approach, which works with any kind of report, including ones with embedded graphics and/or GDI directives, is to print to the well-known Acrobat PDF Writer from (Adobe.. It will create a PDF file from any Windows report, which you can then view with the free Acrobat Reader. This is a bit overkill just for a print preview, and involves the expense of purchasing the Acrobat PDF Writer, but if you already have it, this might make sense.

Yet another option is to obtain a printer driver that only creates a preview. One that we have tried that works well is the NED Image Printer from Northeast Data Corp. The free version displays a small nag message, but you can purchase a full license for a nominal amount. It works more quickly and directly than does Acrobat to give you a graphic view of what the printer output would look like, without having to create an intermediate file.


Color Customization

There are at least three ways to configure the color settings for an A-Shell application without modifying the application itself: First, you can edit the INI.CLR file (see Configuration for details.) Second, you can use the SET TERM FCOLOR # and SET TERM BCOLOR # commands within a startup command file to set the initial foreground and background colors. (For applications that are not "color-aware", either of these first two techniques will be effective.) The last method is to change the definition of the color palette itself (i.e. what actual colors are associated with the color numbers used at the application level.) Under A-Shell/Windows, this can be done via the Edit..Settings menu (which see, above.) Under A-Shell/UNIX, you would have to do it within your terminal emulation software. (ZTERM, for example, has a color redefinition capability similar to A-Shell’s.)

In September 2016, a user asked: "Why are A-Shell / ATE screen colors NOT set to the "natural defaults" shown in the colors settings?" And the answer is:

The .ash file is overriding the "natural defaults", which aren't so much "natural" as "original," dating back to the first color terminals used with AM systems.

The original scheme makes sense for programs and people still based in that 80's era. Trying to use a black background in programs with any GUI content at all—where the default text color is black—is a disaster. The gray is a kind of compromise for mixed GUI/text environments.

For better or worse, there is so much flexibility in the system, and so many parts, that I doubt anyone really understands it, even Herman, who has probably tried harder than anyone. We have the .ash file, which contains the RGB definitions of the color numbers, i.e. what you see in the Settings > Colors dialog; we have the TAB(-2,x) and TAB(-3,x) commands for changing the default fg/bg color index; we have the LIB:INI.CLR file which contains sets of color indices for various contexts like INFLD, VUE, etc.; we have the AG_COLOR command allowing you to redefine the RGB values programmatically; we have MX_WINSETTINGS allowing you to save/load .ash files; and we have the FGC/BGC fields in AUI_CONTROL.) It's great if you understand it all and know exactly what you want; otherwise it's a nearly impenetrable mess, begging for some kind of overall "scheme" choices ("Midnight", "Navajo", "Valentine", etc.) and an easy way for users to just choose one. But that's pretty much what selecting a new .ash file does.

So the "net advice" on the subject is this: if you have one or more color scheme you like, and a preferred default, use File > Save As to save it/them to an .ash file and then load and use them as desired.

See Also

• Colors Menu


Interfacing to the Outside World

One of the advantages of moving your application from AMOS to Windows or UNIX/Linux is that it makes it easier to interface with the outside world (since most of the "outside world" is running under Windows or UNIX/Linux.) However, while it may be easier, it may still require the efforts of a programmer or integrator to work out the details. So the following topics are covered less in the spirit of "how-to" and more in the spirit of "what-you-can-do" (with suggestions on where to go for further "how-to" details.)

Subtopics

IP Lookup

Email

Web Pages

SQL / ODBC

CSV (Comma Separated Values)


IP Lookup

(Windows) A-Shell determines its IP address on startup. In most cases, this will be invisible and painless, but if you have a software firewall and/or a disfunctional internal DNS, the act of trying to determine the IP address may either trigger a hook in your firewall and/or cause a delay in launching an A-Shell session. A-Shell will automatically log the length of such a delay to the ashlog.log file if it exceeds 0.75 seconds. So if you notice a delay in launching A-Shell, you may want to check the log to confirm the source of the problem.

History

2004 April, A-Shell 4.9.879: Feature added to A-Shell


Email

It is actually a rather simple development task to modify an existing report program to send it to an email address rather than a printer. To email a report interactively via your current email client application, under A-Shell/Windows you can use the technique described under Windows-Specific Topics above.

You can also use that technique under A-Shell/UNIX, except that you would need a copy of ATE on the workstation. In that case, you would use a pseudo-printer on the A-Shell/UNIX side that contained COMMAND=SBX:GDIPRT in its init file, which would transfer the file to ATE, where it would be redirected to another pseudo printer using COMMAND=SBX:EMAILP to redirect it to the email client.

To send email directly (without any interactive human intervention) the easiest approach is to use the EMAILX utility, which we make available for a nominal license fee. You can also use the built-in subroutine TCPX.SBR to interface directly to your mail server.


Web Pages

Making content available via web pages can be handled in at least two different ways. At the simplest level, you can add a couple of HTML statements to the start and end of any report and then view it via any browser, either by manually typing in the FILE://<filename> URL into the browser, or by launching it via the MIAMEX Function 96 (under A-Shell/Windows), of via a terminal-emulator-specific ESC sequences (under A-Shell/UNIX). Refer to the ZTERM documentation for details if you are using ZTERM.

The minimum set of HTML statements needed at the start of a report file is the string "<HTML><BODY><PRE>" and the corresponding trailing command would be "</PRE></BODY></HTML>". You could accomplish this without any program modification by using the PREFIX and SUFFIX options in the printer init files (which see in this document), but you would then have to launch the browser manually. An even simpler solution (under A-Shell/Windows) is to print to a printer whose init file contains COMMAND=SBX:HTMLP. This will apply the HTML statements above and automatically launch the browser to view the file.

The approach above is only useful for local or directly connected users. To make content available via web pages to ordinary web browser users who have no other connection to your server, you can modify one or more programs to support a CGI interface.


SQL / ODBC

If your data is stored in ISAM PLUS files, you can purchase a third party ODBC driver from Easysoft Limited that allows you to query, read, and write your data using popular client data analysis tools (spreadsheets, report writers, etc.)

The Easysoft ODBC driver can also access non ISAM PLUS files, but you lose the ability of using indexes. (That is, you have to scan one file at a time, from start to finish.) In either case, you’ll need a the map layout of your data records in order to create a schema definition. If you didn’t write the application, contact your application supplier for assistance before purchasing an Easysoft license.


CSV (Comma Separated Values)

In many cases, the simplest way to make your data available for analysis by popular PC tools is to output it in CSV format. Although this is a programming task, it is a very simple one. To make it even simpler, ASB includes statements that further simplify the task of outputting comma delimited (WRITECD) or tab delimited (WRITETD) files. Such files can then be automatically transferred to the PC (if necessary) and then read directly by many popular PC data-analysis utilities (such as Excel).

Many people instinctively shy away from this suggestion, either out of the belief that converting data files to CSV format is complex or that it would take a long time to run the conversion. Both of these beliefs are misguided. In all but the most extreme cases, a utility to create a CSV version of an existing data file should take under an hour to write and only a few seconds to run. It often takes longer for the utility program (such as Access or Excel) to launch than it does to create the CSV data.


Screen Pictures

Although Windows offers a variety of ways to capture a picture of the screen, A-shell includes an integrated screen picture utility, which is available at most input prompts, and which is often much faster and more efficient to use. The pictures are text-only, but this has the advantage of making them small, quick to print, and easy to edit or import into other contexts. It is also possible to create a log of screen snapshots and refer back to them at will, with or without printing them.

To take a screen picture, from most application contexts, just press Ctrl+P. Unless your application is in a context where it is not able to process the Ctrl+P command, this pop up a dialog box that looks something like this:

Display Screen Buffer?

Printer to Print Capture To:

Delete Capture File after Printing?

Comment:

You can abort from this dialog by hitting the ESC key.

The Display Screen Buffer first prompt gives you the option of examining the accumulated screen picture log. (Whether or not there are more than one snapshot available will depend on whether you used the Delete after Printing option at the time of the previous screen snapshot.)

The Printer prompt allows you to specify a printer. Note that you can put in a non-existent printer if you don’t want to really print it. Under A-Shell/Windows, you can also use the pseudo-printer PROMPT, which will present the Windows select-printer dialog, from which you could always cancel.

The Delete after Printing option is self-explanatory. If you answer negatively, your next screen snapshot will be appended to the current snapshot file, allowing you to accumulate as many as you like. (This can be handy for documenting sessions for training, documentation, or other review purposes.)

The Comment option allows you to add a comment to the bottom of the screen snapshot. This can be very helpful to the person later looking at the snapshot, wondering why you took it.

Notes

If the PRINTER= statement in the miame.ini specifies a second printer name (e.g. PRINTER=p1,p2) then that printer (p2 in this example) will be automatically used as the printer for the screen snapshot, and the pop-up dialog above will skip over the first two questions. If it also specifies the "NODLG" option (e.g. PRINTER=p1,p2,NODLG) then the snapshot will be sent to the printer without the dialog above even appearing. Either of these options is useful when you want to simplify and/or standardize handling of screen snapshots, for example, using them strictly for reporting problems. (In that case, the ideal would be to have your snapshot printer actually email the snapshot to your support provider.)

The Ctrl+P command is actually only processed by the INFLD (aka INPUT) subroutine. This routine is used internally by the vast majority of input routines (including the dot prompt, memos, and field-level data entry) but there may be applications or application situations that do not use it. To obtain screen pictures in such situations, either consult your application provider or use one of the Windows-based methods (assuming you are using a Windows workstation.)

The screen picture file will be named <jobname>.BUF and will be stored in the special directory MEM0:[1,1] if it exists, else the current login directory. You might want to erase these files nightly to avoid the situation where someone wants to print just a single screen picture but instead gets many pages of pictures taken during prior days that were printed without the delete option.


Function Key Programming

A-Shell supports the same function key programming (aka translation) methods most popular under AMOS. For those unfamiliar with function key translations, here is a brief overview, followed by specific instructions on how to do it yourself.

Nearly all terminal keyboards, whether PC-based or not, include a number of special keys which send more than just a simple ASCII byte. When a key sends more than one byte (i.e. a "multibyte sequence"), it usually starts with one of a small group of bytes recognized as "lead-in" characters (ASCII 27 or Escape, and ASCII 1 or Ctrl+A, being the most common). Typical keys that send such multi-byte sequences are those across the top marked F1 thru F12 (or higher), plus a collection of keys over to the right with names like Page Up, Page Down, etc. In addition, using the Shift, Control, and/or Alt keys in conjunction with certain other keys may produce a multi-byte sequence, e.g. Shift-Tab.

The terminal driver (a module embedded within A-Shell that understands your terminal hardware) recognizes these multi-byte sequences by a combination of their lead-in characters and by the fact that the remaining bytes arrive too fast to have been manually typed. Since these multi-byte sequences typically vary greatly among hardware terminal types, they are difficult for applications to use directly. To overcome this difficulty, the terminal driver condenses the sequence into a single integer value, which then serves as an index into a translation table, which can be easily modified by the user or developer.

Function key translation tables are stored in files, which use one of two naming conventions. The first convention is for the name of the file to match the terminal driver name, with an extension that indicates the context in which the translations should be used. The most common of these is IFX (for most input contexts) and VUX (for VUE). These are stored in DSK0:[7,0] (aka the LIB: ersatz directory.) For example, under A-Shell/Windows, the most common terminal driver name is PCTDVG, so the corresponding translation files are LIB:PCTDVG.IFX and LIB:PCTDVG.VUX. Under UNIX/Linux, the most common terminal drivers are AM62A, AM62C, AM65, AM75, WYSE50, and thus the corresponding translation files are LIB:AM62A.IFX, etc. These IFX and VUX files are automatically loaded into memory as needed.

Under A-Shell/Windows, your terminal driver name is determined by the CONSOLE statement in the miame.ini. Under A-Shell/UNIX, it might be determined by a TRMDEF statement in the miame.ini, or simply by setting your terminal emulator to a particular emulation and letting the operating system figure it out. UNIX and Linux will set the TERM environment variable to indicate the terminal type, and then A-Shell will consult this variable to set the terminal driver. You can examine the TERM environment variable from the UNIX/Linux shell prompt by typing the command: echo $TERM. You can reset it with the command: TERM=xxxxxx; export TERM (where xxxxx is the desired terminal type). From the A-Shell dot prompt, you can check your terminal driver setting with the command SET TERM. If it shows "GENERC", then your TERM environment variable setting was not recognized, and it is using a generic driver (which will not support function key translation.) Otherwise, it will indicate your terminal driver name, such as AM62A.

The second naming convention is for the filename to be anything you like, with an extension of PFK. For example, a user named Jack may create a set of his own special function key translations called JACK.PFK. Or, perhaps a user or developer will set up some special function key translations for a particular application, such as invoicing, and call it INVOIC.PFK. These PFK translation files must be manually loaded into user memory (using the LOAD command) in order to be recognized, and once loaded, they override the previously mentioned type of translation file.

Under AMOS, these two naming conventions corresponded to different file formats, and required different commands to edit them (FIXTRN for the former and SET PFK for the latter.) Under A-Shell, they are actually the same format (matching the FIXTRN format used under AMOS) and are both maintained by the FIXTRN utility. See "Notes" for other differences between AMOS and A-Shell relating to the function keys.

To create or edit either style of function key translation table, use one of the following command forms:

FIXTRN

FIXTRN <extension>

FIXTRN <name>.PFK

The first form will create or edit LIB:xxxxx.IFX (where xxxxx is your current terminal driver name.)

The second form will create or edit LIB:xxxxx.<extension> where <extension> would normally be either IFX or VUX (but could be something else if your application was going to specifically request usage of another extension.)

The last form will create or edit the specified PFK-style function key translation file, loading it from memory or from the current PPN if it exists.

From that point, the FIXTRN utility works the same way in all cases. It first prompts for a special key to be used as a delimiter, then prompts you to enter a function key, after which it displays the existing translation (if any) and allows you to enter a new one. You can repeat that process for as many special function keys as you like. At the end, it writes out the new translation table and offers to update it in memory as well.

Notes

There is no particular limit to the length of a translation. The output of the translation is buffered and fed into successive input requests until it is all used up, after which the next real input character (or next translation) will be used.

See FIXTRN.LIT and LOAD.LIT for further details.

If your application does not use all of the function keys, and you want to program the unused ones to act as typing shortcuts, the recommended procedure would be to copy the standard IFX file to another name, using a PFK extension (e.g. COPY MYFUNC.PFK=AM62A.IFX). Then use FIXTRN to modify the desired function key translations. Finally, load and lock the PFK module into user memory at the start of your A-Shell session (e.g. LOAD MYFUNC.PFK /LOCK). The alternative would be to simply modify the standard IFX file, but that runs the risk of it being overwritten during a subsequent update.

Unlike the case under AMOS, PFK translations do not deactivate all IFX translations. Instead, the PFK and IFX translation tables are additive, assuming both are loaded into memory. The PFK takes precedence, but if a key is not defined to the PFK, then the IFX translation will still be active. The idea here is to allow you to add your own function key translation customizations or extensions, but still be able to take advantage of any updates to the IFX tables for those keys which you have not customized.

Subtopics

Standard IFX Translations


Standard IFX Translations

The "standard" IFX file maps the function keys to sequences starting with Ctrl+G (^G) and followed by Ctrl+A for F1, Ctrl+B for F2, etc, as shown in the table below (which should be used as a guide when setting up or verifying an IFX file):

Key | Translation | Key | Translation
F1 | ^G^A | Shift F1 | ^G^Q
F2 | ^G^B | Shift F2 | ^G^R
F3 | ^G^C | Shift F3 | ^G^S
F4 | ^G^D | Shift F4 | ^G^T
F5 | ^G^E | Shift F5 | ^G^U
F6 | ^G^F | Shift F6 | ^G^V
F7 | ^G^G | Shift F7 | ^G^W
F8 | ^G^H | Shift F8 | ^G^X
F9 | ^G^I | Shift F9 | ^G^Y
F10 | ^G^J | Shift F10 | ^G^Z
F11 | ^G^K | Shift F11 | ^G^[
F12 | ^G^L | Shift F12 | ^G^\
F13 | ^G^M | Shift F13 | ^G^]
F14 | ^G^N | Shift F14 | ^G^^ (Ctrl+G, caret)
F15 | ^G^O | Shift F15 | ^G^_ (Ctrl+G, underline)
F16 | ^G^P | Shift F16 | ^G (Ctrl+G, space)
Page Up | ^R | Shift TAB | ^G#
Page Down | ^T | Shift Left Arrow | ^G$
Insert | ^F | Shift Up Arrow | ^G%
Delete | ^D | Shift Right Arrow | ^G&
Home | ^^ (Ctrl+caret) | Shift Down Arrow | ^G' (Ctrl+G, apostrophe)

INFLD (the input routine which uses the IFX translation file) uses these sequences to identify the function key, and then will return a code to the calling application allowing it to decide on the proper action to be taken. (Applications often reuse function keys for different purposes in different contexts.)

Note that most PC keyboards do not have F keys going beyond F12. However, most terminal emulation software packages provide an alternate key sequence to simulate the missing keys. Consult your terminal emulation documentation for details.


Input Line Editing

A-Shell, like AMOS, supports two similar but distinct input modes, known as "line mode", and "image mode". In line mode, the operating system is in charge of the details of keyboard entry, passing an entire line to the application after the user hits the line termination key (typically Enter). In image mode, the application is fully in charge of input, processing each character as it is typed.

In the UNIX world, line mode is typically known as "canonical" (or "cooked") mode, and "image mode" is known as "raw" mode. So much for terminology standardization.

As a technical aside, in actuality all input within A-Shell is in image (or raw) mode, from the operating system’s perspective. A-Shell itself then simulates line mode based on the application context.

Although line mode and image mode are not easy to distinguish from the user’s point of view, the important distinction is that in line mode, you have the ability to recall prior lines of input using Ctrl+R (sometimes mapped to the Page Up key). This is particularly useful when working at the dot prompt, since it is common to have a typo in a complicated command cause the command to be rejected. Rather than re-typing the entire command line, you can hit Ctrl+R (or the Page Up key), and then use the line editing keys to correct the mistake. You can also hit Ctrl+T (or Page Down) to cycle forwards through the last several command lines entered.

Subtopics

Line Editing Commands


Line Editing Commands

The following line editing commands work in almost every input context (line mode or image mode). The only exceptions would be in certain custom image input routines. (Since image mode puts the burden of processing these line editing commands on the application itself, unless the application is using the INFLD routine internally, it is possible that it hasn’t implemented these commands.)

Command | Action
Rt Arrow or Ctrl+L | Move the cursor one character to the right
Lf Arrow or Ctrl+H | Move the cursor one character to the left
Down Arrow or Ctrl+J | May terminate the current field and move to the previous field. (This is highly application dependent.)
Up Arrow or Ctrl+K | May terminate the current field and move to the next field. (This is highly application dependent.)
Ctrl+A | Move the cursor to the start of the previous word
Ctrl+B | In a multi-line editing context, this will break the current line at the cursor, moving the remainder of the line to the next line (and shifting everything else down one line.) At the start of a line, this would simply insert a blank line. (Heavily application dependent.)
Ctrl+D or Delete | Delete the character under the cursor
Ctrl+E | In some programs, this will abort the current entry operation or mode
Ctrl+F or Insert | Insert a space at the cursor (shift rest of field to the right)
Ctrl+G | Start of pseudo function key sequence. In most programs, Ctrl+G followed by 1 will simulate the F1 key; Ctrl+G followed by 2 will simulate the F2 key, etc., thru F9. Ctrl+G followed by A will simulate F10, Ctrl+G followed by T will simulate F20, etc.
Ctrl+I or TAB | TAB may terminate the current field and move the cursor to the next field. (This is highly application dependent.)
Ctrl+M | Same as Enter.
Ctrl+N | Move cursor to end of field.
Ctrl+O | In a multi-line editing context, this would be the opposite of Ctrl+B. It concatenate the next line to the end of the current line, bringing all the other lines up by one. (Heavily application dependent.)
Ctrl+P | Take a picture of the current screen. Depending on the configuration of the PRINTER statement in the miame.ini, this may display a pop-up dialog box with options or just send the picture to the designated printer.
Ctrl+Q | Toggle insert/replace mode.
Ctrl+R or Page Up | In line mode, this will recall the previously entered line. In image mode, it may do nothing, or it may terminate the current field, sending a message to the application that you want to go back to a previous screen. (Heavily application dependent.)
Ctrl+T or Page Down | In line mode, this will recall the subsequently entered line (after having used Ctrl+R one or more times). In image mode, it may do nothing, or it may terminate the current field, sending a message to the application that you want to go forward to the next screen. (Heavily application dependent.)
Ctrl+U | Move the cursor to the beginning of the current line or field.
Ctrl+V | Delete the word starting from the cursor.
Ctrl+W | Move the cursor to the next word.
Ctrl+X | Toggle capitalization of the current word (or may have an alternate, application-defined meaning).
Ctrl+Y | Erase from the cursor to the end of the current field or line.
Ctrl+Z | Erase the current field or line. In a multi-line context, this would delete the current line, moving the subsequent lines up.
Ctrl+[ or ESC | Typically aborts the current input operation. (Very application dependent.)
Ctrl+\ | Displays the INFLD TYPE codes and other "about" info on the bottom line.
Ctrl+Shift-Underline | May recall the original value of the current field (after mistakenly editing it.)


Error Messages

This section contains an alphabetic list of the most common error conditions and messages that can occur, or be displayed by A-Shell, along with explanations and possible causes. Note that most of these messages are stored within the SYS:ERRMSG.<lan> and thus are subject to change (particularly likely if <lan> is not "USA"). Also see the troubleshooting topic in Printer Configuration for printer-related troubleshooting tips.

Subtopics

A-Shell ?-node license already in use

A-Shell out of memory

A-Shell partition too small for file buffers

Access Denied

BIOS computer name required for ?-node network license

Cannot create instance

Cannot open A-Shell queue system

Compiler reports an absurd number of syntax errors

Compiler reports many errors; how do I stop display?

Cannot open company name file

Configuration file not found

Ctrl+S and Ctrl+Q do not work (to stop scrolling)

Disk is full; what can I erase?

Ersatz definition file not found

Ersatz device specification is not formatted properly

Form feed problems (too many or too few) while printing

File specification error

Illegal command in MIAME.INI

Incompatible version of qflock; remove after all users exit

Infinite loop corruption in A-Shell queue system

Language definition file not found

License does not match operating system version

JOBTBL Full! (Increase MAXJOBS setting in miame.ini.)

Msg #,# (sys:<filename>)

Operating in demonstration mode

Out of memory

Out of queue blocks

Printer not defined to workstation

Printing problems under Linux

Print spooling with PREFIX, SUFFIX or AUTOFF doesn't work

RUN file format bad or incompatible

Security key is invalid

Specified job name <job> already exists

Stack Overflow

String Overflow

This update of A-Shell not covered under your license

Too many sessions originating from same source address!

Unable to load <name> control

Unable to initialize ODBC environment

Warning: instance already exists for [??????] - over-writing

Warning: maximum no. aliases exceeded

Warning: maximum no. ERSATZes exceeded

Warning: nested include statements not permitted

Warning: standalone mode for network license disables locking

Windows printer [ptrname] not defined to this workstation

Window instance exceeds the limit defined in your config file

Write protected error (BASIC Error 24)

Your job queue has been zapped; exit A-Shell now


A-Shell ?-node license already in use

A-Shell when used on PC networks or UNIX is licensed on a per-node basis. The number of simultaneous users allowed is dependent on the security key used to install A-Shell. This error will be displayed if a new node attempts to start an A-Shell session and all node licenses are already in use. Contact your dealer or MicroSabio to purchase additional licenses.

In some cases, node licenses can be used up by jobs that no longer exist, but which failed to exit gracefully. The first step in diagnosing this problem is to use SYSTAT to display the list of jobs logged into A-Shell. Under UNIX, SYSTAT will identify and flag "phantoms" and "zombies". (Phantoms are jobs that are logged into A-Shell but which no longer exist at the OS level. Zombies still exist at the OS level, but they are in a nether state between life and death, and need to be helped into the digital afterworld.) SYSTAT/K/Z will automatically remove them, freeing up the node licenses used by them.

Under Windows, it is more difficult to identify jobs which no longer exist. If you can't recognize them directly, one technique would be to use the JSTAT command. If the job is not responding, it will display [time out] on its status line while querying the job. JSTAT.LIT also reports what the job was last doing, whether it is executing any commands, keyboard operations, etc., all of which can help you identify jobs that are no longer running.

You can remotely abort a job that is stuck in some kind of an unresponsive state using the KILL command with the /K switch. If that doesn't work, or if it doesn't succeed in freeing all of the resources left by the job, you can use the QUTL command ("ZAP" option).

The ABOUT command will display information about the number of jobs in use and node licenses used up, which can help you evaluate if you are making any progress with the above techniques.

In small systems, or if all else fails, the simplest approach may be to just ask everyone to exit from A-Shell, and then manually erase the JOBTBL.SYS and QFLOCK.SYS files which are found in the same directory where the miame.ini file is (typically /vm/miame or C:\VM\MIAME). These files are automatically removed by the last user to exit (provided no one crashed without exiting properly), and they are automatically re-created as needed. Some sites insert an erase command for these files into the boot process for the server, so that you can be sure of having a clean job table after a hard reboot.


A-Shell out of memory

This error is displayed on entering A-Shell, and is distinct from the AlphaBASIC-type ?Out of memory error. A-Shell was unable to allocate a partition of the size requested by the MEMORY command in the A-Shell configuration file from the available operating system memory. This partition is used as A-Shell’s workspace, but unlike under AMOS, it is not used to load programs. (Programs are loaded in dynamically allocated memory.) Under Windows and UNIX, it is unlikely that you will ever see this message. If you do, then the chances are that the machine really does require more physical memory (or that your MEMORY command is crazy.) Note that you can dynamically change the size of your memory partition with the MEMORY.LIT command.


A-Shell partition too small for file buffers

In order to keep track of open files, A-Shell maintains a number of internal buffers, and additional buffer space for ISAM 1.0 files. The number of these is specified with the FILES command in the A-Shell configuration file, and they are allocated within the A-Shell memory partition. The size of the A-Shell memory partition is given by the MEMORY command in the configuration file. If this error appears, either increase the size of the memory partition, or reduce the number of data and ISAM buffers required.


Access Denied

If you get this error during an attempt to write to a file (and/or your program aborts with Error 24), then see "Write protected ." . If you get an "Access Denied" pop-up error message when printing to a Window shared printer, you may need to create a local port which points to the network device. To do this, use the Add Printer wizard, select Local Printer (not network), then choose the option to add a local port, and enter the printer’s network share name (e.g. \\server\printer).

In general, this error indicates (rather obviously) that you do not have sufficient privileges to perform the specified action. Both UNIX and Windows (under the NTFS file system) have mechanisms for assigning access privileges to files, programs, directories and other resources. Consult your operating system documentation, and also Installation for further details.


BIOS computer name required for ?-node network license

When running on a PC network, A-Shell needs a unique identifier to individually identify each PC on that network. For this purpose, it makes use of the NetBIOS computer name. This error will result if the NetBIOS computer name is not set on a PC in a networked environment. In NetBIOS or NetBEUI technology networks (including most Windows networks), this name is set automatically.

The one big vendor not using the NetBIOS computer name is Novell. There are three techniques for setting the name for Novell networks. The first depends on the client technology you are using (NETX, or ODI, or MSIPX and NDIS, and so on), but it can be possible to specify the name in the workstation’s net.cfg file. The second works for clients running W95 or higher and consists of adding the Client for Microsoft Networks to your network stack. The third technique is to set the MACHINE environment variable in the server’s system login script. This will need to be set differently for each workstation, which may be done in the same script by testing values of PSTATION, which will contain the hardware Ethernet or Token Ring addresses. More information is available in Installation, and in the Novell documentation.


Cannot create instance

This error indicates that A-Shell is not able to add a record to the JOBTBL.SYS file, which is normally created and managed in parallel to the QFLOCK.SYS file (whose location is specified in the QUEUE command of the miame.ini configuration file). The most likely problem is that you don’t have sufficient user privileges to write to the file (or to create the file by writing to the directory), or that the file has become inaccessible due to some network problem. If you can’t fix the privilege problem directly, then the best solution may be to ask everyone to exit A-Shell, and then erase both JOBTBL.SYS and QFLOCK.SYS. They will be recreated automatically by the next user to launch A-Shell.


Cannot open A-Shell queue system

The queue file specified in the QUEUE line of the A-Shell configuration file could not be opened. Full read/write access permission is required by all users of A-Shell both to the directory in which this file resides, and to the file once it is created. Note that in addition to the queue file (normally qflock.sys) there is also a file called jobtbl.sys which is created and managed in parallel with qflock.sys. See notes for Cannot create instance above.


Compiler reports an absurd number of syntax errors

There are two common causes of this. The first is that you are using COMPIL or COMPLP on a program that contains ISAM 1.0 statements. Since these two variations of the compiler assume by default that the only ISAM is ISAMPlus, they will complain about every ISAM statement. You can solve that problem by either using OCMPIL, or adding the /I switch to COMPIL or COMPLP. Note that all three of these LIT files are identical, but work differently by looking at their own name. Thus, renaming OCMPIL to COMPIL does not work. However, if you prefer to use the command COMPIL but have it act like OCMPIL, the trick is to erase COMPIL.LIT and instead make a COMPIL.DO[2,2] that executes OCMPIL.


Compiler reports many errors; how do I stop display?

Since the operation of ^S and ^Q is dependent on various operating system settings and thus may not be operational within A-Shell, the best way to stop the compiler (or any other scrolling display) is to use the PAGE utility. For example:

.PAGE COMPIL MYPROG

This will cause the display to stop and wait for you to hit Return (or Q to quit) after each screen full.


Cannot open company name file

The company name file specified in the CONAME line of the A-Shell configuration file could not be opened. If A-Shell is being run for the first time, then it will be attempting to create the file, so ensure that you have file write access to the directory. If A-Shell is not being run for the first time, then check that the file exists and that you have file read access to it.


Configuration file not found

The A-Shell configuration file (usually miame.ini) could not be found. Ensure that the environment variable MIAME has been set correctly, or that the correct path has been specified with the -i switch to A-Shell.


Ctrl+S and Ctrl+Q do not work (to stop scrolling)

See Compiler reports too many errors to see (above).


Disk is full; what can I erase?

The first file to check is OPR:SPOOL.LOG), which contains a log of every print request made (since the file was last erased) and which can grow rather large rather quickly on systems that do a lot of spooling. You should arrange for a daily or weekly procedure to erase that file. (As of the 4.7 release, the SPOOL.LOG file will be automatically archived when it reaches 3MB. Up to 4 archived copies – SPOOL.001 thru SPOOL.004 will be kept, with the oldest erased to make room for the newest.) Another A-Shell log file which can be erased (assuming of course that you don’t care about the contents) is ashlog.log which will be found (assuming it exists) in the same directory where miame.ini resides. (This location may be overridden by the LOGDIR statement in the miame.ini file.) (It also gets archived up to 4 times as just described for SPOOL.LOG. Beyond that, obviously you need to look at the temporary files created by your application. If you are running under UNIX or Linux, you can get a quick overview of how full the filesystems are with the df –v command (e.g. .HOST df –v), although SYSTAT will also show how many blocks are available in the filesystems used by your logical devices. (Note that running out of disk space in the root filesystem of a UNIX machine is something you want to avoid at all cost, thus it is very wise to put your application in a separate filesystem so that at least it will never cause the OS to crash just because your program goes crazy producing output.) If df –v indicates a full filesystem but you can’t figure out which files are responsible, try using the UNIX du utility to list the size of each directory. (Since there are many, you may want to pipe that to a file and then sort it so you can narrow down your search.)


Ersatz definition file not found

This is displayed on entering A-Shell if the subject of an ERSATZ command could not be found. Check that the file exists and that you have file read permission in order to access it.


Ersatz device specification is not formatted properly

An ERSATZ definition line in one of the files specified by an ERSATZ command is not in the correct format. The correct form is:

OPR:=DSK0:[1,2]

or

OPR2:=DSK0:

The usual cause is that one or both colons have been omitted. Note that the CPU number field for networked Alpha Micros is not supported.


Form feed problems (too many or too few) while printing

Under UNIX, these are generally caused by printer filters that have their own inscrutable logic for form feed generation. When all else fails, you can take matters into your own hands by configuring the printer to use a filter that outputs absolutely NO trailing formfeeds under any circumstances. For SCO, we supply one on our web site called ‘dumbnoff’ which you can copy to your printer interfaces directory (/lp/spool/lp/model). Then, add AUTOFF=ON to your A-Shell printer INI file. This will cause A-Shell to take over the job of adding a trailing formfeed when required by your spooler switches. Refer to the discussion on Printer Configuration for more details.


File specification error

This error can be generated by any A-Shell .LIT command program if a file specification was given on the command line that does not conform either to the AMOS file specification format or to the host machine pathname format. See Introduction to LIT Files and its subtopics for information on specifications for files and directories, etc.


Illegal command in MIAME.INI

The A-Shell configuration file contained an unknown command. Check the spelling of all commands, and that the commands themselves (to the left of the equal sign) are given in upper case.


Incompatible version of qflock; remove after all users exit

Occasionally a change is made to the queue system record layout to accommodate new information. When this happens, the queue version number is updated. Whenever an instance of A-Shell is launched, it checks its own latest queue version number against that version number of the qflock.sys and jobtbl.sys files which are actually in use, and if they differ, you get this message. As the current users exit, the last one out will erase the qflock.sys and jobtbl.sys files, assuming there are no phantom or corrupted records in it. If they do not go away even after you are sure all users are out, you can erase them manually.

If you want to test a new version of A-Shell without interfering with people running an older version, then you can always specify a different miame.ini file on the A-Shell startup command line. (See -i switch to A-Shell in Launching A-Shell in this document.) Within that miame.ini file you can specify a different name in the QFLOCK parameter.


Infinite loop corruption in A-Shell queue system

In theory, this error should never be displayed. However, it is possible for A-Shell to be fooled into thinking this is the problem when in fact the problem is insufficient privileges to write to the queue file. Check the privileges of the qflock.sys file (whose location is specified in the miame.ini QUEUE statement.) One scenario where the privileges prevent you from writing to it would be if the superuser created the file (i.e. was the first A-Shell user). If you cannot fix the privileges for the existing qflock.sys file, have everyone exit A-Shell, then manually remove the qflock.sys and jobtbl.sys files and then relaunch A-Shell.


Language definition file not found

This is displayed on entering A-Shell if the language file (usually with .LDF extension) could not be opened. Check that the file exists and that you have file read permission to be able to access it.


License does not match operating system version

A-Shell licenses are specific to a particular operating system. You would get this error if, for example, you tried to use an A-Shell/Windows license to run A-Shell/Linux. If you wish to migrate to another operating system, contact your dealer or MicroSabio to have your license converted. (There is a nominal charge for this.)


JOBTBL Full! (Increase MAXJOBS setting in miame.ini.)

The job table is a file called JOBTBL.SYS which is automatically generated whenever A-Shell is launched and the file is not already in existence. Its size is computed to allow for some reasonable multiple of the number of licensed nodes, but if you run a lot of jobs that do not count against the license (such as background jobs or PolyShell jobs), then the computed number may be insufficient. In that case, you can add a MAXJOBS=## statement (which see in the Configuration section) to the miame.ini file to specify a larger size. It is not normally necessary to get everyone out of A-Shell to make this effective – the next time A-Shell is launched it should detect the new size and expand the file.


Msg #,# (sys:<filename>)

This occurs when the message number (#,#) is not found in the message file whose name is in the (parentheses.) Usually this is because you updated the A-Shell executable but not the message files, and the new version of A-Shell is trying to use a new message that wasn’t previously there. In that case, just download the latest A-Shell release to get the latest message files. Another possibility is that the message file has become corrupted. To check, just VUE it and then resave it. A third possibility is that your language definition file is not right, and so A-Shell is trying to use a non-existent message file extension. If the <filename> mentioned in the message does not exist, check your LANGUAGE= statement in the miame.ini to make sure that it references a valid language definition file. If it is simply a matter of you using a language file that we don’t provide a set of messages for, copy one of the others (with the same filename and different extension) to the desired extension, and then you will at least have messages (although perhaps not in the desired language.) Feel free then to use VUE to edit the message file and translate the messages.


Operating in demonstration mode

This warning is displayed on entering A-Shell if demonstration mode is enabled. Thereafter a license warning banner will be displayed periodically explaining that you are breaking software licensing agreements and guilty of software theft if this copy of A-Shell is being used for any purpose other than demonstration or evaluation. Demonstration mode is enabled either if serial number of 0000 was entered during installation, if the wrong serial number/security key was entered, or if the contents of the company name licensee file specified with the CONAME command in the A-Shell configuration file has been changed. See Installation for information on entering a valid security key.


Out of memory

This is a standard AlphaBASIC-type error (BASIC error 3), and is distinct from the ?A-Shell out of memory error. It occurs when attempting to run a program which runs out of memory in the job's memory partition, the size of which is established by the MEMORY command in the A-Shell configuration file. You can also change the memory partition size dynamically with MEMORY.LIT.LIT or with the MX_MEMORY function.

The memory partition is used for a variety of purposes, including storing program variables, command files during execution, expression and function parameter stacks, and string manipulation. Since the RUN program itself is loaded into dynamically allocated memory, a large RUN file would not be directly responsible for out of memory. However, large RUN programs tend to have large numbers of variables, which will take up memory partition space.

Expressions involving manipulation of large string variables can consume a lot of memory and are a common cause of ?Stack overflow (BASIC error 33) or ?String overflow (BASIC error 54).

Dynamic Arrays (DIMX) operations do not use the memory partition. If you receive an out of memory error in a DIMX statement, it is because the operating system is unable to provide the requested amount of memory at that point in time; increasing your memory partition size will not help—and may make it worse by effectively taking that memory out of the system pool.

You use the MEM(0) function within a running program to monitor the amount of memory available in the memory partition.


Out of queue blocks

"Queue blocks" (which are actually records in a shared file called qflock.sys) are used primarily by FLOCK.SBR and XLOCK.SBR, and some developer-specific variations of them, as a scheme of keeping track of, or controlling access to, shared resources (e.g. record and file locks). If you are running out of them, either the qflock.sys file is too small, or your application is not freeing up the queue blocks that it uses.

The size and location of the file is defined by the QUEUE statement in the miame.ini. The file is automatically created when the first A-Shell user starts up, and automatically deleted when the last user logs out. That system can be foiled by "phantom" jobs that never log out. If such is the case, and particularly if one of those phantom jobs has allocated queue blocks and never released them, you need to either remove the phantom jobs, manually clear the locks from the qflock.sys, or get all the real users out and then erase both qflock.sys and jobtbl.sys (which will be in the same directory).

Comments and debugging suggestions:

• ABOUT will show you which miame.ini file you are using.

• VUE %MIAMEFILE% will allow you see and edit the current miame.ini file (to determine where the qflock.sys file is, and possibly to increase its size). Note however, that any changes to the QUEUE statement will not take effect until all users have exited and the existing qflock.sys is deleted.

• QUTL has options to display the queue block usage, both in the form of summary totals, and in detailed lists of the locks by type and by user. It also has an option to "zap" a user (remove the user from the system and release the locks held by it). This is one way to get rid of "phantom" jobs.

• SYSTAT/W will display how long each job has been logged in. This is useful for identifying jobs that have been abandoned (i.e. anything over 24 hours might be suspect, at least for a normal, non-background job).

• See XLOCK.SBR and FLOCK.SBR and ABOUT.LIT, SYSTAT.LIT, and QUTL.LIT.

• If you suspect that an application is not freeing the locks that it requests, one way to study it would be to activate the XCALL trace (with SET TRACE XCALL ON or by opening the debug message window and using the properties dialog). This will trace all of the XCALL statements, which would allow you to see just what an application is actually doing in terms of requesting and releasing locks.


Printer not defined to workstation

See Windows printer [ptrname] not defined to this workstation.


Printing problems under Linux

Linux systems are often configured by default to use the "ghostscript" printer filter, which is often too smart for its (or our) own good. Some things that can throw it into a spin are print files whose final line does not have an LF on the end, or files with embedded escape sequences. The best way to solve these problems is to change your printer configuration (under Linux) to use a null (or text or raw) driver.


Print spooling with PREFIX, SUFFIX or AUTOFF doesn't work

Operations > Error Messages

Print spooling with PREFIX, SUFFIX or AUTOFF doesn’t work

One possibility is that you do not have sufficient privileges to write to the directory where the miame.ini file (or its subdirectories.) The above spooling options cause temporary files to be created in that directory, and if the directory cannot be written to, the operation will fail. Other suggestions are to use the .SET TRACE LP ON command to display detailed information about the various steps involved in printing (possibly clarifying where it is failing) and to look at the OPR:SPOOL.LOG) file to see if it contains any useful error messages.


RUN file format bad or incompatible

2011 August, A-Shell 5.1.1228: Improved handling of "RUN file format bad or incompatible" error: the first time this error occurs, the module is re-loaded from disk. If it happens again, then the error is reported. This helps eliminate rare situations where an updated SBX gets loaded before it is full written to disk, or where some other mishap has caused the copy of a program in memory to become corrupted even though the one on disk is good. Such events are always logged though.


Security key is invalid

The security key is stored on the first line of the miame.ini file. The format of the line is:

SERIAL=####kkkk-kkkk-kkk-kkkkkk-kkkkkkkk ;comment

#### is your serial number and the kkk… represents your security (or license) key.

The most likely cause of this error is that the line has become corrupted, due to either manual editing or some other mishap. It is also possible that the CONAME file (referenced by the CONAME statement in the miame.ini file) has changed, since its contents are tied to the security key. If you have your original license key written down, you can re-enter it (from the dot prompt) using the LICENS command. Note that if your miame.ini file appears corrupted, you may need to first manually clean it up before it can be properly updted. To do this, use your favorite text file editor and set the first line to:

SERIAL=0999NXXXXXXXXXXXXXXXABCD ; license key

Make sure to include several spaces between the ABCD and the semicolon.


Specified job name <job> already exists

This could occur for one of three reasons. The first is that you are specifying a job name via the -j switch to A-Shell (or PolyShell). The second is that you are using TRMDEF statements in the miame.ini to assign job names, and A-Shell is not generating "unique enough" device identifiers (possibly due to an incorrect CONSOLE statement.) The third is that the specified job has partially crashed but still exists in the job table. Under UNIX, A-Shell will prompt you directly to see if you want to kill the conflicting job, which usually takes care of the problem. Alternately, you can have another user (who is already in A-Shell and can get to the dot prompt) execute SYSTAT/K/Z to clear any zombies or phantoms. Under Windows, this is not possible, but you can still have another user remove the dead job with the QUTL command. Or, you can just specify the -j switch with a known-unique job name.


Stack Overflow

Reviewed January 2009

This is equivalent to BASIC Error 33, and is a special case of the more general Out of memory error.

The A-Shell stack occupies the free memory space within the user partition, and is used for local variables (within functions and procedures) as well as for working copies of variables involved in expression evaluation. The error is typically caused by one of the following three conditions:

· The memory partition is simply too small to accommodate the program. In this case, it is equivalent to the Out of memory error; in fact, the same situation might result in either error, depending on whether the lack of memory is noticed at the start of a BASIC instruction or in the middle of it.

· You've exceeded the number of open files defined by the FILES system parameter statement.

· The program has an infinite recursive loop (such as a function that calls itself). The only solution for this is to fix the logic error.


String Overflow

String overflow (BASIC error 54) is similar to Stack Overflow and occurs when there is insufficient memory in the job's memory partition to handle an expression or operation involving large strings. See the discussion of the more general Out of memory error for further information.


This update of A-Shell not covered under your license

This error will occur if you update your copy of A-Shell with a version that was released after the maintenance expiration embedded in your license key. To check your maintenance expiration before downloading an update, you can use ABOUT.LIT from the A-Shell command prompt, or in the case of Windows, you can also display the Help...About dialog box. The release date of the update will be displayed on the web page along with the update file.

Note that the maintenance expiration does not limit you from running your currently licensed version of A-Shell. It only prevents you from running a new version generated after the maintenance expiration. To avoid this problem and gain access to all updates, at all times, contact your dealer or MicroSabio to renew the maintenance on your license annually.


Too many sessions originating from same source address!

This message may occur with ATS (A-Shell Telnet Server) and indicates that you have too many open sessions originating from the same device, or sharing the same IP address. ATS is somewhat more flexible that other A-Shell versions in allowing multiple sessions to share a single node license if they originate from the same device, but since this could be abused by running many terminals through a single terminal server or other proxy service, there is a limit (typically about the same as the number of licensed nodes.)


Unable to load <name> control

Added December 2012

A-Shell loads a number of DLLs dynamically as needed to implement certain control types (XTEXT and XTREE being two examples). The search path for such DLLs starts in the directory where ashw32.exe was loaded from (typically c:\vm\miame\bin), and this is where we keep all of the DLLs released with A-Shell (so as to avoid conflicts with other applications which may be using different versions of the same DLLs). When A-Shell encounters an error loading one of its DLLs, it will make a second try to load it from an alternate location:

C:\Program Files (x86)\Common Files\A-Shell\ (64 bit systems)

or

C:\Program Files\Common Files\A-Shell\ (32 bit systems)

This directory does not normally exist, so the second try will not have any effect unless you set it up. The only reason why you would do such a thing is if you are experiencing the rare error condition where it reports that the DLL cannot be loaded because it is in use. Most likely the cause would be some antivirus software, or backup software or something else on the system that is gaining exclusive use to the library long enough to block other users. But if the cause cannot be resolved directly, you can work around it by creating the alternate directory above and putting a second copy of the affected DLLs into it.

History

2012 December, A-Shell 6.1.1326: Added alternate paths to search sequence


Unable to initialize ODBC environment

This error only applies to A-Shell for Windows when it has been linked with the ISAM Plus to ODBC interface. The ODBC manager has not been installed correctly on the workstation. In order to install ODBC, use Microsoft’s ODBC administration programs, ODBCADM.EXE, or ODBCADM32.EXE. Test access to the SQL data source using Microsoft Query.


Warning: instance already exists for [??????] - over-writing

A-Shell stores user information for each session or instance of A-Shell in the JOBTBL.SYS file. This warning means that an entry already exists in the queue file with the same unique identifier as the one now being used. The most common cause of this is that your last session of A-Shell ended in an unclean manner, for example if the PC crashed or hung in a network situation. In these cases, the message is for information only, and can be ignored. If the warning persists, or recurs regularly when all sessions end cleanly, then the unique identifiers need to be checked. Under UNIX, check the CONSOLE and TRMDEF commands for correctness. In a PC network situation, check that unique NetBIOS names have been assigned to each workstation. Also, attempting to use a standalone, 1-node license version of A-Shell in a networked environment will cause this error, and A-Shell will fail.


Warning: maximum no. aliases exceeded

This is displayed on entering A-Shell if too many subroutine aliases have been defined in the configuration file, miame.ini, with the ALIAS command. Aliases up to the offending one will function correctly. The number of aliases will have to be reduced, or some of the routines re-coded in C.


Warning: maximum no. ERSATZes exceeded

This is displayed on entering A-Shell if too many ERSATZ devices have been defined. ERSATZes up to the offending one will function correctly. Remove some ERSATZ file references completely from the configuration file, or try to create some cut-down ERSATZ files which contain only the devices really needed. As of version 4.7, the maximum number of ERSATZ specifications is 400 for Windows/32 and UNIX.


Warning: nested include statements not permitted

This is displayed on entering A-Shell if a file which is the subject of an INCLUDE statement itself attempts to include another file. Restructure the files so that only one level of inclusion is used.


Warning: standalone mode for network license disables locking

This is displayed on entering A-Shell purely as a reminder. The copy of A-Shell has been installed with a multi-node network license, but has been forced to run in standalone mode with the -s command line switch. This will disable multi-user functions such as locking, but temporarily disables the need to set a NetBIOS computer name.


Windows printer [ptrname] not defined to this workstation

This can mean one of two things. Either the application attempted to print a file to the explicitly named printer [ptrname], and no printer init file (either sys:ptrname.ini or ashcfg:ptrname.pqi) was found, or the printer init file was found, but the DEVICE name it specifies does not match any of the printers known to Windows on this workstation. Note that the reason these two cases report the same error message is that if the printer init file is not found, A-Shell auto-defines one on the fly, with DEVICE=[ptrname]. (This feature eliminates the need for printer init files in many cases.) If unclear why the printer [ptrname] does not match any of the defined printers on this workstation, refer to Troubleshooting Techniques in the Printer Configuration section.


Window instance exceeds the limit defined in your config file

This would occur if the number of A-Shell sessions you have running on your PC exceeds the limit specified by the MAXINST statement in the miame.ini file. Try increasing that, or closing some of you’re A-Shell windows.


Write protected error (BASIC Error 24)

This error (or a variation of it, such as "Access Denied") will occur if you do not have write permission for the file or directory you are trying to write to. One cause of this is copying files from a CD. (Files on a CD often have the read-only attribute set, and some methods of copying files under Windows may not clear that bit.) If there are just a few files affected, then you can fix them (under Windows) by locating them in Explorer, right clicking, and clearing the read-only check mark. This is not convenient if you have many files with the problem. In that case, open a Command Prompt (aka "DOS") window, use the CD command to change to the proper directory, and use the ATTRIB –R command. (This will clear the read-only flag on all the files and subdirectories within the current directory.) Repeat this for all the affected directories.

If the problem occurs under UNIX/Linux, then login in as root (or use the su command), cd to the relevant directory, then use chmod –R +w * (or some variation of the chmod command, such as chmod 666 to reset the privileges for one or all of the affected files. Refer to File Ownership and Privileges in Installation for further information.


Your job queue has been zapped; exit A-Shell now

Reviewed January 2009

Short version

This occurs when someone deletes the qflock.sys and/or jobtbl.sys files (or at least clobbers your entry within the latter, perhaps with the QUTL command) while you are running. A-Shell does not notice the problem until it has reason to update the queue (such as when chaining between programs or logging to a new ppn.) If this problem happens every time you launch a second session, then the problem is most likely that A-Shell is not able to generate a unique device identifier due to a problem in your CONSOLE statement in miame.ini.

Long version

The message indicates that another job has overwritten the current job's job-control-record. (Each job has a record in the JOBTBL.SYS file where it stores a variety of current status information about the job; this is the primary source of information used by SYSTAT, JSTAT, and most XCALLs that request information about a job.)

When a new instance is started, A-Shell generates a (hopefully) unique ID for the instance, then scans the JOBTBL to see if there is already a record for it (which happens when a workstation crashes or is rebooted without exiting A-Shell), if so, displays a brief warning message on the screen and in the log, and then re-uses the record.

You can see the instance identifiers using SYSTAT/C (3rd column). Generally they consist of 2 parts separated by a colon: an identifier of the workstation (like a machine name or possibly an IP address), plus an instance number (01, 02, etc.) to separate the instances of A-Shell coming from the same workstation.

For example:

.systat/n/c

Status of A-Shell/32 Ver. 5.1.1134.2 on Friday, January 09, 2009 15:22:26

TSKAAA TSKAAA JACKT400:01 DSK0:1,4 RN SYSTAT 2912 986K bytes

TSKAAB TSKAAB JACKT400:03 DSK0:150,277 RN MYDOC 5464 939K bytes

TSKAAE TSKAAE JACKT400:05 DSK0:150,277 ^C VUE 6892 1502K bytes

This shows 3 instances, all coming from the machine whose name is "JACKT400", and each with a separate instance # (01, 03, and 05).

In some particular environments, such as Terminal Server, or CGI, or when launching A-Shell sessions from another application, it may be necessary to ask A-Shell to add a numeric suffix (-###) to the machine name (and prior to the instance number) in order to prevent duplicates. There are two ways to accomplish this: add OPTIONS=NTTS to the miame.ini file, or add the -awts switch to the A-Shell launch command line.

Besides SYSTAT/C, the best tool for analyzing this problem is the ashlog.log file, provided you add TRACE=INOUT,SIGHUP,BASERR to the miame.ini file (which we recommend as standard procedure.) This will cause A-Shell to log an entry for each session started and ended, along with the ID name, job number, user login, and license utilization information.


APEX

Following is documentation on A-Shell's print preview and export-to-Excel subsystem.

Introduction

A-Shell Preview and EXport ("APEX") is a built-in component of A-Shell for Windows and ATE. At the user’s option or under program control, APEX receives a print file and re-directs it into a preview window. That window displays an image of the report and provides the user with various viewing options (zoom, multiple pages, single page, etc.). After previewing the report, the user may then print the report as it was originally intended to be printed (i.e., to the originally-specified printer), print it under user control (different printer, say, or landscape instead of portrait), or discard it. The purpose of the viewer, as with all such print preview functions, is to make sure that you are printing what you think you are printing—and to save time, energy, money and paper in the process. In some cases, viewing the report may eliminate the need for printing entirely.

APEX offers a variety of controls and options to facilitate viewing the report. Most of these items, and how to use them, are fairly obvious.

APEX also includes a valuable Export to Excel function, which is initiated by a button on the toolbar.

Following are some screen shots illustrating various aspects of APEX.

Title Bar and Tool Bar

The APEX title bar displays information about the report: original filename ("tstz" in this example), the first (-1) printing this session, temporary extension (.APF for "A-Shell print file"), the number of pages in the report, and Windows printer for which this report is intended, and the printer properties being used for printing. The toolbar provides options (in order from left) to set zoom percentage (10% to 999%); zoom in; zoom out; single page; multi-page grid (drop-down menu); page number / back / forward; print setup; print; help; close; print per application; find text (search); open another report; APEX preferences; export to Excel; export preferences.

Multi-Page Grid

Clicking on the multi-page grid option (see toolbar above) offers choices for the layout of multiple pages. You can (barely) see the grid choices below near the top left. The full screen shows the report in the 4 (across) by 2 (down) grid.

Find Text (Search)

Clicking the find text tool and entering a word into the "Find" dialog box ("exitcode" in this case) causes all the occurrences of "exitcode" on the current (first, in this case) page to be highlighted. Clicking "Find Next" displays the highlighted words on the next applicable page, etc.

Licensing

The programs and files needed by APEX are automatically installed on the PC with the underlying software (A-Shell for Windows or ATE). Starting from the date it is installed, APEX will work in unrestricted mode for approximately 30 days. After that free-trial period, APEX reverts to demo mode, which means that it will work so you can see its functionality, but with qualifications. When operating in demo mode, APEX will display an annoying message saying that it is in demo mode.

To enable full APEX operation on your PC, you will need to obtain an APEX software license from either your application provider/dealer or from MicroSabio.

Preferences

Several things about how the preview function behaves are under user control, and these things are set on the Preferences dialog. This dialog is accessible from both the menu bar in A-Shell/ATE (Settings | Preview Preferences) and from the Preferences button on the preview toolbar. The following screen shot, while not necessarily identical to the one shown in your version of the program, illustrates some of the user-controlled options.xe "Discard"

Preferences toolbar button:

Preview on Print

Normal report printing consists of a report being created by a program, and then being sent to the PC for printing. The "Preview On Print" option allows you, the user, to control the circumstances under which those reports from the host, received for printing, are instead displayed on your screen. The "Always" and "Never" options should be fairly clear. The two "Application Control" options allow you to let the program that created the report determine whether the report is previewed--and gives you the option to say what happens when the report program doesn't specify anything.

There is no right or wrong, or best or worst, setting for this option. It is strictly determined by (a) your needs and objectives, and (b) those of your work environment.

The default value for this setting is "Application Control, Default=Off", which means that (a) APEX is expecting to receive a launch or don't launch command from the program that generated the report, and (b) if it does not get such a command, it will NOT launch.

On Exit from Preview

What do you want to happen when you exit the preview window (which, by the way, you can do by clicking on the "X" in the top right corner of the preview window, or by hitting the Escape key)? As you make your choice, keep in mind that all reports viewed with APEX are saved to disk; you can come back and view them again later if you wish.

Preview Window State

It is not possible for the program that launched the preview, or the programmer who wrote the program, to know how the user wants to deal with the preview: display the preview windows right now, or continue working and view the report later? The Preview Window State allows the user to set her preference for what happens when a report is sent to the preview window. "Visible (Foreground)" means that the preview window is shown right now. "Minimized (Background)" means that the preview window is created right now but then minimized; it appears in the task bar, which you need to click in order to view the report.

Preview File Retention

When a file is viewed using APEX, it is possible that the user may want to view this file again later. So as soon as a report is viewed, a copy of it is written to a file in the APEX folder. If the original file name being viewed is "report.xxx," then the file that is written into the APEX folder is called "report.apf" (apf = A-Shell Print File). These files remain in the APEX folder, and can be opened by the Open another report file button on the toolbar.

How long do they remain in the APEX folder? This is controlled by a setting on the Preferences called "Preview File Retention (hours)." The default value is 96 hours, 4 days, but you can set it to whatever you wish.

From an environmental perspective, the fact that you can view the report again later should make it easier to forego actual printing of every document (after previewing), merely out of fear that you might need it reference it in a few hours or days. The default setting of 96 insures that your disk won't get clogged up with more than four days worth of report files.

Files Requiring Preprocessing

Files that require processing before they can be displayed include GDI print files (i.e., those contain graphical printing commands), files printed through ATE, and any files using the PREFIX or SUFFIX options.

Possible options: "Close all previews on exit?"

Option: Delete report files after we're done with them? (or let them sit)

Ctrl +/- zoom increment %

Export to Excel: save to disk?

Keystrokes and Mouse Clicks

Keystroke | Action
 | Multi-page Mode
Home | Positions to the first group of pages, starting at the first page. The first page becomes the current page. testing.
End | Positions to the last group of pages, ending at the last page. The first page of the displayed pages becomes the current page.
Control+Home | Same as the Home key.
Control+End | Same as the End key.
Left Arrow | Moves to the previous page. The displayed group of pages is adjusted if necessary.
Right Arrow | Advances to the next page. The displayed group of pages is adjusted if necessary.
Up Arrow | Moves the first page of the displayed group of pages to the previous page (or sheet in duplex mode). The current page is adjusted if necessary.
Down Arrow | Advances the first page of the displayed group of pages to the next page (or sheet in duplex mode). The current page is adjusted if necessary.
PgUp | Displays the previous group of pages. The current page is adjusted if necessary.
PgDn | Displays the next group of pages. The current page is adjusted if necessary.
Plus on NP | Zoom in. ("NP" refers to the numeric keypad.)
Left Click | Display page clicked in single-page view at scaling of last single-page view.
1 (numeric) | Switches from multi-page mode to single page mode.
 | Single Page Mode
Home | Positions to the top of the current page.
End | Positions to the end of the current page.
Control+Home | Positions to the top of the first page.
Control+End | Positions to the end of the last page.
Left Arrow | Horizontally scrolls left on the current page.
Right Arrow | Horizontally scrolls right on the current page.
Up Arrow | Vertically scrolls up on the current page.
Down Arrow | Vertically scrolls down on the current page.
PgUp | Vertically scrolls up on the current page. At the top of the current page, move to the bottom of the previous page.
PgDn | Vertically scrolls down on the current page. At the end of the current page, advance to the top of the next page.
Plus on NP | Zooms in . ("NP" refers to the numeric keypad.)
Minus on NP | Zooms out. ("NP" refers to the numeric keypad.)
Escape | Close
Left click | Zoom in. Same as "plus zoom" button.
Right click | Zoom out. Same as "minus zoom" button.
Ctrl+PlusKey | Zooms in 5%.
Ctrl+MinuKey | Zooms out 5%.
2 (numeric) | Switches from single page mode to multi-page mode.
 | Both Modes
Escape | Close
Ctrl+P | Print
Alt+Ctrl+P | Toggles between main window (A-Shell or ATE) and Preview.
Ctrl+Enter | Toggles between multi-page and single page modes.
Ctrl+Alt+ | Toggles between maximized and normal windows.
Ctrl+G | Go to page number control.
Ctrl+Z | Go to zoom control.
F1 | Help
F3 | Find

Operations

Zoom Percentage and Zoom In/Out

The Zoom Percentage control shows various steps of zoom. When you use the magnifying glass buttons to zoom in or zoom out, the steps by which you zoom are those shown in the zoom percentage control. You may manually set (by typing it in) the zoom percentage to any value between 10 and 1000. Note that when you are selecting a value for the zoom percentage control, and it has the focus, using the PageUp and Down key, as well as the up and down arrows, apply to the zoom percentage and not to the report being displayed. In other words, you can cycle through the zoom percentages by using those directional keys.

Find Text

This button on the toolbar will be grayed out (inactive) if the report being previewed does not contain any text—i.e., is all images and/or graphics. To initiate a text search, click on this button and enter the text to be found in the resulting dialog box.

Export to Excel

APEX includes an Export to Excel function which is initiated via a button of that name on the toolbar. There is also a button for setting the export preferences.

Print As Application Intended

This is rather an odd function to see in a Windows program, so a bit of explanation is in order.

Reports that are generated by A-Shell programs frequently are sent—by the report program—directly to a PC printer. In addition to the report, those print instructions include information for the printer, such as the name of the printer, number of copies, etc. However, APEX intercepts the report and (a) stops it from going directly to the printer, and (b) allows the user to now print the report using different parameters than the report program specified. Which is fine, and of course the user can print as he/she wishes.

But she might decide what she really wants, after looking at the report, is for it to be printed how the report program originally intended. Unfortunately she doesn't know what the report program intended; perhaps it was going to print six copies on a network printer called "Laser45."

By using this oddly-named button and function, the user can make sure that the report is handled and/or processed and/or printed as the original instructions intended.

If you do not need this function, just use the regular print operation.

Open another report file

See Preview File Retention in this document for information on what files may be opened and how they got here.

When you click this button, you will see a standard Windows file open dialog. Unfortunately, the list of file names that you see is probably not enough information to figure out what report it is you want to see. On the file open toolbar, you should see an icon near the top of the dialog box called Views, and one of its options is "details." If you click on the details icon, you should be able to see a little more information about the files. You may click on the column headers to sort by those columns in any effort to fine the report you're looking for. Unfortunately, not much information is available to you here, so you'll just have to open as many reports as it takes to find the one you're after.

Other Topics

Custom Extensions

You can add your own extensions to APEX, which are accessed as buttons on the toolbar and which call your own BASIC code, by defining them in the APEX configuration file, ASHCFG:APEX.CFG. The configuration file, if present, is scanned for commands of the following form:

BUTTON=prog, iconspec, tooltip {,msgno, inifile}

prog

indicates the subroutine which implements the extension. In theory it wouldn't have to be an SBX, but currently that is the only format supported, so prog must be in the form of "SBX:name", e.g. "SBX:PRTXLS". The corresponding subroutine (e.g. PRTXLS.SBX) must be in the BAS: directory (e.g. c:\ate\dsk0\007006\prtxls.sbx). The subroutine should be written according to the same interface specifications used by the printer initialization command line, COMMAND=SBX:... (see A-Shell Setup Guide).

iconspec

specifies the icon to display in the button that will be added to the toolbar. Supports the same syntax as for AUI_CONTROL icon buttons (see the A-Shell XCALL Reference).

tooltip

is a short tooltip to display when the mouse hovers over the button.

msgno (optional)

may specify a message number in the file <inifile.lng>, where lng is the current language extension, e.g. USA, to supply the tooltip text. If present, it overrides the tooltip parameter above.

inifile (optional)

may specify an initialization file used by the extension, although the details of how is is used are up to the custom code in prog.

The file may also contain any number of comment lines, each beginning with a semicolon in the first position. Here's , for example:

;APEX customization

;BUTTON=prog,icon,tip{,msgno,ini}

;If msgno>0, is expected to be msg 002,### in inifile.lng

BUTTON=SBX:PRTXLS,ashico1::document_out,Export to Excel,38,BAS:PRTXLS.INI

BUTTON=SBX:PXLCFG,ashico1::preferences,Configuration Options For Export,0,BAS:PRTXLS.INI

There are no particular limitations on what the subroutine (prog) may do, other than that it cannot delete or replace the file being previewed, and must eventually return so that APEX can resume control.

Debugging

In case of a problem launching the preview from ATE, use the debug message window to help clarify what is happening. Call up the A-Shell GUI Control Operations dialog with control+shift+double-right-click, then select Show Debug Dialog. When the debugging/trace window comes up, repeat the print attempt. It will log the command string that is actually being used, which might then be helpful to test independently, such as from Start..Run, or at least useful in identifying the problem.

Settings

In ATE, changes to Preferences are immediately stored with the connection profile in the Windows Registry. This means that they are both implemented immediately, and saved for future use; all subsequent operations of the preview window, whether in this session or new sessions, will reflect the latest settings.

In A-Shell/Windows, changes to Preferences are part of the overall A-Shell settings set which, along with the other options on the various Settings menu dialogs, are stored in the A-Shell settings (.ash) file. However, as with all other settings, changes made in the dialogs are not automatically written to the file. Thus, they only affect the current session. To make them permanent, you must save them via the File | Save option.

Files and Folders

The help file is called "apex.chm."

When you call up the Preferences menu, the actual words you see are taken from the file SYS:SBRMSG.USA. If you see odd codes in place of intelligible options, then your SBRMSG file is not being found.

Any temporary work files required by APEX are also created in the APEX folder.

The default location of the APEX folder is c:\apex, and this folder will be created the first time it is needed. If you don't like this folder and/or want it to be placed somewhere else, you may create an environment variable called "APEX" and point it wherever you wish.

Most of the print preview and display-related aspects of APEX are performed by a program module called "SftPrintPreview_###.dll" where "###" is platform and version information. This file lives in the main A-Shell or ATE folder on your PC.

Most of the export-to-Excel functionality is contained in the subroutine "prtxls.sbr." This file is found in DSK0:[7,6] of the A-Shell or ATE file system.

PRTXLS.INI Export Init File

Various operations and options in the export-to-Excel process are controlled by settings in the export initialization file, PRTXLS.INI. If this file is missing or an individual lines/statement is missing, APEX will use the value shown as "Default" in the table below. The init file is normally stored in the [7,6] directory or equivalent, although when PRTXLS.SBX is invoked from the COMMAND statement of a printer init file, the init file specification may be passed as an argument (e.g. COMMAND=SBX:PRTXLS,dsk7:xls123.ini[40,30]).

Note that each of the statements below must reside within the section indicated. Within a section, the order or presence/absence of a given statement is not relevant. The section names are in upper case, are enclosed in square brackets, and are preceded by a blank line. See the sample init file section.

As with many init files, lines beginning with semi-colons are comments and are ignored by the file processor. Comments can only occur on their own lines--i.e., cannot be appended to the ends of command lines.

Statement | Section | Values | Default | Description
IncludeTotals | DATA | 0,1 | 0 | If set, lines which look like totals or subtotals are treated as data lines.
IncludeBlankLines | REMNANTS | 0,1 | 0 | If set, blank lines are included in Remnants worksheet.
IncludeDupLines | REMNANTS | 0,1 | 1 | If set, duplicate lines are included in Remnants worksheet. (Otherwise only one line per set of duplicates is included.) For example, if set, the Remnants page may have many identical lines containing column headers.)
SortBy | REMNANTS | 0,1 | 0 | If set, Remnants lines are sorted by their contents.
BGcolor | ORIG | See sample init file | Silver | Background color of "Original" worksheet.
AppendSeqNo | POST | 0,1 | 1 | If set, a sequence number is appended to the XLS filename to make it unique.
SaveToDir | POST | Path specification |  | Directory where the XLS file is saved.
SendToPC | POST | 0,1 | 1 | (UNIX only) If set, causes the exported XLS file to be transferred to the PC using ATE/ZTERM FTP protocol.
Launch | POST | 0,1 | 1 | If set, the spreadsheet program (typically Excel) is launched to view the spreadsheet.
RemoteServer | POST | IP address: port | n/a | Specifies the location of a service to generate the XLS file. (Local generation requires that Perl be available and the WriteExcel add-on library be installed.)
IgnoreLocalServer | POST | 0,1 | 0 | Set to force use of RemoteServer even if local generation is available.
ServerErrorURL | MISC | URL |  | URL of page to display when an error related to the RemoteServer occurs.

Sample Init File

;PRTXLS.INI - Config file for PRTXLS.SBX

[DATA]

IncludeTotals=1

[REMNANTS]

IncludeBlankLines=1

IncludeDupLines=1

SortBy=1

[ORIG]

;BGcolor options: silver,white,red,lime,blue,yellow,magenta,cyan,brown,green,navy,purple,gray,orange

BGcolor=silver

[POST]

AppendSeqno=1

SaveToDir=c:\vm\miame\dsk0\150502

SendToPC=1

Launch=1

; RemoteServer spec is IP address, colon, port

RemoteServer=11.111.111.111:222

RemoteServer=63.199.106.102:39899

IgnoreLocalServer=1

[MISC];ServerErrorURL=http://

Troubleshooting Export to Excel

If the Export to Excel function does not work, either at all or properly, perhaps understanding the sequence of events will help you find and fix the problem.

Requirements: Perl has been installed on the host computer or PC, as appropriate. The report has been displayed with the A-Shell print preview function.

1. The Export to Excel button is enabled if and only if the A-Shell subroutine PRTXLS.SBX is present and available. It should be located in the directory [7.6]. If the Export to Excel button is inactive (grayed out), it is because this file is missing.

ATE only: the preview session of ATE (which itself is a second ATE session) launches another session of ATE to handle the export process. This job runs in the background and remains hidden except for the progress window.

2. PRTXLS.SBR creates a temporary working/debugging file called <sourcefilename>.XLX.

3. PRTXLS.SBR generates Perl script with the name <sourcefile>.PL.

4. PRTXLX.SBR executes PERL script. If the process breaks at this point, it is probably because the required Perl function "\spreadsheet\WriteExcel.pm" is not being found. This in turn may be because Perl is not installed, or because "\spreadsheet\WriteExcel.pm" is in the wrong location.

5. The Perl script runs and creates a spreadsheet file called <sourcefile>.XLS, which is placed in the xxx folder.

6. The temporary files (.XLX and .PL) are erased, and extra ATE session is shut down,

To assist in troubleshooting, you may want to use the debug function. To turn it on, check the "Debug" option on ATE's Connection Properties | Printer | General Options. If you are using A-Shell rather than ATE, get to the prompt and enter SET DEBUG.

Introduction

A-Shell Preview and EXport ("APEX") is a built-in component of A-Shell for Windows and ATE. At the user’s option or under program control, APEX receives a print file and re-directs it into a preview window. That window displays an image of the report and provides the user with various viewing options (zoom, multiple pages, single page, etc.). After previewing the report, the user may then print the report as it was originally intended to be printed (i.e., to the originally-specified printer), print it under user control (different printer, say, or landscape instead of portrait), or discard it. The purpose of the viewer, as with all such print preview functions, is to make sure that you are printing what you think you are printing—and to save time, energy, money and paper in the process. In some cases, viewing the report may eliminate the need for printing entirely.

APEX offers a variety of controls and options to facilitate viewing the report. Most of these items, and how to use them, are fairly obvious.

APEX also includes a valuable Export to Excel function, which is initiated by a button on the toolbar.

Following are some screen shots illustrating various aspects of APEX.

Title Bar and Tool Bar

The APEX title bar displays information about the report: original filename ("tstz" in this example), the first (-1) printing this session, temporary extension (.APF for "A-Shell print file"), the number of pages in the report, and Windows printer for which this report is intended, and the printer properties being used for printing. The toolbar provides options (in order from left) to set zoom percentage (10% to 999%); zoom in; zoom out; single page; multi-page grid (drop-down menu); page number / back / forward; print setup; print; help; close; print per application; find text (search); open another report; APEX preferences; export to Excel; export preferences.

Multi-Page Grid

Clicking on the multi-page grid option (see toolbar above) offers choices for the layout of multiple pages. You can (barely) see the grid choices below near the top left. The full screen shows the report in the 4 (across) by 2 (down) grid.

Find Text (Search)

Clicking the find text tool and entering a word into the "Find" dialog box ("exitcode" in this case) causes all the occurrences of "exitcode" on the current (first, in this case) page to be highlighted. Clicking "Find Next" displays the highlighted words on the next applicable page, etc.

Licensing

The programs and files needed by APEX are automatically installed on the PC with the underlying software (A-Shell for Windows or ATE). Starting from the date it is installed, APEX will work in unrestricted mode for approximately 30 days. After that free-trial period, APEX reverts to demo mode, which means that it will work so you can see its functionality, but with qualifications. When operating in demo mode, APEX will display an annoying message saying that it is in demo mode.

To enable full APEX operation on your PC, you will need to obtain an APEX software license from either your application provider/dealer or from MicroSabio.

Preferences

Several things about how the preview function behaves are under user control, and these things are set on the Preferences dialog. This dialog is accessible from both the menu bar in A-Shell/ATE (Settings | Preview Preferences) and from the Preferences button on the preview toolbar. The following screen shot, while not necessarily identical to the one shown in your version of the program, illustrates some of the user-controlled options.xe "Discard"

Preferences toolbar button:

Preview on Print

Normal report printing consists of a report being created by a program, and then being sent to the PC for printing. The "Preview On Print" option allows you, the user, to control the circumstances under which those reports from the host, received for printing, are instead displayed on your screen. The "Always" and "Never" options should be fairly clear. The two "Application Control" options allow you to let the program that created the report determine whether the report is previewed--and gives you the option to say what happens when the report program doesn't specify anything.

There is no right or wrong, or best or worst, setting for this option. It is strictly determined by (a) your needs and objectives, and (b) those of your work environment.

The default value for this setting is "Application Control, Default=Off", which means that (a) APEX is expecting to receive a launch or don't launch command from the program that generated the report, and (b) if it does not get such a command, it will NOT launch.

On Exit from Preview

What do you want to happen when you exit the preview window (which, by the way, you can do by clicking on the "X" in the top right corner of the preview window, or by hitting the Escape key)? As you make your choice, keep in mind that all reports viewed with APEX are saved to disk; you can come back and view them again later if you wish.

Preview Window State

It is not possible for the program that launched the preview, or the programmer who wrote the program, to know how the user wants to deal with the preview: display the preview windows right now, or continue working and view the report later? The Preview Window State allows the user to set her preference for what happens when a report is sent to the preview window. "Visible (Foreground)" means that the preview window is shown right now. "Minimized (Background)" means that the preview window is created right now but then minimized; it appears in the task bar, which you need to click in order to view the report.

Preview File Retention

When a file is viewed using APEX, it is possible that the user may want to view this file again later. So as soon as a report is viewed, a copy of it is written to a file in the APEX folder. If the original file name being viewed is "report.xxx," then the file that is written into the APEX folder is called "report.apf" (apf = A-Shell Print File). These files remain in the APEX folder, and can be opened by the Open another report file button on the toolbar.

How long do they remain in the APEX folder? This is controlled by a setting on the Preferences called "Preview File Retention (hours)." The default value is 96 hours, 4 days, but you can set it to whatever you wish.

From an environmental perspective, the fact that you can view the report again later should make it easier to forego actual printing of every document (after previewing), merely out of fear that you might need it reference it in a few hours or days. The default setting of 96 insures that your disk won't get clogged up with more than four days worth of report files.

Files Requiring Preprocessing

Files that require processing before they can be displayed include GDI print files (i.e., those contain graphical printing commands), files printed through ATE, and any files using the PREFIX or SUFFIX options.

Possible options: "Close all previews on exit?"

Option: Delete report files after we're done with them? (or let them sit)

Ctrl +/- zoom increment %

Export to Excel: save to disk?

Keystrokes and Mouse Clicks

Keystroke | Action
 | Multi-page Mode
Home | Positions to the first group of pages, starting at the first page. The first page becomes the current page. testing.
End | Positions to the last group of pages, ending at the last page. The first page of the displayed pages becomes the current page.
Control+Home | Same as the Home key.
Control+End | Same as the End key.
Left Arrow | Moves to the previous page. The displayed group of pages is adjusted if necessary.
Right Arrow | Advances to the next page. The displayed group of pages is adjusted if necessary.
Up Arrow | Moves the first page of the displayed group of pages to the previous page (or sheet in duplex mode). The current page is adjusted if necessary.
Down Arrow | Advances the first page of the displayed group of pages to the next page (or sheet in duplex mode). The current page is adjusted if necessary.
PgUp | Displays the previous group of pages. The current page is adjusted if necessary.
PgDn | Displays the next group of pages. The current page is adjusted if necessary.
Plus on NP | Zoom in. ("NP" refers to the numeric keypad.)
Left Click | Display page clicked in single-page view at scaling of last single-page view.
1 (numeric) | Switches from multi-page mode to single page mode.
 | Single Page Mode
Home | Positions to the top of the current page.
End | Positions to the end of the current page.
Control+Home | Positions to the top of the first page.
Control+End | Positions to the end of the last page.
Left Arrow | Horizontally scrolls left on the current page.
Right Arrow | Horizontally scrolls right on the current page.
Up Arrow | Vertically scrolls up on the current page.
Down Arrow | Vertically scrolls down on the current page.
PgUp | Vertically scrolls up on the current page. At the top of the current page, move to the bottom of the previous page.
PgDn | Vertically scrolls down on the current page. At the end of the current page, advance to the top of the next page.
Plus on NP | Zooms in . ("NP" refers to the numeric keypad.)
Minus on NP | Zooms out. ("NP" refers to the numeric keypad.)
Escape | Close
Left click | Zoom in. Same as "plus zoom" button.
Right click | Zoom out. Same as "minus zoom" button.
Ctrl+PlusKey | Zooms in 5%.
Ctrl+MinuKey | Zooms out 5%.
2 (numeric) | Switches from single page mode to multi-page mode.
 | Both Modes
Escape | Close
Ctrl+P | Print
Alt+Ctrl+P | Toggles between main window (A-Shell or ATE) and Preview.
Ctrl+Enter | Toggles between multi-page and single page modes.
Ctrl+Alt+ | Toggles between maximized and normal windows.
Ctrl+G | Go to page number control.
Ctrl+Z | Go to zoom control.
F1 | Help
F3 | Find

Operations

Zoom Percentage and Zoom In/Out

The Zoom Percentage control shows various steps of zoom. When you use the magnifying glass buttons to zoom in or zoom out, the steps by which you zoom are those shown in the zoom percentage control. You may manually set (by typing it in) the zoom percentage to any value between 10 and 1000. Note that when you are selecting a value for the zoom percentage control, and it has the focus, using the PageUp and Down key, as well as the up and down arrows, apply to the zoom percentage and not to the report being displayed. In other words, you can cycle through the zoom percentages by using those directional keys.

Find Text

This button on the toolbar will be grayed out (inactive) if the report being previewed does not contain any text—i.e., is all images and/or graphics. To initiate a text search, click on this button and enter the text to be found in the resulting dialog box.

Export to Excel

APEX includes an Export to Excel function which is initiated via a button of that name on the toolbar. There is also a button for setting the export preferences.

Print As Application Intended

This is rather an odd function to see in a Windows program, so a bit of explanation is in order.

Reports that are generated by A-Shell programs frequently are sent—by the report program—directly to a PC printer. In addition to the report, those print instructions include information for the printer, such as the name of the printer, number of copies, etc. However, APEX intercepts the report and (a) stops it from going directly to the printer, and (b) allows the user to now print the report using different parameters than the report program specified. Which is fine, and of course the user can print as he/she wishes.

But she might decide what she really wants, after looking at the report, is for it to be printed how the report program originally intended. Unfortunately she doesn't know what the report program intended; perhaps it was going to print six copies on a network printer called "Laser45."

By using this oddly-named button and function, the user can make sure that the report is handled and/or processed and/or printed as the original instructions intended.

If you do not need this function, just use the regular print operation.

Open another report file

See Preview File Retention in this document for information on what files may be opened and how they got here.

When you click this button, you will see a standard Windows file open dialog. Unfortunately, the list of file names that you see is probably not enough information to figure out what report it is you want to see. On the file open toolbar, you should see an icon near the top of the dialog box called Views, and one of its options is "details." If you click on the details icon, you should be able to see a little more information about the files. You may click on the column headers to sort by those columns in any effort to fine the report you're looking for. Unfortunately, not much information is available to you here, so you'll just have to open as many reports as it takes to find the one you're after.

Other Topics

Custom Extensions

You can add your own extensions to APEX, which are accessed as buttons on the toolbar and which call your own BASIC code, by defining them in the APEX configuration file, ASHCFG:APEX.CFG. The configuration file, if present, is scanned for commands of the following form:

BUTTON=prog, iconspec, tooltip {,msgno, inifile}

prog

indicates the subroutine which implements the extension. In theory it wouldn't have to be an SBX, but currently that is the only format supported, so prog must be in the form of "SBX:name", e.g. "SBX:PRTXLS". The corresponding subroutine (e.g. PRTXLS.SBX) must be in the BAS: directory (e.g. c:\ate\dsk0\007006\prtxls.sbx). The subroutine should be written according to the same interface specifications used by the printer initialization command line, COMMAND=SBX:... (see A-Shell Setup Guide).

iconspec

specifies the icon to display in the button that will be added to the toolbar. Supports the same syntax as for AUI_CONTROL icon buttons (see the A-Shell XCALL Reference).

tooltip

is a short tooltip to display when the mouse hovers over the button.

msgno (optional)

may specify a message number in the file <inifile.lng>, where lng is the current language extension, e.g. USA, to supply the tooltip text. If present, it overrides the tooltip parameter above.

inifile (optional)

may specify an initialization file used by the extension, although the details of how is is used are up to the custom code in prog.

The file may also contain any number of comment lines, each beginning with a semicolon in the first position. Here's , for example:

;APEX customization

;BUTTON=prog,icon,tip{,msgno,ini}

;If msgno>0, is expected to be msg 002,### in inifile.lng

BUTTON=SBX:PRTXLS,ashico1::document_out,Export to Excel,38,BAS:PRTXLS.INI

BUTTON=SBX:PXLCFG,ashico1::preferences,Configuration Options For Export,0,BAS:PRTXLS.INI

There are no particular limitations on what the subroutine (prog) may do, other than that it cannot delete or replace the file being previewed, and must eventually return so that APEX can resume control.

Debugging

In case of a problem launching the preview from ATE, use the debug message window to help clarify what is happening. Call up the A-Shell GUI Control Operations dialog with control+shift+double-right-click, then select Show Debug Dialog. When the debugging/trace window comes up, repeat the print attempt. It will log the command string that is actually being used, which might then be helpful to test independently, such as from Start..Run, or at least useful in identifying the problem.

Settings

In ATE, changes to Preferences are immediately stored with the connection profile in the Windows Registry. This means that they are both implemented immediately, and saved for future use; all subsequent operations of the preview window, whether in this session or new sessions, will reflect the latest settings.

In A-Shell/Windows, changes to Preferences are part of the overall A-Shell settings set which, along with the other options on the various Settings menu dialogs, are stored in the A-Shell settings (.ash) file. However, as with all other settings, changes made in the dialogs are not automatically written to the file. Thus, they only affect the current session. To make them permanent, you must save them via the File | Save option.

Files and Folders

The help file is called "apex.chm."

When you call up the Preferences menu, the actual words you see are taken from the file SYS:SBRMSG.USA. If you see odd codes in place of intelligible options, then your SBRMSG file is not being found.

Any temporary work files required by APEX are also created in the APEX folder.

The default location of the APEX folder is c:\apex, and this folder will be created the first time it is needed. If you don't like this folder and/or want it to be placed somewhere else, you may create an environment variable called "APEX" and point it wherever you wish.

Most of the print preview and display-related aspects of APEX are performed by a program module called "SftPrintPreview_###.dll" where "###" is platform and version information. This file lives in the main A-Shell or ATE folder on your PC.

Most of the export-to-Excel functionality is contained in the subroutine "prtxls.sbr." This file is found in DSK0:[7,6] of the A-Shell or ATE file system.

PRTXLS.INI Export Init File

Various operations and options in the export-to-Excel process are controlled by settings in the export initialization file, PRTXLS.INI. If this file is missing or an individual lines/statement is missing, APEX will use the value shown as "Default" in the table below. The init file is normally stored in the [7,6] directory or equivalent, although when PRTXLS.SBX is invoked from the COMMAND statement of a printer init file, the init file specification may be passed as an argument (e.g. COMMAND=SBX:PRTXLS,dsk7:xls123.ini[40,30]).

Note that each of the statements below must reside within the section indicated. Within a section, the order or presence/absence of a given statement is not relevant. The section names are in upper case, are enclosed in square brackets, and are preceded by a blank line. See the sample init file section.

As with many init files, lines beginning with semi-colons are comments and are ignored by the file processor. Comments can only occur on their own lines--i.e., cannot be appended to the ends of command lines.

Statement | Section | Values | Default | Description
IncludeTotals | DATA | 0,1 | 0 | If set, lines which look like totals or subtotals are treated as data lines.
IncludeBlankLines | REMNANTS | 0,1 | 0 | If set, blank lines are included in Remnants worksheet.
IncludeDupLines | REMNANTS | 0,1 | 1 | If set, duplicate lines are included in Remnants worksheet. (Otherwise only one line per set of duplicates is included.) For example, if set, the Remnants page may have many identical lines containing column headers.)
SortBy | REMNANTS | 0,1 | 0 | If set, Remnants lines are sorted by their contents.
BGcolor | ORIG | See sample init file | Silver | Background color of "Original" worksheet.
AppendSeqNo | POST | 0,1 | 1 | If set, a sequence number is appended to the XLS filename to make it unique.
SaveToDir | POST | Path specification |  | Directory where the XLS file is saved.
SendToPC | POST | 0,1 | 1 | (UNIX only) If set, causes the exported XLS file to be transferred to the PC using ATE/ZTERM FTP protocol.
Launch | POST | 0,1 | 1 | If set, the spreadsheet program (typically Excel) is launched to view the spreadsheet.
RemoteServer | POST | IP address: port | n/a | Specifies the location of a service to generate the XLS file. (Local generation requires that Perl be available and the WriteExcel add-on library be installed.)
IgnoreLocalServer | POST | 0,1 | 0 | Set to force use of RemoteServer even if local generation is available.
ServerErrorURL | MISC | URL |  | URL of page to display when an error related to the RemoteServer occurs.

Sample Init File

;PRTXLS.INI - Config file for PRTXLS.SBX

[DATA]

IncludeTotals=1

[REMNANTS]

IncludeBlankLines=1

IncludeDupLines=1

SortBy=1

[ORIG]

;BGcolor options: silver,white,red,lime,blue,yellow,magenta,cyan,brown,green,navy,purple,gray,orange

BGcolor=silver

[POST]

AppendSeqno=1

SaveToDir=c:\vm\miame\dsk0\150502

SendToPC=1

Launch=1

; RemoteServer spec is IP address, colon, port

RemoteServer=11.111.111.111:222

RemoteServer=63.199.106.102:39899

IgnoreLocalServer=1

[MISC];ServerErrorURL=http://

Troubleshooting Export to Excel

If the Export to Excel function does not work, either at all or properly, perhaps understanding the sequence of events will help you find and fix the problem.

Requirements: Perl has been installed on the host computer or PC, as appropriate. The report has been displayed with the A-Shell print preview function.

1. The Export to Excel button is enabled if and only if the A-Shell subroutine PRTXLS.SBX is present and available. It should be located in the directory [7.6]. If the Export to Excel button is inactive (grayed out), it is because this file is missing.

ATE only: the preview session of ATE (which itself is a second ATE session) launches another session of ATE to handle the export process. This job runs in the background and remains hidden except for the progress window.

2. PRTXLS.SBR creates a temporary working/debugging file called <sourcefilename>.XLX.

3. PRTXLS.SBR generates Perl script with the name <sourcefile>.PL.

4. PRTXLX.SBR executes PERL script. If the process breaks at this point, it is probably because the required Perl function "\spreadsheet\WriteExcel.pm" is not being found. This in turn may be because Perl is not installed, or because "\spreadsheet\WriteExcel.pm" is in the wrong location.

5. The Perl script runs and creates a spreadsheet file called <sourcefile>.XLS, which is placed in the xxx folder.

6. The temporary files (.XLX and .PL) are erased, and extra ATE session is shut down,

To assist in troubleshooting, you may want to use the debug function. To turn it on, check the "Debug" option on ATE's Connection Properties | Printer | General Options. If you are using A-Shell rather than ATE, get to the prompt and enter SET DEBUG.

Subtopics

Introduction

Preferences

Keystrokes and Mouse Clicks

Operations

Other Topics


Introduction

A-Shell Preview and EXport ("APEX") is a built-in component of A-Shell for Windows and ATE. At the user’s option or under program control, APEX receives a print file and re-directs it into a preview window. That window displays an image of the report and provides the user with various viewing options (zoom, multiple pages, single page, etc.). After previewing the report, the user may then print the report as it was originally intended to be printed (i.e., to the originally-specified printer), print it under user control (different printer, say, or landscape instead of portrait), or discard it. The purpose of the viewer, as with all such print preview functions, is to make sure that you are printing what you think you are printing—and to save time, energy, money and paper in the process. In some cases, viewing the report may eliminate the need for printing entirely.

APEX offers a variety of controls and options to facilitate viewing the report. Most of these items, and how to use them, are fairly obvious.

APEX also includes a valuable Export to Excel function, which is initiated by a button on the toolbar.

Following are some screen shots illustrating various aspects of APEX.

Title Bar and Tool Bar

The APEX title bar displays information about the report: original filename ("tstz" in this example), the first (-1) printing this session, temporary extension (.APF for "A-Shell print file"), the number of pages in the report, and Windows printer for which this report is intended, and the printer properties being used for printing. The toolbar provides options (in order from left) to set zoom percentage (10% to 999%); zoom in; zoom out; single page; multi-page grid (drop-down menu); page number / back / forward; print setup; print; help; close; print per application; find text (search); open another report; APEX preferences; export to Excel; export preferences.

Multi-Page Grid

Clicking on the multi-page grid option (see toolbar above) offers choices for the layout of multiple pages. You can (barely) see the grid choices below near the top left. The full screen shows the report in the 4 (across) by 2 (down) grid.

Find Text (Search)

Clicking the find text tool and entering a word into the "Find" dialog box ("exitcode" in this case) causes all the occurrences of "exitcode" on the current (first, in this case) page to be highlighted. Clicking "Find Next" displays the highlighted words on the next applicable page, etc.

Subtopics

Licensing


Licensing

The programs and files needed by APEX are automatically installed on the PC with the underlying software (A-Shell for Windows or ATE). Starting from the date it is installed, APEX will work in unrestricted mode for approximately 30 days. After that free-trial period, APEX reverts to demo mode, which means that it will work so you can see its functionality, but with qualifications. When operating in demo mode, APEX will display an annoying message saying that it is in demo mode.

To enable full APEX operation on your PC, you will need to obtain an APEX software license from either your application provider/dealer or from MicroSabio.


Preferences

Several things about how the preview function behaves are under user control, and these things are set on the Preferences dialog. This dialog is accessible from both the menu bar in A-Shell/ATE (Settings | Preview Preferences) and from the Preferences button on the preview toolbar. The following screen shot, while not necessarily identical to the one shown in your version of the program, illustrates some of the user-controlled options.xe "Discard"

Preferences toolbar button:

Preview on Print

Normal report printing consists of a report being created by a program, and then being sent to the PC for printing. The "Preview On Print" option allows you, the user, to control the circumstances under which those reports from the host, received for printing, are instead displayed on your screen. The "Always" and "Never" options should be fairly clear. The two "Application Control" options allow you to let the program that created the report determine whether the report is previewed--and gives you the option to say what happens when the report program doesn't specify anything.

There is no right or wrong, or best or worst, setting for this option. It is strictly determined by (a) your needs and objectives, and (b) those of your work environment.

The default value for this setting is "Application Control, Default=Off", which means that (a) APEX is expecting to receive a launch or don't launch command from the program that generated the report, and (b) if it does not get such a command, it will NOT launch.

On Exit from Preview

What do you want to happen when you exit the preview window (which, by the way, you can do by clicking on the "X" in the top right corner of the preview window, or by hitting the Escape key)? As you make your choice, keep in mind that all reports viewed with APEX are saved to disk; you can come back and view them again later if you wish.

Preview Window State

It is not possible for the program that launched the preview, or the programmer who wrote the program, to know how the user wants to deal with the preview: display the preview windows right now, or continue working and view the report later? The Preview Window State allows the user to set her preference for what happens when a report is sent to the preview window. "Visible (Foreground)" means that the preview window is shown right now. "Minimized (Background)" means that the preview window is created right now but then minimized; it appears in the task bar, which you need to click in order to view the report.

Preview File Retention

When a file is viewed using APEX, it is possible that the user may want to view this file again later. So as soon as a report is viewed, a copy of it is written to a file in the APEX folder. If the original file name being viewed is "report.xxx," then the file that is written into the APEX folder is called "report.apf" (apf = A-Shell Print File). These files remain in the APEX folder, and can be opened by the Open another report file button on the toolbar.

How long do they remain in the APEX folder? This is controlled by a setting on the Preferences called "Preview File Retention (hours)." The default value is 96 hours, 4 days, but you can set it to whatever you wish.

From an environmental perspective, the fact that you can view the report again later should make it easier to forego actual printing of every document (after previewing), merely out of fear that you might need it reference it in a few hours or days. The default setting of 96 insures that your disk won't get clogged up with more than four days worth of report files.

Subtopics

Files Requiring Preprocessing


Files Requiring Preprocessing

Files that require processing before they can be displayed include GDI print files (i.e., those contain graphical printing commands), files printed through ATE, and any files using the PREFIX or SUFFIX options.

Possible options: "Close all previews on exit?"

Option: Delete report files after we're done with them? (or let them sit)

Ctrl +/- zoom increment %

Export to Excel: save to disk?


Keystrokes and Mouse Clicks

Keystroke | Action
 | Multi-page Mode
Home | Positions to the first group of pages, starting at the first page. The first page becomes the current page. testing.
End | Positions to the last group of pages, ending at the last page. The first page of the displayed pages becomes the current page.
Control+Home | Same as the Home key.
Control+End | Same as the End key.
Left Arrow | Moves to the previous page. The displayed group of pages is adjusted if necessary.
Right Arrow | Advances to the next page. The displayed group of pages is adjusted if necessary.
Up Arrow | Moves the first page of the displayed group of pages to the previous page (or sheet in duplex mode). The current page is adjusted if necessary.
Down Arrow | Advances the first page of the displayed group of pages to the next page (or sheet in duplex mode). The current page is adjusted if necessary.
PgUp | Displays the previous group of pages. The current page is adjusted if necessary.
PgDn | Displays the next group of pages. The current page is adjusted if necessary.
Plus on NP | Zoom in. ("NP" refers to the numeric keypad.)
Left Click | Display page clicked in single-page view at scaling of last single-page view.
1 (numeric) | Switches from multi-page mode to single page mode.
 | Single Page Mode
Home | Positions to the top of the current page.
End | Positions to the end of the current page.
Control+Home | Positions to the top of the first page.
Control+End | Positions to the end of the last page.
Left Arrow | Horizontally scrolls left on the current page.
Right Arrow | Horizontally scrolls right on the current page.
Up Arrow | Vertically scrolls up on the current page.
Down Arrow | Vertically scrolls down on the current page.
PgUp | Vertically scrolls up on the current page. At the top of the current page, move to the bottom of the previous page.
PgDn | Vertically scrolls down on the current page. At the end of the current page, advance to the top of the next page.
Plus on NP | Zooms in . ("NP" refers to the numeric keypad.)
Minus on NP | Zooms out. ("NP" refers to the numeric keypad.)
Escape | Close
Left click | Zoom in. Same as "plus zoom" button.
Right click | Zoom out. Same as "minus zoom" button.
Ctrl+PlusKey | Zooms in 5%.
Ctrl+MinuKey | Zooms out 5%.
2 (numeric) | Switches from single page mode to multi-page mode.
 | Both Modes
Escape | Close
Ctrl+P | Print
Alt+Ctrl+P | Toggles between main window (A-Shell or ATE) and Preview.
Ctrl+Enter | Toggles between multi-page and single page modes.
Ctrl+Alt+ | Toggles between maximized and normal windows.
Ctrl+G | Go to page number control.
Ctrl+Z | Go to zoom control.
F1 | Help
F3 | Find


Zoom Percentage and Zoom In/Out

The Zoom Percentage control shows various steps of zoom. When you use the magnifying glass buttons to zoom in or zoom out, the steps by which you zoom are those shown in the zoom percentage control. You may manually set (by typing it in) the zoom percentage to any value between 10 and 1000. Note that when you are selecting a value for the zoom percentage control, and it has the focus, using the PageUp and Down key, as well as the up and down arrows, apply to the zoom percentage and not to the report being displayed. In other words, you can cycle through the zoom percentages by using those directional keys.


Find Text

This button on the toolbar will be grayed out (inactive) if the report being previewed does not contain any text—i.e., is all images and/or graphics. To initiate a text search, click on this button and enter the text to be found in the resulting dialog box.


Export to Excel

APEX includes an Export to Excel function which is initiated via a button of that name on the toolbar. There is also a button for setting the export preferences.


Print As Application Intended

This is rather an odd function to see in a Windows program, so a bit of explanation is in order.

Reports that are generated by A-Shell programs frequently are sent—by the report program—directly to a PC printer. In addition to the report, those print instructions include information for the printer, such as the name of the printer, number of copies, etc. However, APEX intercepts the report and (a) stops it from going directly to the printer, and (b) allows the user to now print the report using different parameters than the report program specified. Which is fine, and of course the user can print as he/she wishes.

But she might decide what she really wants, after looking at the report, is for it to be printed how the report program originally intended. Unfortunately she doesn't know what the report program intended; perhaps it was going to print six copies on a network printer called "Laser45."

By using this oddly-named button and function, the user can make sure that the report is handled and/or processed and/or printed as the original instructions intended.

If you do not need this function, just use the regular print operation.

Subtopics

Open another report file


Open another report file

See Preview File Retention in this document for information on what files may be opened and how they got here.

When you click this button, you will see a standard Windows file open dialog. Unfortunately, the list of file names that you see is probably not enough information to figure out what report it is you want to see. On the file open toolbar, you should see an icon near the top of the dialog box called Views, and one of its options is "details." If you click on the details icon, you should be able to see a little more information about the files. You may click on the column headers to sort by those columns in any effort to fine the report you're looking for. Unfortunately, not much information is available to you here, so you'll just have to open as many reports as it takes to find the one you're after.


Custom Extensions

You can add your own extensions to APEX, which are accessed as buttons on the toolbar and which call your own BASIC code, by defining them in the APEX configuration file, ASHCFG:APEX.CFG. The configuration file, if present, is scanned for commands of the following form:

BUTTON=prog, iconspec, tooltip {,msgno, inifile}

prog

indicates the subroutine which implements the extension. In theory it wouldn't have to be an SBX, but currently that is the only format supported, so prog must be in the form of "SBX:name", e.g. "SBX:PRTXLS". The corresponding subroutine (e.g. PRTXLS.SBX) must be in the BAS: directory (e.g. c:\ate\dsk0\007006\prtxls.sbx). The subroutine should be written according to the same interface specifications used by the printer initialization command line, COMMAND=SBX:... (see A-Shell Setup Guide).

iconspec

specifies the icon to display in the button that will be added to the toolbar. Supports the same syntax as for AUI_CONTROL icon buttons (see the A-Shell XCALL Reference).

tooltip

is a short tooltip to display when the mouse hovers over the button.

msgno (optional)

may specify a message number in the file <inifile.lng>, where lng is the current language extension, e.g. USA, to supply the tooltip text. If present, it overrides the tooltip parameter above.

inifile (optional)

may specify an initialization file used by the extension, although the details of how is is used are up to the custom code in prog.

The file may also contain any number of comment lines, each beginning with a semicolon in the first position. Here's , for example:

;APEX customization

;BUTTON=prog,icon,tip{,msgno,ini}

;If msgno>0, is expected to be msg 002,### in inifile.lng

BUTTON=SBX:PRTXLS,ashico1::document_out,Export to Excel,38,BAS:PRTXLS.INI

BUTTON=SBX:PXLCFG,ashico1::preferences,Configuration Options For Export,0,BAS:PRTXLS.INI

There are no particular limitations on what the subroutine (prog) may do, other than that it cannot delete or replace the file being previewed, and must eventually return so that APEX can resume control.


Debugging

In case of a problem launching the preview from ATE, use the debug message window to help clarify what is happening. Call up the A-Shell GUI Control Operations dialog with control+shift+double-right-click, then select Show Debug Dialog. When the debugging/trace window comes up, repeat the print attempt. It will log the command string that is actually being used, which might then be helpful to test independently, such as from Start..Run, or at least useful in identifying the problem.


Settings

In ATE, changes to Preferences are immediately stored with the connection profile in the Windows Registry. This means that they are both implemented immediately, and saved for future use; all subsequent operations of the preview window, whether in this session or new sessions, will reflect the latest settings.

In A-Shell/Windows, changes to Preferences are part of the overall A-Shell settings set which, along with the other options on the various Settings menu dialogs, are stored in the A-Shell settings (.ash) file. However, as with all other settings, changes made in the dialogs are not automatically written to the file. Thus, they only affect the current session. To make them permanent, you must save them via the File | Save option.


Files and Folders

The help file is called "apex.chm."

When you call up the Preferences menu, the actual words you see are taken from the file SYS:SBRMSG.USA. If you see odd codes in place of intelligible options, then your SBRMSG file is not being found.

Any temporary work files required by APEX are also created in the APEX folder.

The default location of the APEX folder is c:\apex, and this folder will be created the first time it is needed. If you don't like this folder and/or want it to be placed somewhere else, you may create an environment variable called "APEX" and point it wherever you wish.

Most of the print preview and display-related aspects of APEX are performed by a program module called "SftPrintPreview_###.dll" where "###" is platform and version information. This file lives in the main A-Shell or ATE folder on your PC.

Most of the export-to-Excel functionality is contained in the subroutine "prtxls.sbr." This file is found in DSK0:[7,6] of the A-Shell or ATE file system.


PRTXLS.INI Export Init File

Various operations and options in the export-to-Excel process are controlled by settings in the export initialization file, PRTXLS.INI. If this file is missing or an individual lines/statement is missing, APEX will use the value shown as "Default" in the table below. The init file is normally stored in the [7,6] directory or equivalent, although when PRTXLS.SBX is invoked from the COMMAND statement of a printer init file, the init file specification may be passed as an argument (e.g. COMMAND=SBX:PRTXLS,dsk7:xls123.ini[40,30]).

Note that each of the statements below must reside within the section indicated. Within a section, the order or presence/absence of a given statement is not relevant. The section names are in upper case, are enclosed in square brackets, and are preceded by a blank line. See the sample init file section.

As with many init files, lines beginning with semi-colons are comments and are ignored by the file processor. Comments can only occur on their own lines--i.e., cannot be appended to the ends of command lines.

Statement | Section | Values | Default | Description
IncludeTotals | DATA | 0,1 | 0 | If set, lines which look like totals or subtotals are treated as data lines.
IncludeBlankLines | REMNANTS | 0,1 | 0 | If set, blank lines are included in Remnants worksheet.
IncludeDupLines | REMNANTS | 0,1 | 1 | If set, duplicate lines are included in Remnants worksheet. (Otherwise only one line per set of duplicates is included.) For example, if set, the Remnants page may have many identical lines containing column headers.)
SortBy | REMNANTS | 0,1 | 0 | If set, Remnants lines are sorted by their contents.
BGcolor | ORIG | See sample init file | Silver | Background color of "Original" worksheet.
AppendSeqNo | POST | 0,1 | 1 | If set, a sequence number is appended to the XLS filename to make it unique.
SaveToDir | POST | Path specification |  | Directory where the XLS file is saved.
SendToPC | POST | 0,1 | 1 | (UNIX only) If set, causes the exported XLS file to be transferred to the PC using ATE/ZTERM FTP protocol.
Launch | POST | 0,1 | 1 | If set, the spreadsheet program (typically Excel) is launched to view the spreadsheet.
RemoteServer | POST | IP address: port | n/a | Specifies the location of a service to generate the XLS file. (Local generation requires that Perl be available and the WriteExcel add-on library be installed.)
IgnoreLocalServer | POST | 0,1 | 0 | Set to force use of RemoteServer even if local generation is available.
ServerErrorURL | MISC | URL |  | URL of page to display when an error related to the RemoteServer occurs.

Sample Init File

;PRTXLS.INI - Config file for PRTXLS.SBX

[DATA]

IncludeTotals=1

[REMNANTS]

IncludeBlankLines=1

IncludeDupLines=1

SortBy=1

[ORIG]

;BGcolor options: silver,white,red,lime,blue,yellow,magenta,cyan,brown,green,navy,purple,gray,orange

BGcolor=silver

[POST]

AppendSeqno=1

SaveToDir=c:\vm\miame\dsk0\150502

SendToPC=1

Launch=1

; RemoteServer spec is IP address, colon, port

RemoteServer=11.111.111.111:222

RemoteServer=63.199.106.102:39899

IgnoreLocalServer=1

[MISC];ServerErrorURL=http://


Troubleshooting Export to Excel

If the Export to Excel function does not work, either at all or properly, perhaps understanding the sequence of events will help you find and fix the problem.

Requirements: Perl has been installed on the host computer or PC, as appropriate. The report has been displayed with the A-Shell print preview function.

1. The Export to Excel button is enabled if and only if the A-Shell subroutine PRTXLS.SBX is present and available. It should be located in the directory [7.6]. If the Export to Excel button is inactive (grayed out), it is because this file is missing.

ATE only: the preview session of ATE (which itself is a second ATE session) launches another session of ATE to handle the export process. This job runs in the background and remains hidden except for the progress window.

2. PRTXLS.SBR creates a temporary working/debugging file called <sourcefilename>.XLX.

3. PRTXLS.SBR generates Perl script with the name <sourcefile>.PL.

4. PRTXLX.SBR executes PERL script. If the process breaks at this point, it is probably because the required Perl function "\spreadsheet\WriteExcel.pm" is not being found. This in turn may be because Perl is not installed, or because "\spreadsheet\WriteExcel.pm" is in the wrong location.

5. The Perl script runs and creates a spreadsheet file called <sourcefile>.XLS, which is placed in the xxx folder.

6. The temporary files (.XLX and .PL) are erased, and extra ATE session is shut down,

To assist in troubleshooting, you may want to use the debug function. To turn it on, check the "Debug" option on ATE's Connection Properties | Printer | General Options. If you are using A-Shell rather than ATE, get to the prompt and enter SET DEBUG.


Introduction to LIT Files

Although A-Shell is primarily a development and runtime environment, it also contains an emulation of the AMOS monitor mode (aka "dot prompt") for the benefit of applications, developers, and users that rely on monitor mode for auxiliary operations. Examples of such operations include copying and erasing files, creating PPNs, performing maintenance on ISAM files, getting system status, building function key translation tables, displaying directory lists, dumping files, and logging to different PPNs—and of course, running, compiling, and editing programs.

The operations just described are all implemented via program files, which under both AMOS and A-Shell, have the extension "LIT" and are thus sometimes referred to as "LIT commands." Under AMOS, the LIT name was thought to derive from the idea that these were "literal" commands (i.e. machine language to be executed literally by the CPU) as opposed to commands that are interpreted by some higher-level software (like BASIC programs). Under A-Shell, they are implemented in BASIC and thus the LIT extension may be a bit misleading, but we decided to stick with it nonetheless since the distinction is no longer relevant.

Some of the A-Shell LIT commands are essentially replacements for existing host operating system utilities (e.g. COPY, DIR, ERASE), but others are so AMOS or A-Shell-oriented that there would be no host operating system equivalent (e.g. ISMDMP, ISMUTL, SUBMIT, SYSTAT, etc). Even for the first category, the many differences between AMOS and Windows or UNIX syntax make the A-Shell emulations of the AMOS LIT commands worthwhile. For example, what would be the Windows/UNIX equivalent of the command "COPY [,0]=*.RUN/Q"?

Although LIT commands are useful in themselves and often typed directly by users at the "dot prompt", they are more commonly grouped together in CMD or DO files, which are conceptually equivalent to BAT or script files under Windows or shell scripts under UNIX. Due to the obvious utility of being able to create a complex series of command operations that can be invoked via a single command line, they are extensively used in most existing applications. This, perhaps more than any other reason, is the justification for implementing so many of the AMOS LIT commands in A-Shell—i.e., so that existing CMD and DO files would not have to be rewritten when porting applications from AMOS. A section on the details of writing CMD and DO Files is included at the end of this document.

Subtopics

Filespecs and Directories

Mapping Filespecs

System Command Syntax

Command Search Path

Binary Compatibility

Wildcard Commands

Native Filespecs

Command Line Editing and Recall


Filespecs and Directories

AMOS organizes disk space into physical devices, logical units, and a pair of octal numbers referred to as the "PPN". Within this structure are the files, which consist of a one-to-six character name and a one-to-three character extension. The characters used in filenames are from the "RAD50" set, which consists of 0-9, A-Z, and $. No part of the filespec is case sensitive. For example, the following are equivalent:

DSK0:COPY.LIT[1,4]

dsk0:copy.lit[1,4]

Dsk0:Copy.Lit[1,4]

In these examples, the physical device is DSK, the logical unit is 0, and the PPN is [1,4]. The file name is COPY and the extension is LIT.

Under AMOS, a logical unit was essentially a partition within a physical disk device, more or less equivalent to a drive letter under Windows. Within each logical unit, there were individual directories identified by a pair of octal numbers (each ranging from 0-377) referred to as a "PPN" (Project, Program Number). Individual directories (i.e. a PPN within a logical unit within a physical unit) could also be assigned aliases, called ERSATZ devices, which have the syntax of device names. This is similar to the situation under Windows where a drive letter can be mapped to another directory. These ERSATZ devices are defined in a text file DSK0:ERSATZ.INI[1,4]. You can add your own (each one consisting of up to six "RAD50" characters starting with an alphabetic character). In addition, the standard ERSATZ.INI defines ERSATZ device names for a collection of PPNs on DSK0: which are considered the "system accounts" and which are listed in the following table. See the ERSATZ system parameter for additional information on ersztz devices and usage.

Device:[P,PN] | ERSATZ | System Account Purpose
DSK0:[1,2] | OPR: | System operator account. This account has special privileges and is usually password protected. Logging into this account might be considered analogous to logging in as Administrator under Windows or as the superuser under UNIX. Certain commands, for example, will only run, or have greater powers, when executed from this account.
DSK0:[1,4] | SYS: | "The" system account. This is the default location for all of the system commands (those with LIT extensions) plus certain configuration files, such as the language files and ERSATZ.INI.
DSK0:[1,6] | DVR: | Terminal driver and language definition file account. Under A-Shell, terminal drivers are embedded in the executable, so the only files you will normally have in this account of the language definition files (e.g. ENGLSH.LDF).
DSK0:[1,7] | ASHCFG: | A-Shell configuration files, in particular, printer init (PQI) files.
DSK0:[2,2] | CMD: | Command files (i.e. those with CMD or DO extensions). These are the AMOS and A-Shell equivalents of BAT files under DOS or shell scripts under UNIX.
DSK0:[7,0] | LIB: | Library files. Function key translation tables, color configuration files, INI.VUE (VUE initialization file).
DSK0:[7,1] | HLP: | Help files. A-Shell tends to embed help which is associated with system commands in the commands themselves, or use external PDF (Acrobat) or CHM (Windows Compiled Help) files, leaving this directory only for the help files that are displayed from within the VUE command mode with the HELP command.
DSK0:[7,6] | BAS: | RUN files placed in this directory can be run from any other location.
DSK0:[7,376] |  | A-Shell sample program directory


Mapping Filespecs

Because the non-AMOS operating systems where A-Shell typically runs all use a multi-level hierarchical directory system, we map the AMOS-style devices and PPNs to hierarchical directories using DEVICE statements in the miame.ini file. A couple of simple examples should make the concept relatively clear:

DEVICE=DSK0 C:\VM\MIAME\DSK0\ ;(Windows)

DEVICE=DSK0 /myapp/dsk0/ ;(UNIX)

The above definitions equate the A-Shell device named DSK0 with the directory C:\VM\MIAME\DSK0\ (Windows) and with /myapp/dsk0/ (UNIX). To these base directories, we would convert the PPN into a six digit number, using three digits for the Project number and three digits for the Programmer number. Thus, DSK0:[1,4] would get mapped to C:\VM\MIAME\DSK0\001004\ in the first case and /myapp/dsk0/001004 in the second. Finally, the filename is appended to the end. So, DSK0:COPY.LIT[1,4] would be mapped to C:\VM\MIAME\DSK0\001004\COPY.LIT in the first case (Windows) and to /myapp/dsk0/001004/copy.lit in the second. Under UNIX, we fold the filespec to lower case to be consistent with typical UNIX conventions. Each AMOS or A-Shell device must be mapped to a native path, as in the examples above, but each definition can be entirely independent and arbitrary. It is also possible to map individual PPNs to arbitrary native directories.


System Command Syntax

The general syntax of an A-Shell system command line is:

<command-name> {switches} {arguments} {switches}

or, in the case of many commands that operate on files, and/or which accept wildcard filespecs:

<command-name> {<outfile>=} {wildcard list} {switches}

<Angular brackets> are used in these syntax examples to indicate a token that must be replaced, while {curly brackets} indicate items that may be replaced (i.e., are optional). So in the example above, {<outfile>=} indicates an optional term; if specified, <outfile> must be replaced with an actual argument, such as MYFILE.TXT.

The command name (e.g. COPY) is never case sensitive, and is generally given as just the name, without the extension or the directory location. Specifying more than just the name may alter the search path (for which see next topic). If the command takes arguments, they are usually not case sensitive, but this could be up to the discretion of the command implementation.

Switches are always preceded by a forward slash, and are virtually never case sensitive. In most cases, the switch may be abbreviated to the minimum number of unique characters for that command. For example, many commands support the switch /query, which can usually be abbreviated to /q. In some cases switches may precede the arguments, but the most common position is at the end.

The <outfile=> syntax element in the second example above indicates that the output of the command will be sent to that file, rather than to the screen. This is roughly the AMOS equivalent of the UNIX technique of redirecting stdout to a file.

For some commands, like COPY and APPEND, <outfile=> is mandatory.

Also note that unlike DOS and UNIX, output file arguments precede the input file arguments—i.e., they are reversed—and are separated by the equal sign.

Command lines are tokenized using both spaces and commas, plus other punctuation characters. For example, the command name itself may be terminated by a space, slash, equal sign, or new line. Arguments for LIT commands are typically separated by commas, while arguments for DO commands must be separated by spaces.

The semicolon marks the beginning of a comment, as in this example:

DIR/V MYAPP.LST=A.RUN,B.RUN,C.RUN ;this is a comment

This would create the file MYAPP.LST containing the directory information including version (/V) of the three specified files.


Command Search Path

When only the command name (i.e. no device, PPN, or extension) is specified, the search path for the command is given in the table below:

Filespec searched for | Notes
DSK0:<name>.LIT[1,4] | LIT command in the system directory.
<name>.LIT | LIT command in the current PPN
<name>.LIT[p,0] | LIT in the ,0 PPN of the current project
DSK0:<name>.CMD[1,4] | CMD file in the system directory
DSK0:<name>.CMD[2,2] | CMD file in the CMD file account
<name>.CMD | CMD file in the current PPN
<name>.CMD[p,0] | CMD file in the ,0 PPN of the current project
<name>.DO | DO file in the current PPN
<name>.DO[p,0] | DO file in the ,0 PPN of the current project
DSK0:<name>[2,2] | DO file in the CMD file account

If the command extension is included with the command name, then the search path is modified from the above to first look for the command in the current PPN (rather than in the system or CMD file directory).


Binary Compatibility

While A-Shell’s LIT commands are binary compatible across A-Shell platforms, they are not binary compatible with the AMOS LIT commands. In fact, as previously mentioned, A-Shell’s LIT commands are simply BASIC programs that have been renamed from .RUN to .LIT, and which have appropriate startup logic to process command line arguments. You can create your own LIT commands by doing the same thing.


Wildcard Commands

Many of the A-Shell LIT commands support wildcard arguments. Those that do are marked with an asterisk in the "Class" column of LIT Command List. Commands which support wildcards will also accept a comma-delimited list of filespecs, each of which may contain wildcards. Supported wildcards are:

Wildcard | Meaning
* | Matches any full or partial token in the specified position. For example, *.RUN matches any filename with a RUN extension. Or AB*.DAT[1,*] would match any filename beginning with AB that has a DAT extension and is in the Project 1. When a portion of a filespec is omitted, it may act like the * wildcard. For example, DIR ABC is equivalent to DIR ABC.* (rather than DIR ABC*.*).
? | Matches one character. If multiple ?? are used together, then the combination will match between 1 and the specified number of question mark characters. For example, A?BC.?? Would match any file any file starting with A, followed by any character, followed by BC, and with any one or two character extension. May also be used with the [P,PN], e.g. *.BAS[150,27?]
ALL: | Special wildcard that matches all devices. For example, ALL:*.BAS[7,6] would match all files with extension BAS in [7,6] on any device.
[] | Matches any PPN. For example, ALL:[]. You may also omit one of the two parts of the PPN, such as [,0] (equivalent to [*,0]).


Native Filespecs

By default, filespecs used in system commands are expected to be in AMOS format. Some commands, including all of the wildcard commands, will allow you to specify a native filespec by enclosing it in quotes. For example:

.COPY HOSTS.TXT="/etc/hosts" /NOD

.TYPE "/etc/hosts"

.SIZE "c:\vm\miame\bin\ashw32.exe"

.DIR HASH.DIR="/vm/miame/bin/ashell" /H

When using quoted native filespecs, you cannot use wildcards.


Command Line Editing and Recall

Given the syntactic complexity and advanced typing skills involved with some of these command lines, you are likely to commit syntax errors or simply tire of retyping commands that you already typed just a few moments previously. At that point you will appreciate the ability to recall previous command lines and edit them. To cycle backwards through the last 25 command lines, hit Ctrl+R (typically the same as the PageUp key). To cycle forwards through them, hit Ctrl+T (page down). Once you find the previously-typed command line, you can re-execute it just by hitting Enter. If instead of just re-executing it as is, you prefer to edit it first, you can do so using the following keystrokes:

Primary | Alternate | Editing Action
ctrl+a |  | Move cursor to previous word
ctrl+c |  | Abort the current line (start a new one).
ctrl+d | delete | Delete the character under the cursor
ctrl+f | insert | Insert a space under the cursor
ctrl+h | LeftArrow | Move cursor to the left
ctrl+l | RightArrow | Move cursor to the right
ctrl+n |  | Move cursor to the end of the line
ctrl+q |  | Toggle insert/replace mode
ctrl+r | PageUp | Cycle through the previously typed ten command lines.
ctrl+t | PageDown | Cycle forward through the previously typed ten command lines (after having used ctrl+r to go backwards).
ctrl+u |  | Move cursor to start of command line
ctrl+w |  | Move cursor to next word
ctrl+y |  | Delete line to the right of the cursor


LIT Command List

The following table shows the LIT commands that are included A-Shell, with links to extended descriptions for most of them. An asterisk in the "Class" column indicates that the command will accept wildcards. For information on how the commands are processed, see Introduction to LIT Files.

Note that many of the commands will display usage information if invoked with a /? Switch.

Command | Class | Function
ABOUT | A-Shell | Display information about the current license and environment
AGCMD | A-Shell | Sends a AG_xxx command from the dot prompt or a command file
APN | A-Shell | Launches APN session.
APPEND | AMOS | Appends file together
ASHUPDATE | A-Shell | Retrieves A-Shell updates via the A-Shell menu Help ... Check for Updates.
ASTAT | Utility | Abbreviated dynamic job display
ATECFG | JB Tech | Configure A-Shell Terminal Emulator (Windows only)
ATECTL | A-Shell | Connect ATE "reverse channel" socket
ATSYNC | A-Shell | Synchronize host directory with ATE's cache on PC
C, CLS | Utility | Clear screen
CHAT | A-Shell | (UNIX only) Full screen dialog between two users
COMPIL | AMOS | AlphaBASIC 1.4 compiler
COMPLP | A-Shell | AlphaBASIC Plus compiler; see COMPIL.
COPY | AMOS * | Copy files
CREATE | AMOS | Allocate random data file
DATE | AMOS | Display system date
DEL | AMOS | Deletes modules from user memory
DEVTBL | AMOS | List virtual AMOS devices
DIFF | UNIX | (UNIX only) Compare two source files.
DING | AMOS | Ring bell
DIR | AMOS * | Produce directory of files
DO | AMOS | Force .CMD or .DO file execution
DUMP | AMOS * | Dump file contents in octal or hex
ELSE | AMOS | Conditional flow in command file
ENDIF | AMOS | Conditional flow in command file
ERASE | AMOS * | Erase files
ERSATZ | AMOS | Display defined ERSATZ devices
EXIT | AMOS | Exit command or DO file
EXPLORE | MicroSabio | Launches Windows file explorer.
EZPRT | MicroSabio | Print file, using EZ-SPOOL configured menu of printers
EZTYP | MicroSabio | Display text file with full paging control
FLIT |  | Used internally by A-Shell.
FIXTRN | AMOS | Function key translation table editing utility
FORCE | AMOS | Force keystrokes into another job’s input
FREE | AMOS | Display amount of free space on specified device
GETENV | A-Shell | Retrieves value of environment variable; use getenv var. Lists all of the environment definitions if no parameter is passed on command line.
GETATEREG | A-Shell | Retrieve ATE configuration settings from the server. Execute with no arguments or with /? to display help.
GOTO | AMOS | Jump to label within command file
HEAD | A-Shell * | Display (or copy) first N lines of a text file
HOST | A-Shell * | Return to host machine command level
IF | AMOS | Conditional flow in command file
ISMBLD | AMOS | Build ISAM 1.x file.
ISMDMP | AMOS | Dump ISAM 1.0 file
ISMUTL | AMOS | Dump/build/examine ISAM-A file
JOBALC | AMOS | Display current job name
JSTAT | A-Shell | Monitor another job
KILL | AMOS | Terminate another process
LICENS | A-Shell | Update license information
LOAD | AMOS | Load file into memory
LOG | AMOS | Change current login account
LOGOFF | AMOS | Log off
LOKUTL | A-Shell | Display information about file locks in use
LOOKUP | AMOS | Lookup file and display message; supports quoted native filespecs to 160 chars.
MAKE | AMOS | Create a blank sequential file. Will create a file ending in "." if so directed.
MAP | AMOS* | Display user memory
MDO | A-Shell | Alternate version of DO
MEMORY.LIT | AMOS | Change user partition size
MMAP | A-Shell* | Display or load list of files to be memory mapped
MOVE | A-Shell * | Move a file (UNIX / Linux only)
OCMPIL | AMOS | AlphaBASIC 1.3 compiler; see COMPIL
OPRE | Debug plc | AlphaBASIC 1.3 pre-compiler
ORUN | AMOS | Run AlphaBASIC 1.3 or 1.4 program (same as RUN)
PAGE | Debug plc | Page command output
PPN | AMOS | Display PPNs on a given device
PRE | Debug plc | AlphaBASIC 1.4 pre-compiler
PRINT | AMOS * | Sends files (wildcard spec) to a spooler
PWD | A-Shell | Display current login directory in native O/S format
QUIT | A-Shell | Same as HOST, but terminates PolyShell parent and all siblings
QUTL | Debug plc | Queue/XLOCK/FLOCK display utility
RENAME | AMOS * | Rename files
RUN | AMOS | Run AlphaBASIC 1.3 or 1.4 program
SAVE | AMOS | Save module from memory to disk
SEND | AMOS | Send text message to another user
SET | AMOS | Set miscellaneous system and job parameters
SETATEREG | A-Shell | Set ATE configuration settings. Execute with no arguments or with /? to display help.
SETENV | A-Shell | Sets environment variable; use setenv var = value.
SHLEXC | A-Shell | Execute/open specified file in Windows
SIZE | AMOS | Display size of specified file, in bytes
SLEEP | AMOS | Sleep specified number of seconds or fractions of a second.
SLEEPR | AMOS | Sleep until specified time
SORT | AMOS | Sort sequential data file
SRCCOM | AMOS | Compare two source files
SUBMIT | AMOS * | Submit a background task
SYSACT | AMOS | Maintain PPNs and passwords
SYSTAT | AMOS | Display jobs and devices
TAIL | A-Shell * | Display (or copy) last N lines of a text file
TELNET | JB Tech | Launch A-Shell Terminal Emulator; see ATECFG
TELSER | A-Shell | Turn current session into telnet server
TIME | AMOS | Display system time; see DATE, TIME
TYPE | AMOS | Type sequential text file on screen
U | AMOS | Store a command line for later recall
VER | AMOS | Display current A-Shell version
VERIFY | AMOS | Verify files against a DIR file
VERSYS | A-Shell * | Display detailed version information about a LIT command
VUE | AMOS | Full screen-based text editor
WEBRUN | A-Shell * | Runs A-Shell's WEBCACHE system for named program
WSET | Debug plc | Install TRACKER 2.0
XY | AMOS | Execute TCRT code
ZTXFER | MS | ZTERM file transfer
ZXPWIN | A-Shell | (ZTERM utility) Transfer file to PC and launch app


ABOUT

Updated April 2011

ABOUT {switches}

ABOUT displays information about your A-Shell software license and environment in the format shown below. Hidden bookmark here. Select line and Shift+F9 to see/change.

Switch | Function
/L | Causes the output to written to the file ABOUT.LST instead of the screen.
/R | Forces a rebuild/recount of JOBTBL.SYS before displaying the information.
/?, /H | Writes switch listing and usage info to the screen.

Notes

· Details about the software license are also available from, and may be changed with, the LICENS command. For A-Shell/Windows, similar information is available for viewing (but not changing) from the Help | About menu.

· If you enter new license data and then immediately run ABOUT, it is possible that ABOUT will return incorrect license information—i.e., info that doesn't agree with the license you just entered. To correct, simply exit A-Shell, reload, and rerun ABOUT.

Example

A-Shell/32/Windows Ver. 6.1.1408.0c

Licensed to: MicroSabio

Serial # 3000

A-Shell Key: OCDE-6683-RFF-062981-6XAOFA6M

Nodes Licensed: 5

Nodes / Jobs in Use: 1 / 1

License Options: D-Isam ATS ATE PDFX APEX W32IO

Release Date: 23-Apr-2015

Maintenance Expiration: 19-Nov-2020

INI File: c:\ashell\ashell\miame.ini

ATE Licensing: Server

Nodes Licensed: All

JOBTBL.SYS File:

Spec: C:\ashell\ashell\jobtbl.sys

Created: 19-Jan-11 10:03

History

2011 April, A-Shell 5.1.1213: For ATE, the ABOUT display now clarifies that the version it is displaying at the top of the About box applies to ATE (A-Shell on the client) not to A-Shell on the server. The latter version continues to also show in the lower part of the box. The display also indicates which ashnet library is being used, when applicable. In all cases, the license options have been made somewhat more uniform and consistent with those used when issuing license codes and those displayed by ABOUT.LIT.

Note: There remain some "license options" which appear in the "about" display but are not chargeable and/or not associated with the PIC. These include LFS (Large File Support), W32IO (a variation of the file i/o library), VI(x.x.x) (Victor Imaging library version), and possibly others.

2010 April, A-Shell 5.1.1177: ABOUT.LIT 2.2(108) now displays license options for the auxiliary ATE license. Also, when the ATE client is supplying its own license even though the server offers server-based licensing, a warning message now displays at the end of the ABOUT display.


AGCMD

Added May 2011

AGCMD {switches} <cmd> <parms>

AGCMD may be used to send a AG_xxx command from the dot prompt or within a command file without having to write code and compile it. It may be useful for experimentation and for inserting simple ATE or other GUI configuration commands in startup command files. Usage:

Parameters

cmd

the symbolic AG_xxx name (case insensitive, with or without the AG_ prefix), or numeric value of the AG command to execute.

parms

the parameter list as it would be passed in the AG_xxx statement, except without the trailing chr(127).

switches

Switch | Function
/K# | Assign result to CMD/DO variable $KBD#
/S | Silent (don't display the command response)
/N | No wait (don't wait for any response)
/W:# | Wait # seconds for response (overriding default)

Examples

AGCMD WINEXEC,$DEL %ATE%\dsk0\001004\ftpdlx.log

AGCMD WINTITLE,This is the new and improved title

AGCMD SHOWWINDOW 3

AGCMD STATUSLINES,1,0

AGCMD/S 24,cmd.exe,option,"/c ipconfig > ipcfg.lst",,0,1

AGCMD/N PALETTE,3,0,123,207,242

AGCMD/S/K1 BROWSEFOLDER

Comments

If neither of the /N or /W:# switches are specified, AGCMD will use the "normal" wait value based on the command itself, ranging from no wait (for commands with no response, e.g. AG_STATUSLINES), to a few seconds (for commands with an immediate response, e.g. AG_GETENV), to unlimited (for commands which require a user response, e.g. AG_WINPTR).

Some commands have a variable response (or lack of), depending on the command parameters. For example, AG_PALETTE has no response when used to set a color, but has a "standard wait time" response when used to retrieve palette info. For these commands, AGCMD defaults to the "standard wait time" (a few seconds). To avoid waiting for a response that won't be coming, use the /N switch (as in the example above).

History

2011 May, A-Shell 5.1.1215: Added function to A-Shell


APN

Added November 2014

APN {file{.ext}} {/switches}

APN launches an A-Shell Programmer's Notepad (APN) editing session for the specified file.

Switch | Meaning
/R | Launches file in read-only mode
/T | Traces the search for the default extension list. Default extension list: bas,bp,txt,cmd,do,bsi
/Y | Creates file if non-existent (else asks)

If the extension is omitted, it searches for an INI.VUE file using the same path as VUE does (current [p,pn], [p,0], dsk0:[7,0]) and then uses the DEFAULT statement in the INI.VUE for the list of extensions to search. If the INI.VUE is not found, it uses a built-in default list of:

.BAS, .BP, .CMD, .DO, .BSI, .BPI, .CPY. .UTL, .INI

Comments

If APN is not already running, it will then be launched. If the specified file.ext is not already being edited in one of the APN windows, a new window (TAB panel) will be opened containing the file. The focus will then be switched APN to facilitate editing. If the file was already open within APN, the only action will be to set the focus on the specified window.

See Also

• There is a fair amount of worthwhile information about APN on the MicroSabio's web site

History

2014 November, A-Shell 6.1.1397: Added function to A-Shell.


APPEND

APPEND {switches} <outfile>=<infile1>,<infile2>{,…}

APPEND creates a file consisting of two or more input files concatenated together.

Switch | Meaning
/I | Causes nonexistent input files to be ignored. (Otherwise a missing file would cause the operation to abort.)
/Z | Strips EOF (^Z) characters from the source files. DOS files, or files transferred to DOS/Windows with some file transfer software, sometimes end with a ^Z used as an end-of-file marker, which can cause all kinds of havoc in programs not prepared to filter these out.
/?, /H | Writes switch listing and usage info to the screen.

Notes

If the outfile already exists, it will be overwritten. You may specify the same file as both the outfile and one of the infiles.

APPEND handles long native filenames containing spaces. For example, the following is legal:

.APPEND TEST.LST=TEST.LST,"%TEMP%\THIS IS A LONG FILE.LST"

APPEND supports the case where the destination and one of the source files is the same file, and neither exists, provided the /I{gnore} switch is specified, e.g.:

.APPEND /I A.A=A.A,B.B

In older versions of A-Shell, this would have aborted with an error if A.A didn't exist. Now, the above command is logically equivalent to COPY A.A=B.B

ASHUPD hidden 11/2016; delete if not reinstated soon

ASHUPD {switches}

ASHUPD retrieves A-Shell updates via the Update Center. It is intended primarily for resellers and developers who wish to stay abreast of the latest changes to A-Shell, but can be used by any A-Shell client. Exercise appropriate caution when updating to the latest—and not necessarily fully tested—version of A-Shell (or any other software product).

Switch | Function
/F | The Fast switch stifles all user interaction requiring a user response—that is, it checks for updates and either performs them or reports there are none, without waiting for user confirmation. This could be useful in a command file where you always want to update if possible, without bothering the user to make decisions.
/B | Background mode. Run the update in the background, do not display any information on the screen, do not re-launch A-Shell when update is complete.
/RECAP | Display log file for last update.
/ATE | Update ATE client.
/V:51 | Update to version 5.1
/?, ?H | Writes switch listing and usage info to the screen.

Comments

Note that ASHUPD:

· Checks for an existing update in progress (or possibly a hung prior instance) and attempts to delete UPDATECENTER.TEMP.EXE if needed. If it can't delete it, it reports the problem, which is better than leaving you wondering what happened.

· Checks for multiple instances of ASHW32 running, refusing to update if in /FAST mode, or giving you abort/retry/ignore options if in interactive mode.

· Tries to start the update process for ten seconds before reporting that the check for updates failed.


ASTAT

Updated September 2011; see History

ASTAT {switches}

ASTAT displays a dynamically updated list of jobs currently running along with the current program name. The list is formatted into two columns to fit more jobs on the screen, making it useful on large systems. You may condense the list further by putting the names of programs that are not of interest in the file BAS:IGNORE.PRG (one per line). Thus, if you want to quickly size up if it is safe to do a shutdown or backup, you may want to list those programs that are safe to interrupt (such as the main menu, application logon, etc.). so that only the jobs which are doing something worthy of attention will be shown.

Switch | Function
/# | (#=1-9) Sets the sleep interval (time between screen updates) in seconds. The default is one second. Note that the shorter the interval, the more load this program will place on the system, particularly on a large system.
/C | Causes the console or tty name to be displayed for each job instead of the user name.
/S | Sorts the entries by job name.
/SU | Sorts the entries by user name.
/SP | Sorts the entries by program name.
/?, /H | Writes switch listing and usage info to the screen.

ASTAT was actually developed and then contributed to the A-Shell community by Carl Staff of Diversified Data Systems. Thanks, Carl!

History

2011 September, A-Shell 5.1.1235: Add support for new job table layout and ten character program name.


ATECFG

(Windows only) ATECFG is a wrapper for the Windows program, ATECFG.EXE, which is installed along with A-Shell/Windows and which allows you to add or edit "ATE configurations". ATE (A-Shell Terminal Emulator) is a facility that allows you to turn your A-Shell/Windows session into a client connected to another machine, over serial or network (telnet) links. It is invoked via TELNET.LIT.

In order to use TELNET to make a connection to another machine, you must first define a "configuration", which is a collection of parameters describing the connection. Such configurations are stored in the local Registry. The parameters are reasonably self-explanatory to anyone familiar with telnet and serial connections. See the discussion on TELNET for more information about ATE.


ATECTL

ATECTL switch

ATECTL allows you to connect, disconnect, or query the status of the ATE "reverse channel."

Switch | Function
/C | Connect
/D | Disconnect
/S | Query

The "reverse channel" is an optional second socket connection between the ATE client and the server used for the purpose of sending response information from the client to the server. The "reverse channel" generally speeds up communication between the server and client, and minimizes conflicts between keyboard activity and the other control information sent between the two machines.

When connected, all non-keyboard communication from the ATE client to the server is sent via the socket, rather than sharing the stdin data stream with the keyboard. The objective is to eliminate interference between keyboard data (especially in the form of typeahead) and control data (such as result codes from INFLD and GUI operations).

There are two steps to activating the connection. The first is to check the option "Accept Connection From Server" on the Misc tab of the ATE configuration dialog and enter an available port number that is visible by the server to the client; requires ATE build 153 or higher. A high-numbered port, above 20000, is recommended.

The second step is to execute ATECTL/C from the dot prompt of the server after connecting.

Note that if there is a firewall between the server and client (or you are running a software firewall in the ATE client), you will need to open up the port you choose to connect on.

Also note that use of this connection is optional, and can even be turned on and off during a session. When the connection is not available, ATE will revert to using the keyboard channel for passing control.


ATSYNC

Updated September 2015

ATSYNC {hostdir} {,pcdir} {switches}

(ATE environment only) ATSYNC does a one-way synchronization of the contents of a directory or a set of files, from the server to the ATE client. This is particularly useful for resources—images, icons, auxiliary files—that are distributed with an application—i.e., on the server—but which need to be present on each individual client.

Parameters

hostdir

specifies the source of the files to be transferred. It can be either a directory on the host, in AMOS or native format, or a file containing a list of files to transfer; see /F switch below. If hostdir is not specified—i.e. the command line starts with a comma or a switch or is blank—it uses the current directory. If the hostdir contains forward slashes, enclose it in quotes.

pcdir

specifies the target directory on the PC, using native Windows directory syntax, with optional embedded environment variables using the %envvar% syntax. If not present, the default is %ATEPERMCACHE%. In the case of the /F switch, pcdir just sets the default directory for entries in the list file that do not contain explicit target directories.

switches

Switch | Function
/A{UX} | Use the ATE aux port transfer protocol as an alternative to FTP. The switch is set automatically in the ATSD environment, where FTP is usually not configured.
/C | Continue trying even after a transfer error.
/D | Delete files from PC target dir not in host source dir.
/F{ILES} | Replaces the HostDir parameter with a file containing the list of files to transfer. See Comments, plus History note for 6.1.1366.
/P | Display progress info.
/NOERR | Don't display FTP errors, just return status.
/NOHASH | Don't use file hash to determine if updated needed. This may speed up the process slightly for large files.
/NOTIME | Disable any use of the timestamp to decide whether the file needs to be transferred. This is a moot point, except when the /NOHASH switch is also used, in which case the determination will be based solely on the file size. The /NOTIME switch will be ignored for ATE versions prior to 6.1.1368.1.
/L{:f} | Output to file rather than screen. If filename ("f") is not specified, output file is ATSYNC.LST.
/V2 | Requests the new FTP implementation in ASHNET.DLL 1.6.138. Note that if the switch is specified, it will still use the old (FTPDLX) implementation if the ASHNET.DLL is not version 138+. This switch should significantly reduce the amount of time it takes to synchronize many files.
/?, /H | Writes switch listing and usage info to the screen.

Comments

ATSYNC only replicates files from the server to the client; it is not a general purpose two-way synchronization utility.

Files are transferred if they are different and the modification timestamp on the server is newer than that on the client. To ignore the timestamp, use the /NOTIME switch.

Unless the server and client copies of a file are identical, based on hash, modification time, and/or file size (see /NOHASH and /NOTIME switches), ATSYNC transfers the server's copy of the file to the client, even if the timestamp on the client copy of the file is newer than that on the server copy.

ATSYNC relies on FTP (or SFTP) as configured on the ATE client. The FTP root directory must agree with the root directory as seen by A-Shell on the server. See FTP Debugging.

The ATSYNC protocol is optimized to minimize latency time, especially if the /V2 switch is used, and to eliminate unnecessary transfers. It is therefore much more efficient than simply doing a wildcard transfer from the server to the client.

The /F{ILES} switch uses ATEAPX.SBX which must be present in the BAS: directory.

See Also

• discussion on the ATE environment variable.

History

2015 September, A-Shell 6.1.1417: AG_FTPSYNC (ATSYNC.LIT) fixes and refinements:

• Client will now accept a timestamp from the server which it uses to fine-tune the test for whether the source file is newer or older than the destination. This is useful in situations where the system clock and/or time zone is different enough between the server and client to create confusion as to which version is actually newer.

• Now, when the hashes are different (unless /NOHASH specified) or when the file sizes are different, the file is only transferred if the source timestamp is newer. Disable that logic with /NOTIME to force a transfer unless the hashes and sizes are the same. Previously it was always transferring files if the sizes were different.

• New version of ATSYNC adapts to the behavior of the client (based on whether it is before 6.1.1417.0 or not). This fixes an issue in which the /NOHASH switch was previously being misinterpreted by the client, causing the sync operation to not take place even if needed.

• Setting DEBUG mode was causing the final FTP operation to fail.

• Clean up the ambiguity in the ATSYNC.LST file relating to the client transfer log which is normally appended to the end. In cases where no files needed to be transferred, a previous copy of the client transfer log was being included.

• Clean up several other minor user interface issues.

Note that the updated ATE client will resolve these issues regardless of whether the ATSYNC.LIT on the server is updated.

2014 June, A-Shell 6.1.1387: /D now explicitly ignored with /F mode. The delete option doesn't really make much sense when not syncing an entire directory; attempting it could have had strange side effects.

2013 December, A-Shell 6.1.1368, 1369, 1370:

• In SBX mode, the normal /L message ("See ...") is eliminated, allowing for totally silent operation. For all other cases, it now reports the total time of the transfer operation, making it easier to see how much faster sync operations are with the /V2 switch.

• Add /V2 switch.

• Zero-byte files are now transferred just like any other files. Previously they were flagged to be transferred but then skipped by the actual transfer routine.

• Add /NOTIME switch.

2013 November, A-Shell 6.1.1366: ATSYNC.LIT 1.3(114) now includes the switch /F{ILES} allows you to replace the HostDir parameter with a file containing the list of files to transfer:

.ATSYNC HostDir{,PCdir}/FILES

The layout of the HostDir file should be a series of lines in the following format:

hostfile{,pcfile}

Each hostfile specification may be in either AMOS or native format and may be partially or fully qualified. The pcfile specification can be omitted, in which case the files will be transferred to the directory specified by the PCdir parameter on the ATSYNC command line. To override that, provide a fully qualified PC filespec in the pcfile parameter.

You may insert a ";" at the start of the line to comment it out.

ATE will create a log file called %ATECACHE%\ateftp.log for each file transfer, using the format:

status,hostfile,pcfile

Where status will be 0 for a successful transfer, else an error code. Hostfile and pcfile will be the fully qualified host and PC file specifications for the transfer.

If you specify the ATSYNC /L switch, the ateftp.log file contents will be appended to the list file. Otherwise, you can retrieve it manually using AG_FTP or some other method.

2013 August, A-Shell 6.1.1359: ATSYNC 1.2(112) now works both as a LIT and as an XCALL; just copy the LIT to SBX. The XCALL syntax consists of just one parameter containing the command line otherwise passed to the LIT, i.e.

CMD$ = "MYICONS:,%ATE%\myicons /P/L"

xcall ATSYNC, CMD$

to retrieve the exit status, you can call it via XFUNC, i.e.:

STATUS = XFUNC("ATSYNC", CMD$)

STATUS values:

Value | Meaning
0 | Ok
1 - 200 | BASIC error
< 0 | Internal errors in protocol
=> 30000 | FTPDLX error codes

If you'd like to customize the display, contact us for the source code.

2013 May, A-Shell 6.1.1353: Add /A{UX} switch.

2009 January, A-Shell 5.1.1177: The ATSYNC mechanism can now be disabled by creating a registry item DisableFileSync (DWORD) within the current ATE profile (HKCU\Software\MicroSabio\JBCT\ATE\Hosts\profile-name\DisableFileSync) and setting it to 1. The motivation behind this odd feature is to accommodate certain "power users" (presumably developers or tech support staff) who have to connect remotely to multiple sites (running different versions of the application) and who don't necessarily want to have icons, bitmaps, subroutines, etc. synchronised to the PC each time. You are on your own to create and set this registry value, but once set, ATSYNC.LIT will abort immediately with error -4.

2008 December, A-Shell 5.1.1131: ATSYNC.LIT 1.0(107) now supports hash codes as a way of making sure whether files are different or not. Also, it now works from within a CMD or DO file. Previously, the CMD file interfered with the input of status responses coming from the ATE client, causing it to act as if no files needed transferring.


CHAT

(UNIX only) CHAT allows two users to enter into a dialog in which they can type messages back and forth to each other; this is similar to PTCHAT.LIT under PolyTRACK. While in the dialog, their previous instance of A-Shell is put into the background, and automatically restored to the foreground when the dialog is over.

CHAT <target name>

Target name may be either the job name or the login user name of the person you want to chat with. (You can use the SYSTAT command to help you determine this information.) The target user will then get a pop-up message on his screen asking him if he wants to engage you in dialog. If not, or if he does not respond within fifteen seconds, the dialog does not take place. While this is happening, the originating user will have been returned to the dot prompt and can go on running another program. If the target user does engage, at that point, a similar phenomenon will happen with the originating user. (A pop-up dialog appears on the screen, suspending the previous process.) Once the dialog begins, it continues until either user exits by hitting the Escape key. At that point, the dialog is closed on both screens and both users go back to the process that was previously running.

Note that because of UNIX security rules, it is impossible for one user to send signals to another unless the first user has superuser privileges, or unless they are both sharing the same effective user ID. Refer to File Ownership and Privileges for instructions on achieving this.


COMPIL

Updated October 2015; see History

COMPIL and its aliases COMPLP and OCMPIL each process an AlphaBasic or A-Shell/Basic source file, creating a compiled RUN file which can be executed by RUN.LIT. Using COMPIL as an example, the syntax for all three commands is:

COMPIL srcfile {switches}

For example:

COMPIL MYPROG.BAS /X:2/LF/M/C:APP_VER=9

See Compiler Edit History for information on changes to the compiler.

Parameters

srcfile

specifies the program source file (with an assumed extension of .BAS or .BP). If omitted, COMPIL will display the internal compiler version number.

switches

provide options and expanded capabilities. Note that there several switches supported by A-Shell which are not supported by AMOS (AV, C, D, DEBUG, LF, MX, RC, V:1, VC, X:2, and X:3).

Switch | Function
? | Display list of switches.
13 | OCMPIL mode (AlphaBASIC 1.3 compatibility)
A | Increase size of offsets used for program addresses from 16 to 24 bits. This fixes "transfer address out of range" compiler errors. Beginning with COMPIL version 1.0(112), /A is invoked automatically (as needed).
AV | Additional Variables: Extends the allowable number of variables.
B | Background: Send errors messages to <sourcefile>.lst.
C | (C:symbol=value) Provides for passing Compiler Symbol Definitions.
CI | Enables case insensitive compilation. Note that this applies to labels and function/procedure names as well as variables and symbols.
CTAGS | Outputs just a list of ++include files to <source>.LST. Mainly for internal use by APN.
D | Enables use of certain d/BASIC statements.
DEBUG | Activate conditional debug code by compiling the variable DEBUG as 1.
I | Allow the use of ISAM 1.0 statements (not relevant for OCMPIL or /13)
IGOO | Treats all ++includes as ++include'once; "IGOO" = Include Global Once Only.
IEEE | Assume F,8 instead of F,6 if variable size is not specified.
LF | Creates a consolidated List File showing all of the source with location offsets.
LI | Local Include causes the directory information on any ++INCLUDE statement to be ignored.
LSM | Create .LSM file containing metadata used by APN.
M | Mapped variable required: causes compiler error for any unmapped variables.
MX | Unmapped Variable List: Reports every line in which an unmapped variable appears.
N | Turns off the display of compiler statistics.
O | Removes the internal line number references from the compiled object code, making it smaller and faster, but eliminating the capability for error handling routines to display the line number of the error.
RC | Run Compatible: Preserves runtime compatibility for AMOS.
S | Silent: Turns off the display of ++include file names.
T | Trace: Display source code as it is being processed.
V:1 | Attempts to duplicate AMOS 1.4 and higher.
VC | (VC:pattern) Version Copy causes the compiler to make a backup copy of every source module encountered according to the specified pattern.
XTAGS | Outputs a "tag" file to <source>.TAGS. Mainly for internal use by APN.
X:1 | Enables use of certain BASIC Plus syntax elements. These are clarified in more detail in the section on BASIC Plus extensions.
X:2 | Enables the use of certain A-Shell extensions to AlphaBASIC. See A-Shell Extensions.
X:3 | Same as X:2, but creates an SBX file instead of RUN.
Definition File: compil.def

Comments

The three LIT commands are just wrappers which process parameters and then call the internal compiler module embedded inside the A-Shell executable (via XCALL MIAMEX, MX_COMPIL). In fact, they are all the same, but they act slightly differently (mostly in terms of default switches) based on looking at their own name at runtime.

· OCMPIL (equivalent to COMPIL with /13 switch) is designed to emulate the AMOS AlphaBasic 1.3 compiler of the same name.

· COMPIL emulates the AMOS AlphaBasic 1.4 compiler.

· COMPLP is equivalent to COMPIL/X:1 and is designed to emulate the AMOS BasicPLUS compiler of the same name.

Note that the OCMPIL nearly always produces the exact same output (RUN file) as the AMOS equivalent, and thus is the best choice when cross-platform compatibility is important. On the other hand, it lacks several features, such as support for ISAM-A, structure loops, SWITCH, user-defined functions and procedures, etc., and thus is the worst choice when developing for the A-Shell platform exclusively.

In addition to the three LIT wrappers, there are two standalone (native executable) implementations of the compiler, which do not depend in any way on the presence of A-Shell:

compil.exe (Windows)

compil (UNIX)

For the standalone implementations, the switches are the same, but the syntax is slightly different. The switches must precede srcfile, use the lead-in character "-" (rather than "/"), and are case sensitive (must be lower case). For example:

c:\compil.exe -a -b -m -x:2 prog.bas)

There is also another front-end, RECOMX.LIT, distributed in the SOSLIB, which compiles all of the BAS and BP source files in the current account. The source code of RECOMX is provided so that the switch settings can be customized for individual developers.

See A-Shell Extensions for additional details of the compiler and related language features.

History

2015 October, A-Shell 6.1.1420: Add CTAGS and XTAGS switches.


Additional Variables

The AV switch allows the "variable index area" to exceed 64K. Furthermore, like with the /A switch (which is implied by /AV), unless OPTIONS=STRICT, the compiler will automatically restart the compilation using /AV if the program would exceed the 64K variable index limit. Normal variables require ten bytes of indexing space each (array variables take more), so this limited programs to something less than 6400 variables. With /AV, the limit becomes 256 times greater. /AV is independent of other compiler switches (except /A), so you don't need to go to BasicPlus mode, but any RUN file thus compiled will not be compatible with AMOS, nor with any version of A-Shell prior to 4.9(857). You will get the error "RUN file is in an incompatible format" if you try to run such a program under AMOS or an earlier A-Shell.

History

2004 January, A-Shell 4.9.859: COMPIL invokes /AV automatically only if STRICT is not set.

2003 December, A-Shell 4.9.857: AV switch added.


Background

The B switch enables background mode, which sends all error messages to the file <srcfile>.lst instead of the screen. The format of each message is:

<filename>, <line#>, <error message>, <source line>

Background mode is mainly useful for integrating program compilation into an editor.


Compiler Symbol Definitions

Reviewed September 2008

The following command line switch supports passing symbol definitions into the compiler. Syntax:

/C:symbol {=value}

Example

COMPIL MYPROG/RC/C:APPVER=2/C:GUI="VISTA"

This specifies the /RC switch, plus two instances of /C to define two symbols, APPVER=2 and GUI="VISTA". These definitions are treated exactly as if the following had been inserted at the top of the MYPROG source code:

define APPVER=2

define GUI="VISTA"

Note the need for quotes when defining a string symbol (per the normal rules of the DEFINE statement).

If the =value clause not specified, it is treated as = 0, i.e. the symbol is defined (responds to ++IFDEF <symbol> but it has a null value.

Example

COMPILER_VERSION Macro


ISAM

In COMPIL (1.4) and COMPLP (BASIC Plus) modes, the I switch causes ISAM 1.0 statements to be accepted (and in the case of ambiguous open statements, for ISAM 1.0 to be assumed). Otherwise, old ISAM statements are only accepted in OCMPIL mode. New file type open specifiers ISAM’INDEXED{‘EXCLUSIVE} and ISAMP’INDEXED{‘EXCLUSIVE} can be use to avoid ambiguity and to allow both ISAM 1.0 and ISAM-A to coexist in the same program.


List File

New/rewritten December 2016

The List File compiler option—/LF for COMPIL.LIT, -lf for the standalone compiler—generates a consolidated list file showing all of the source code, with all of the ++include files merged in. The list file is known as the "LSX file" (LiSt with indeX), is named <prog>.LSX, and is created in the same directory as the main program source. Some of its attributes and uses are detailed in the comments below.

Standalone Recompilability

Since the LSX file contains all of the source code merged in from all the ++include statements, it effectively captures the entire state of the source code at the time it was compiled, and thus provides an easy way to archive the source corresponding to a particular RUN or SBX module released. The top of the LSX file indicates the compiler version and switches, which you can use to regenerate the compiled output directly from the LSX file. For example, the LSX file for a program named ASHDEVINF.BP may contain the following at the top...

Command line args >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

/av /i /x:2 /lf /p /m  [Ver: 6.3(788)]

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

000000 PROGRAM ashdevinf.bp,1.0 (102)

000000

...

To recompile the LSX, just specify the LSX extension along with the original switches, i.e.

.compil ashdevinf.lsx/av/i/x:2/lf/p/m

Note that you probably don't need to specify the /lf switch again, since you already have the LSX file, but if you do, it will create a new one with a .LSY extension.

Also note that you can make minor edits to the LSX file and recompile it, perhaps to fix a minor bug in an older version of a program which has since undergone many changes that you don't want to introduce along with the bug fix. The only trick here is that the compiler expects every line of source code to be prefixed with the six digit location counter (see below) followed by two spaces, which you'll need to manually add to any lines you add. However, this is just a syntactic formality; the compiler does not care about the value of the location counters in the LSX file, so you can just set them all to a dummy value like 000000 or 999999.

Location Counters

The LSX file contains the location counter for each line of the source code, providing a way to located the source corresponding to BASIC errors. Traditionally programmers used line numbers for this purpose, but line numbers are cumbersome to deal with, cluttering up the source code, requiring renumbering utilities and management schemes to avoid duplicating line numbers in ++include modules, making the RUN modules larger and adding to the execution overhead. In modern A-Shell BASIC they have mostly been deprecated in favor of location counters, which require no additional overhead or effort, other than to keep a copy of the LSX files corresponding to the compiled programs for cross-reference purposes.

The standard BASIC error messages contain the location counter automatically, but if you are trapping errors yourself, you can retrieve the location counter using the ERR(8) function. You can also use the Dot Variables .LOCATION to retrieve the current location file, independent of error processing; see History notes below. Because it takes effort on the part of the user to write down and report error messages faithfully, and/or effort by the programmer to programmatically track them, you may want to take advantage of the built-in BASERR TRACE—by adding TRACE=BASERR to the miame.ini—which results in all BASIC errors, whether trapped or not, being logged to the ashlog.log file along with their location counters.

Note that by convention, location counter values are displayed in hex within internal error messages, log messages, LSX file, etc. But since the PRINT statement only outputs in decimal, you'll need to use a function such as MX_OCVT or the SOSLIB function Fn'Dec2Hex$() to convert the ERR(8) or .LOCATION values to hex, e.g. PRINT Fn'Dec2Hex$(ERR(8)).

Also note that because the LSX file only shows the location counter at the start of each source line, while an error might occur at a location in the middle of a source line, the location counter reported for an error may not necessarily match any location counter shown in the LSX file. For example, consider the following LSX excerpt:

003337       ELSEIF (dlg'ashdevinf_cntlsup_ary(x).gen'type = 5) THEN

00334f           menucntl = dlg'ashdevinf_cntl_ary(x)

00335b           IF (ABS(menucntl.clickcode) = ABS(click)) THEN

003369               fn'dlg'ashdevinf_clickcode2pointer = x

003371               EXIT

003375           ENDIF

003375

003375 !     comment bla bla bla

003375       ENDIF

003375   NEXT x

If the value of (x) in the second line generates a subscript out of range error (BASIC error 8), the location counter reported for the error will probably be somewhere between the location given for the start of the line (334f) and the location for the start of the next line (335b). So to locate the error, you'll just have to scroll through the LSX to find the pair of lines that bracket the error location.

The above example also illustrates the fact that many source lines do not increase the location counter at all, since they don't generate any executable code. The last 5 lines shown all have the same location counter, 3375.

Auto-Mapped Variables

If you don't use the /M switch, which reports un-mapped variables as errors, the compiler will automatically generate MAP statements for any such variables, and these will be listed near the bottom of the LSX file as follows:

MAP1 AUTO'MAPPED'VARS

    MAP2 COMMON'RKEY,F,6

    MAP2 COL'X,F,6

    MAP2 COPIES,F,6

This explicit listing provides a relatively easy way for you to come in from the figurative cold—of living with the subtle errors introduced by inevitable typos—to take advantage of the compiler's ability to point out those typos to you before they become bugs. Just copy the AUTO'MAPPED'VARS MAP statements from the LSX file back to the original source and then you can compile with /M. That won't help resolve issues related to typos you've already introduced—although perhaps in seeing the AUTO'MAPPED'VARS all together, you might spot some suspicious ones—but it will allow you to benefit going forward.

Unreferenced Variables

When the /LF switch is used to create an LSX list file, unreferenced variables are listed at the end, as a convenience for those interested in clearing dead weight out of program. Note, however, that these are not errors, and in many cases, it isn't even desirable to remove them. For example, it is common to group misc variables under a heading, e.g.

MAP1 WORK'VARS

MAP2 X,F

etc.

Typically in the above case, there would probably be no explicit reference to WORK'VARS, but you couldn't just delete it without elevating the MAP2 variables beneath it to MAP1. So the new feature is only to be used a guide or ignored as you see fit.

Note: see Compiler Edit History, edits 452 and 500, for additional info on the List File option.

Procedure Reference Count

When compiling with /P or /PX, a section will be added to the bottom of the LSX file listing all the procedures and functions defined in the program, along with the reference count—i.e., the number of times the routine is called. For example:

Procedures, Functions [reference count]

======================================================

Fn'NextCh(ch) [2]

Fn'XMList'Load'Doc($xml,xmldoc$) [1]

Fn'XMList'Save'Doc($xml,xmldoc$,level,och) [0]

Fn'XMList'Get'Subtree'Callback($xml,item$,parent$,flags,$response) [1]

In the above example, we can see that there are several functions which are defined but are never used. These don't hurt anything, other than making the RUN modules larger than they need to be, so we might want to remove them. Fortunately, the /PX switch will do this for us automatically, showing a "<nc>" (for Never Called) next to any function that gets removed by this "tree-shaking" feature, e.g.

Procedures, Functions [reference count]

======================================================

Fn'NextCh(ch) [2]

Fn'Load'Doc($xml,xmldoc$) [1]

Fn'Save'Doc($xml,xmldoc$,level,och) [0] <nc>

Fn'Get'Subtree'Callback($xml,item$,parent$,flags,$response) [1] <nc>

Fn'Walk($xml,@fn'callback=.NULL,level=0 ,parent$=.null ) [0] <nc>

The above shows that the last three functions were removed from the RUN module, because they were never called. Note that this can occur even when the reference count is non-zero, as in the Fn'Get'Subtree'Callback example above, which was apparently referenced once, but still marked <nc>. This occurs when the only references to the target routine occur within other routines which themselves are never called. In the above case, it may be that the function Fn'Walk() references Fn'Get'Subtree'Callback(), but since Fn'Walk() is itself not referenced anywhere and thus never called, then by extension, Fn'Get'Subtree'Callback() is never called, and can thus be removed.

Note that routines that are removed by the /PX switch still show up in the LSX file, but the location counter will not increment. The routines removed this way are essentially treated by the compiler as if removed by conditional compilation logic.

Duplicate ++includes

You may find when perusing your LSX files that there are ++include files listed multiple times, because they are included from within multiple modules, but then conditionally compiled so as to not actually generate duplicate code. For example...

002339 ++include sosfunc:fnextch.bsi

! SOS63:FNEXTCH.BSI[907,10] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

002339 ! Function Name:  Fn'NextCh(ch)

...

002339 ++ifndef INC_FNNEXTCH_

002339  define INC_FNNEXTCH_ = 1

002339

002339 Function Fn'NextCh(ch as b4:inputonly) as b4

002339

002339     if ch = 0 then     ! [102]

002339         ch += 1

002339     endif

...

The above excerpt shows the ++include statement for the module sosfunc:fnextch.bsi, which contains a ++ifndef statement to prevent it from being compiled more than once if it is ++include'd multiple times. And we can see unchanging location counter (002339) that the compiler did not actually generate code for this instance of the module. The same phenomenon will occur if the routine is removed by the /PX switch because it is never called.

Note that while there is no real harm associated with these multiply-included but only singularly-compiled modules, they do take up space in the LSX file, and they do burn up a few extra CPU cycles as the compiler parses them, even if not actually "compiling" them. To avoid that, you may replace the ++include statements with ++include'once; or or add a ++PRAGMAs INCLUDE_GLOBAL_ONCE_ONLY, or use the /IGOO compiler switch, do automatically treat all ++include statements as if they were ++include'once).

Also See

The compiler /LSM switch which generates another kind of list file containing program metadata which is mostly used by APN, but which is somewhat related to the metadata contained in the LSX file.

History

2016 June, A-Shell 6.3.1514, Compiler edit 762: /PX switch added to the compiler.

2014 March, A-Shell 6.1.1382, Compiler edit 663: Function list with reference count added to LSX

2014 January, A-Shell 6.1.1373, Compiler edit 652: /P switch added to compiler

2007 June, A-Shell 5.0.990 , Compiler edit 356: /LF switch added to the compiler (LSX file introduced)

Note that the above feature introductions were subject to various subsequent fixes and enhancements; for details see the Compiler Edit History and search for "LSX."


Unmapped Variable List

The /MX switch acts like /M except that it reports every line in which an unmapped variable appears, even if that variable has already been reported. Note that, as with other errors, typically only the first error on a line is reported. Otherwise you might get dozens of errors on each line due to the cascading effect.

History

2004 September, A-Shell 4.9.902: Switch added to A-Shell. See the Update note for edit 1177 related to List File (/LF) for an approach to getting a large number of unmapped variables under control.


Run Compatible

Updated and Reviewed August 2010

The RC switch enables the use of several compiler and source code enhancements without breaking backwards Runtime Compatibility with AMOS. To be effective, you must use with COMPIL.LIT / OCMPIL.LIT 1.0(117)+ (not COMPLP) and without any of the /X:# switches. The idea is to accommodate people who want to compile under A-Shell and use as many A-Shell features as possible, but still retain the option of copying the RUN files to AMOS for execution there. RC was added to A-Shell in Build 924 of 29 March 2005.

The features which /RC adds to COMPIL or OCMPIL can be divided into fully and partially supported categories, as shown below.

Fully Supported:

DEFINE | SIZEOF(var)
DEFSTRUCT / ENDSTRUCT | Use of underline in identifiers
Hex, Octal, ASCII Literal Values (&h10FC, &o1777, 'a') | Max source line length of 3070 instead of 512
IF / ELSE / ELSEIF / ENDIF | ++INCLUDE nested 13 levels deep
DO / WHILE ... UNTIL / LOOP | ++PRAGMA (all)
BasicPLUS-style FOR/NEXT semantics (test before loop) | Comment may follow an & on a continuation line
EXIT / REPEAT | ++ERROR, ++MESSAGE
SWITCH / ENDSWITCH | Conditional compilation (++IF, ++IFDEF, ++IFNDEF, ++IFMAP, ++IFNMAP, ++ELSE, ++ELIF, ++ENDIF)
Shortcut Operators (var += <expr>, etc.) |

Partially Supported:

3D TAB(x,y,z): z value ignored | DPRINT / EPRINT / TPRINT: compiled as if PRINT
TRACE.xxxx / DEBUG.xxxx: compiled as XCALL EVTWIN | DIMX: compilation only, and only if OPTIONS=RC_DIMX.

See the discussion on A-Shell Extensions for more information on all of the above statements and features.

Subtopics

Single Code Base


Single Code Base

Here are some strategies for managing a single code base for deployment under AMOS and A-Shell.

If you are willing to maintain a single source code base, but generate separate RUN modules for each run-time environment, then you can take advantage of conditional compilation directives to separate out the code that isn't cross-compatible. For example:

++if RUN_VER = "ASHELL"

INPUT CSV #CH, name$, addr1$, addr2$, comments$

++else

<some alternative logic not relying on A-Shell specific features like INPUT CSV>

++endif

In this case, for the A-Shell compilation, you can, for example use COMPIL /X:2/C:RUN_VER="ASHELL" to compile the A-Shell-specific sections and ignore the AMOS-specific sections. For the AMOS version, use COMPIL /RC (optionally with /C:RUN_VER="AMOS" in place you plan to test for that condition explicitly). If you accidentally include some non-AMOS compatible code outside your ++if RUN_VER = "ASHELL" condition blocks, the compiler will flag these as errors in the version of the compilation without /X:2.

You'll be able to distinguish the different RUN versions using the VERSYS utility.

If, on the other hand, if you would rather maintain just a single set of RUN modules which work in all environments, then you pretty much have to limit yourself to only those features that are supported by /RC (which leaves out, for example, user-defined functions and procedures). The only alternative would be to compile with /X:2, but make sure that you separate out your A-Shell-only or AMOS-only code via run-time IF statements. For example:

<runtime logic to set RUNVER$ to "ASHELL" or "AMOS" - perhaps using GETJTB.SBR>

if RUNVER$ = "ASHELL" then

INPUT CSV #CH, name$, addr1$, addr2$, comments$

else

<some alternative logic not relying on A-Shell specific features like INPUT CSV>

endif

The above technique also requires one further trick in order for AMOS to accept the RUN modules created by the A-Shell compiler when using /X:2: you will need to manually modify the RUN header. The 11th and 12th bytes of the RUN file contain a series of flags which indicate to the run-time system certain attributes of the RUN module, such as whether it was compiled with OCMPIL or COMPIL, /A or not, etc. This allows the run-time interpreter to properly interpret the RUN code, and also to identify RUN modules that are incompatible. Trying to run an invalid RUN module will most likely result in "illegal syntax code" errors (error #34).

To modify the RUN header to make it appear to be AMOS-compatible, write a Basic program to treat the RUN file as a RANDOM file with a record size of 1, allowing you to manipulate the 11th and 12th bytes. To determine what they should be, use VERSYS to look at similar RUN modules compiled under AMOS. In particular, be careful about /A (and /AV), since if the associated header flag bits are not correct, the program will crash. For this reason, you may want to use /A explicitly on all compilations, whether needed or not, so that you can use a fixed RUN header. Otherwise, the A-Shell compiler will invoke /A (and /AV) automatically as needed and your utility to patch the header will have to leave the /A and /AV bits alone.


Silent

The S switch turns off the display of ++include file names. (This conflicts with the AlphaBASIC Plus compiler which uses /S for .SBR instead of .XBR subroutine extensions. Under A-Shell, subroutine name extensions are irrelevant, since they are linked into the executable.) Note that since eliminating the ++include messages makes it difficult to determine which include file an error occurs in, the error message format is modified by this switch to include the file name and line number.


Trace (T)

The T switch displays source code as it is being processed. This sometimes makes it easier to track down errors, although the error messages always include the line numbers. You may want to use the PAGE.LIT utility to manage the speed of the display (e.g. PAGE COMPIL ABC/T).


AMOS 1.4

The V:1 switch attempts to match new features and quirks of the AMOS version of COMPIL.LIT 1.4(309) and higher (released with AMOS 2.3A). Unfortunately, although this version of COMPIL shares the same major and minor version number (1.4) with preceding versions, it introduces some new features and generates RUN modules with various differences, causing them to be incompatible with earlier versions of RUN.LIT. This is true under both AMOS and A-Shell. The main reason for using this switch would be if you are using a source code feature that was not previously supported. WARNING: Even with the /V:1 switch, the A-Shell compiler does not support all of the AlphaBASIC 1.4 changes and may not generate the same hash as the AMOS version. Also note that /X:1 and /X:2 both implicitly give you /V:1 features. Features that are activated by /V:1 include:

· LOOKUP returns 0.5 for a zero block file

· READ’ONLY option on OPEN statements

· READ’READ’ONLY statement

· ALLOCATE’INDEXED supports the Device param.


Version Copy

Reviewed April 2010

When specified, VC ("Version Copy") causes the compiler to make a backup copy of every source module encountered (the main program and any ++include files) according to the pattern. The idea is to provide a simple way to archive source code, which is sensitive to program versions.

The pattern is made up of literal characters, plus any of the following:

Symbol

Meaning

%d

directory of the original file (e.g. c:\vm\miame\dsk0\150100\)

%f

filename of the original file, minus extension (e.g. myprog)

%e

extension of the original file (e.g. bas)

%v

vedit value of the file. For the main file, this comes from the program statement, e.g. "PROGRAM name,M.ms(eee)" where M=VMAJOR, m=VMINOR, s=VSUB and ###=VEDIT. For included files, it comes from a comment found anywhere in the file, having the following form:

!VEDIT = ###

Spaces around the "=" are optional, and the ### may be one to five digits long. Following the last digit, to the remainder of the line, no characters are allowed except spaces and "!". These restrictions are to avoid confusing an occurrence of "VEDIT" in, say, an assignment statement, with a declaration of the version number of the source file.

Note that VUE uses the same rules to identify the VEDIT statement, used in two special commands related to using the VEDIT value:

Command | Result
^_E | increments the VEDIT value and inserts a partially filled in dated edit history line at the cursor location
^SE | inserts a "[###]" at the cursor location (### = the current VEDIT value)

If no VEDIT value is defined for the current file, it is treated as 0.

For example, consider an original program file (after conversion to local syntax) of c:\vm\miame\dsk0\909060\sqltest4.bp :

/vc:%d%f-%v.%e ==> c:\vm\miame\dsk0\909060\sqltest4-104.bp

/vc:c:\backup\%f.%e ==> c:\backup\sqltest4.bp

/vc:%dalpha-%v-%f.bak ==> c:\vm\miame\dsk0\909060\alpha-104-sqltlest4.bak

The pattern may also be quoted, which is necessary in order for it to contain spaces or slashes, i.e., under UNIX we might have:

/vc:"%dback up/%f.%e" ==> /vm/miame/dsk0/909060/back up/sqltest4.bp

Without the quotes, the pattern will be terminated at the first space or forward slash.

Note that if the %d (directory) directive is omitted from the pattern, the copied file will be placed in the current directory. This would be one easy way to get all of the ++included modules used by a program into one directory. See the following topic on the /LI switch for a related feature.

History

2010 April, 5.1.1177, compiler edit 451: switch added to A-Shell.


Local Include

Reviewed April 2010

When the COMPIL /LI switch is specified, the directory information on any ++INCLUDE statement is ignored; the file is loaded from the current directory. This might be useful in situations where, for reasons of portability or archival, you might consolidate all of the ++include modules associated with a single program into a single directory. Compiling with /LI would then eliminate the need to edit all of the ++INCLUDE statements to remove the directory specifications.

For example, you might use the switch /VC:c:\archive\%f.%e to make a copy of all the source modules associated with a program into the directory c:\archive. To compile to copy made in that directory, you could then log into that directory and use the /LI switch.

Note that a related feature is always activated: when the compiler is unable to locate the specified ++include file in the specified directory, or in the BAS: account, it will look in the location where the main source file was loaded from. (In comparison, the /LI switch ignores the specified and BAS: locations and only looks in the current directory.)

Note that when using the compil.exe version of the compiler, if you are compiling from a difference directory than where the source files are, you may need to specify the -l switch in order to establish the current directory context from which the -li switch will be processed.

This switch was added to A-Shell in build 1177 of April 2010, compiler edit 451.


Compiler Edit History

Following is a list of recent and significant changes to the compiler. The gaps in the numeric sequence indicate edits that were minor enhancements or bug fixes. Note that the descriptions below are just summaries; for full details, refer to the appropriate topic(s) elswhere in this document and/or to the applicable version of the A-Shell Development Notes. For compiler changes prior to the release of A-Shell 6.1 and compiler edit 600, refer to the A-Shell 6.0 Development Notes.

A-Shell 6.3/6.4 below here, A-Shell 6.5 above

2017 March, A-Shell 6.4.1547, edit 803: the line marking the end of a ++include now also indicates the module that we are returning to.

2017 March, A-Shell 6.4.1546, edit 797: maximum nesting levels for ++INCLUDE and ++IF conditions increased from 20 to 40. Improve messaging/recovery for the overflow condition.

2016 November, A-Shell 6.3.1538, edit 792: add new dot functions .LINENO and .LOCATION.

2016 October, A-Shell 6.3.1534, edit 790: use of .ARGCNT within a PRIVATE_BEGIN / PRIVATE_END block now generates a compile error. Although the expression wouldn't technically be illegal, because the PRIVATE block is essentially called for initialization by whatever function or procedure in the module gets called first, there's really no good way to predict in advance what the .ARGCNT value will represent, and thus it is almost certain to create a discrepancy between the expected and actual behavior.

2016 September, A-Shell 6.3.1528, edit 779: adds pragma ++pragma INCLUDE_GLOBAL_ONCE_ONLY <boolean> . When enabled, ++include is treated as ++include'once, except when it occurs inside a function or procedure. In such cases, it is likely that you are intentionally including an extra copy of some map statements.

2016 September, A-Shell 6.3.1528, edit 778: adds auto-defined macros ABC_CURRENT_ROUTINE$ and ABC_CURRENT_MODULE$. These equate to the current function/procedure name (or "" if none), and the current module filename (file.ext). Both may be useful in standardized error reporting.

2016 September, A-Shell 6.3.1528, edit 777: adds three pragmas: +PRAGMA ASHELL_EXTENSIONS <boolean>, ++PRAGMA PRE_PROCESS <boolean>, and ++PRAGMA EXTENDED_PRE_PROCESS <boolean>

2016 September, A-Shell 6.3.1528, edit 776: adds indirect function calls.

2016 September, A-Shell 6.3.1527, edit 774: adds .INSTRR function

2016 September, A-Shell 6.3.1526, edit 773: adds IFELSE functions

2016 August, A-Shell 6.3.1523, edit 770: adds Private Attribute for Functions and Procedures

2016 July, A-Shell 6.3.1517, edit 764: Enhancement to recognize the new random generator functions RND() and SRND() in /X:2 mode.

2016 April, A-Shell 6.3.1508, edit 761: Optimization of PRIVATE_BEGIN/END logic so that the initialization is effectively "lazy", i.e. delayed until code within the module is executed. This eliminates unnecessary initializations that would otherwise occur if the ++include for the module is placed near the top of the parent program.

A-Shell 6.1/6.2 below here, A-Shell 6.3/6.4 above

2015 October, A-Shell 6.1.1420, edit 756 & 758: Compiler/APN change/refinement (edits 756 & 758): ++IF, ++IFDEF and ++IFNDEF directives are now being "obeyed". Previously, all of the ++IFxxx directives were being ignored, resulting in both the True and False sections being included in the tags. This was harmless in some cases, but in others it was resulting in duplicate tags, which interferes with the ^ALT+G command. Note however, that since neither MAPs nor labels are "compiled" by the tagger, ++IFMAP, ++IFNMAP, ++IFLBL and ++IFNLBL directives continue to be ignored—i.e. no source code is excluded by them or their associated ++ELSE and ++ELIF directives. Also, SIZEOF(var) will evaluate to zero. Hopefully this represents the sweet spot on the compromise between file loading/tagging speed and accuracy.

2015 September, A-Shell 6.1.1418, edit 751: Compiler now generates the tag output used by APN, eliminating the need to call the external tagger and speeding up file loads substantially. Note that this only applies to the standalone compil.exe and APN.

2015 August, A-Shell 6.1.1416, edit 748: MAP2+ statements are now flagged as illegal if not preceded by a finalized MAP1 statement.

2015 August, A-Shell 6.1.1416, edit 747: Compiler bug fix ***SERIOUS***: Referencing a variable in a MAP statement initializer was causing the side-effect of finalizing the parent MAP1 definition, which was then causing it be encoded in the RUN file with the wrong size.

2015 August, A-Shell 6.1.1414, edit 744: Attempting to define a local dimx byref array without the required initial subscript value of -1 is now flagged as an error. Previously, no error was generate but the pass-by-reference mechanism would not have worked correctly.

2015 August, A-Shell 6.1.1414, edit 743: MAP statements with initial values, when part of a DEFSTRUCT, were generating improper assignments in the RUN file. Typically these were benign, but in some cases they were causing the program to abort with a nonsensical error code during the initialization.

2015 August, A-Shell 6.1.1414, edit 742: Add new Dot Function .ISNULL for use with ordered maps to test for the .NULL condition.

2015 February, A-Shell 6.1.1401, edit 740: DEFXCALL now allows all named parameters to be optional, i.e. to be enclosed in braces, e.g.: DEFXCALL MYSBR {,one=1, two=2, three$="3"}. Previously there had to be at least one mandatory parameter prior to the "{" marking the start of the optional parameters.

2014 November, A-Shell 6.1.1398, edit 734: When passing an entire ordmap to an XCALL, you can now use the more natural syntax with a pair of empty (), rather than having to specify a null string, e.g. (""). For example, in the CGIUTL opcode CGIOP_GETPARARY (see edit 1394 below), you can now specify the ordmap using () as in this example: xcall CGIUTL, CGIOP_GETPARARY, status, $req() {,stdin$} The old syntax is still supported, but is now deprecated and any existing programs using it should probably be changed after updating to this version.

2014 October, A-Shell 6.1.1396, edit 730: LSM files (/LSM compiler switch) no longer limited to Windows.

2014 October, A-Shell 6.1.1392, edit 718: You may now optionally use procedure-style syntax with the XCALL statement. In other words, instead of: XCALL NAME,ARG1,...ARGN, you can instead use XCALL NAME(ARG1,...ARGN). The advantage of the alternate syntax is perhaps mainly aesthetic, but will seem more natural to programmers coming from other language backgrounds. Another potential advantage is that it would allow APN call tips to be set up for common XCALLs, since the feature is triggered by typing the "(" which normally signals the start of a procedure parameter list.

2014 October, A-Shell 6.1.1392, edit 717: Add pragmas GLOBAL_BEGIN and _END.

2014 October, A-Shell 6.1.1391, edit 714: ++MESSAGE and ++ERROR output is now captured when executing in background mode—i.e. from within APN.

2014 October, A-Shell 6.1.1391, edit 713: ++include files without a line terminator on the last line should no longer generate syntax errors.

2014 October, A-Shell 6.1.1391, edit 711: New auto-defined COMPILER_VERSION macro equates to the compiler edit.

2014 October, A-Shell 6.1.1391a, edit 710: New dot variables .TRUE and .FALSE may be used as self-documenting replacements for -1 and 0.

2014 October, A-Shell 6.1.1391b, edit 710: New statement DEFTYPE may be used to define an alias for a data type.

2014 October, A-Shell 6.1.1391, edit 708: It is no longer required that function names start with fn'.

2014 July, A-Shell 6.1.1387, edit 685: LSX file now shows offsets for members within instances of structures.

2014 July, A-Shell 6.1.1387, edit 679: ++PRAGMA ERROR_IF_NOT_MAPPED "FALSE" may now be used to override /M or a previous "TRUE". Previously it was only possible to enable the /M switch, not disable it. Note that you can now turn the option on and off multiple times within a program, allowing you to get the benefit of the for new sections of code without being forced to clean up the unmapped variables in all of your code—i.e. in all of your include modules.

2014 July, A-Shell 6.1.1387, edit 678: Improve error reporting on missing ++endif; now lists all of the unmatched ++if statements in the stack.

2014 July, A-Shell 6.1.1387, edit 675: On first $COPY, attempt to also include <prog>.VER if it exists.

2014 July, A-Shell 6.1.1387, edit 672, 674: Support Madics $COPY directive. Similar to ++include but with default extension .cpy and different search paths.

2014 July, A-Shell 6.1.1387, edit 673: Compiler now allows a locally defined structure variable with same name as a module or global variable provided they are same type of structure.

2014 July, A-Shell 6.1.1387, edit 669-671: APN-related internal adjustments.

2014 June, A-Shell 6.1.1387, edit 668: Compiler now flags as an error an attempt to define a local structure whose name matches an auto-externed global or private (module) structure. Although this would be technically legal, it invites confusion likely to lead to difficult-to-detect bugs, especially when the local and module/global structures aren't even the same layout.

2014 June, A-Shell 6.1.1387, edit 668: Added support for -so switch to output errors to stdout rather than to a file or window. This makes it easier to interface with certain editors and IDEs.

2014 March, A-Shell 6.1.1381, edit 663: When using /P and /L, the LSX file now contains a list of all the procedures and functions, along with an indicator of how many times they were called.

2014 March, A-Shell 6.1.1381, edit 655: New statements ++IFLBL label, ++IFNLBL label and ++ELIFLBL label areanalogous to the existing ++IFDEF, ++IFNDEF, and ++ELIFDEF statements, as well as ++IFMAP, ++IFNMAP and ++ELIFMAP, except that instead of referring to defined symbols or mapped variables, they refer to labels—used by GOTO and GOSUB—as well as procedure and function names. Note however that when the specified label is meant to refer to a function or procedure name, it must be terminated by an empty pair of parentheses.

2014 March, A-Shell 6.1.1380, edit 654: The new UNDEF statement causes the specified symbol to be undefined, allowing it to be redefined or to fail a ++IFDEF symbol test.

2014 February, A-Shell 6.1.1373, edit 651: Two new dot functions, .ARGTYP(argno) and .ARGSIZ(argno), return the type and size of the specified argument passed to the current SBX, function, or procedure. If the specified argno is invalid, the return value will be -1.

2014 February, A-Shell 6.1.1373, edit 652/653: Subroutines, both internal and SBX, may now use named parameters for functions and procedures. Parameter passing to subroutines is nearly identical to that for procedures and functions, so the implementation details are nearly the same. The main difference is that since subroutines do not have definition statements like functions and procedures, a new statement had been introduced to allow you to define their parameter names and default values: DEFXCALL xcallname{+|,}pname{|alias}{=defval},pname{|alias}{=defval}...

2013 October, A-Shell 6.1.1363, edit 647: When a function or procedure definition occurs (illegally) within an extended IF or FOR statement, the compiler now reports the location of the unterminated IF or FOR statement. Otherwise, it may have occured countless lines or even modules previously, since there otherwise no limit to the size of the body of a FOR or IF statement, making it very difficult to find the problem.

2013 August, A-Shell 6.1.1358, edit 642: New variations of ++INCLUDE: ++INCLUDE'IF'EXISTS <filespec> and ++INCLUDE'ONCE'IF'EXISTS <filespec>. As the name implies, these operate just like ++INCLUDE and ++INCLUDE'ONCE except that if the file is not found in the normal search path, it is just skipped.

2013 April, A-Shell 6.1.1350, edit 633: New compile-time function .OFFSIZ$(struct.member) is a variation of the .OFFSET() function which returns the combination of the specified structure member's offset and size, as a string formatted as "offset~size". While the combination of the two values in a string may seem unusual, since the offset and size are often used together, the combined format eliminates the need to specify the struct.member name twice, which invites discrepancy, and lends itself to use in runtime functions that may parse out the two values and combine them with other information.

Also: SIZEOF(VAR) now handles a much wider variety of VAR arguments, including structure names, DIMX structure variables, etc. Also, for symmetry with .OFFSET(), .SIZEOF() may be used interchangeablywith SIZEOF()—i.e. with or without the leading dot.

2013 April, A-Shell 6.1.1350, edit 632: The new compile-time function .OFFSET(struct.member) is similar to SIZEOF(var) except that it returns the offset to the specified member variable within the specified structure, starting from 1, rather than the size of the variable, and it only works on fields within structures. Also, in the case of arrays, .OFFSET only returns the offset to the base of the array, and doesn't actually allow the use of subscripts. The specified structure name can either be a defined structure name, or a MAP'd or DIMX'd instance of it.

2013 March, A-Shell 6.1.1346, edit 627: Add new conditional compilation statements ++ELIFDEF <symbol> and ++ELIFMAP <var>. ++ELIFDEF is to ++IFDEF, and ++ELIFMAP is to ++IFMAP, as ++ELIF is to ++IF.

2013 March, A-Shell 6.1.1339, edit 624: The new pragmas PRIVATE_BEGIN ... PRIVATE_END may be used within ++include files to ensure that the module's private variables (MAP and DIMX) are initialized once and only once before they are used, regardless of the position of the ++include in the main program.


COPY

Updated June 2011; see History

COPY copies files from one place or name to another.

COPY {outspec} = inspec1 {inspec2, … inspectN} {switches}

Parameters

outspec

specifies an output file, using either AMOS-style (e.g. DSK1:MYFILE.DAT[123.4]) or native operating system, in which case it must be enclosed in quotes (e.g. "c:\temp\somefile.xyz"). When dealing exclusively with AMOS-style inspec files, outspec may be omitted, in which case it acts like *.*—i.e. uses the name.ext of each inspec file.

inspec

specifies an input file, using either AMOS-style or native operating syntax. AMOS-style filespecs may include the * and ? and [] wildcards (e.g. DSK2:[]*.TMP). Native filespecs must be quoted and may not contain wildcards. When the outspec is blank or *.*, you may list more than one inspec, provided they are all AMOS-style filespecs.

switches

Switch | Function
/D | Delete: overwrites an existing output file.
/Q | Query: prompts for a confirmation before copying each of the input files.
/C | Similar to {/query} except that it only prompts you to confirm whenever the destination already exists. Note: if you are prone to accidentally overwriting important files by loose-fingered copy commands, you may want to rename COPY.LIT to something else, then create a COPY.DO file which automatically invokes the /C switch.
/mindays:# | Ignore files changed within the last # days.
/minsecs:# | Ignore files changed within the last # seconds.
/NOD | No delete: does not overwrite existing files.
/? | Writes switch listing and usage info to the screen.

Comments

If all of the files on the command line (input and output) are in AMOS-style syntax, the wildcards * and ? and [] may be used on both sides of the equals (e.g. COPY DSK1:*.X?[] = DSK2:*.D?[]).

COPY preserves the modification time and ownership of the source file.

COPY skips wildcarded source files that have more than one extension, and displays a warning message listing the filename. You can still copy such a files using quoted native filespecs.

Copying from read-only devices under Windows: In general, COPY will try to preserve the attributes of the source file, such as the last-modified time stamp, archive bit, etc. One notable exception is that when copying from a read-only device (like a CD), it will remove the read-only attribute from the output file. (Otherwise files copied from CD would typically need manual adjustment to remove the read-only attribute.) However, this feature only works for source devices that A-Shell can detect as being naturally read-only. If this is not the case, you can force A-Shell to recognize the device as read-only by adding the ,RO flag to the DEVICE definition in the miame.ini.

COPY.LIT and MOVE.LIT are identical. Their behavior changes based on the name of the module. Both use MIAMEX, MX_COPYFILE function to perform the operation, the only difference being that MOVE sets the CPYF_MOVE flag.

Native (quoted) filespecs may contain environment variables, e.g. "%MIAME%\ashlog.log"

Examples

The following example simply makes a copy of FILE1.NEW called FILE1.OLD, overwriting an existing FILE1.OLD if necessary.

.COPY FILE1.OLD=FILE1.NEW/D

This example copies the specified file from the SYS: directory to the current directory.

.COPY=SYS:ERSATZ.INI

This makes copy of all of the files with BAS extensions in all of the PPNs of the current device/logical unit, plus the file DSK1:DIRECT.LST. The copies will all be in the current PPN and will all have SAV extensions.

.COPY *.SAV=*.BAS[],DSK1:DIRECT.LST

The following demonstrates the ability to create new directories as needed while copying files. It copies all of the files from DSK0:[50,*] to the corresponding PPN in DSK1:. Note that the ability to create new directories during the COPY operation is only available if you are currently logged into [1,2]. Furthermore, if the OPTIONS=STRICT setting is specified in the miame.ini, then you may not create files during a COPY command outside of the current project.

.COPY DSK1:[]=DSK0:[50,*]

The following two examples illustrate the use of a quoted native operating system filespec. In the second case, it also illustrates the use of %ENV% variables. (%MIAME% is an automatically created environment variable which points to the directory where the miame.ini is.)

.COPY "/tmp/backup of app.log" = OPR:APP.LOG

.COPY ASHELL.LST = "%MIAME%\ashlog.log"

History

2011 June, A-Shell 5.1.1221: Remove the limit on the number of PPNs allowed per device.

2010 April, A-Shell 5.1.1181: Add MINDAYS and MINSECS switches.


CREATE

CREATE <file>, <blocks>

CREATE allocates and fills a file with the specified number of 512-byte blocks.

Under AMOS, "random" or "contiguous" files are actually different in structure from the normal "sequential" files, and as the name implies, are allocated in contiguous space. Under Windows and UNIX, there is no equivalent concept, nor is there a need for one. All data files can be accessed using either the "random" access method or the sequential method. In fact, a file allocated with CREATE could later be accessed as if it were a sequential file. Since there is no perfect way to recognize whether an existing file was created with CREATE (and thus should be treated as a "random" file) or via a sequential output process, A-Shell can only guess based on whether the file size is a perfect multiple of 512 bytes. If so, there is a very good likelihood that it was intended to be a random file. If not, then it must be a sequential file. The only significance of this decision is for the DIR/F operation (which indicates contiguous files with a "C"), and for the BASIC LOOKUP statement, which by default returns a negative number to indicate random or contiguous files. (The miame.ini setting OPTIONS=ABSLOOKUP eliminates that distinction, causing all files to be reported as positive numbers.)

The OPTIONS=BRKALC switch in the miame.ini affects what the newly allocated file is pre-filled with. When set, the file is filled with brackets (]]]]). Otherwise, the contents will be whatever was previously occupying that disk space.


DATE, TIME

The A-Shell implementations of DATE and TIME differ from AMOS in that it is only possible to display system date or time information and not to change it. An attempt to set the date or time will result in the following message:

?You must use the host operating system to reset the date (or time)


DEL

DEL <spec> {/unlock}

DEL under A-Shell is nearly equivalent to the version under AMOS except that the A-Shell version supports the unlock switch, which is necessary to delete modules which have been loaded with the /Lock switch.


DEVTBL

DEVTBL displays the names of the defined A-Shell devices. This is essentially just a list of the DEVICE= statements from the miame.ini file.

You can use the PPN command on any of the defined devices to display the available PPNs on that device.


DIFF

DIFF {listfile=} oldfile, newfile {/w}

(UNIX only) DIFF is an A-Shell front-end to the standard UNIX diff utility, with is much faster and more powerful than the SRCCOM.LIT utility. Like the SRCCOM utility, the standard version lists the lines that are different between the two specified files. The differences between DIFF and SRCCOM are:

· DIFF ignores differences that are just white space (i.e. a TAB and three spaces is treated as no different than a single space).

· DIFF has no switches (although you are welcome to add your own!)

· DIFF uses the UNIX-like space delimiter to separate the two filespec arguments, rather than a comma or comma space to separate the files.

· DIFF displays its output in the EZTYP viewer rather than just outputting to the screen.

Since DIFF is simply a front-end to the UNIX diff, and since source code is provided (in the SOSLIB), you can easily modify it to take advantage of other features supported in the UNIX diff.

The only switch supported is /w, which causes DIFF to ignore differences comprising white space only.

If you create your own variation of DIFF.LIT, it is recommended that you rename it in order to avoid having it be overwritten by a subsequent A-Shell update.


DING

DING <number-of-times>

DING rings the bell. This sophisticated technique is mainly used within CMD and DO files to get the operator’s attention, perhaps because input is required or an error has occurred.

Under Windows, and most terminal emulators (such as ZTERM), this will play the "System Default" sound. (You can change the WAV file associated with that sound from the Sound applet of your Control Panel, no doubt amazing and delighting your colleagues by setting it to a shrieking woman, theme from Thus Spake Zarathustra, or a gastronomic by-function.)

If you do not have a sound card, or are using a dumb terminal, you will be at the mercy of the default hardware bell sound (and loudness, or lack thereof).


DIR

Updated January 2016; see History

DIR {listspec=} {fspec1{,...fspecN}} {switches}

The DIR command implements most of the switches available under AMOS, plus some additional switches that are unique to A-Shell. See the following topic DIR Switches.

Aside from the slightly different set of switches between AMOS and A-Shell, note the following differences in behavior:

· Keep in mind that files will only be listed if you have file read permission for them. In the case of UNIX, it is also required that the directory, and all directories above it, have the execute bit set. (The execute privilege on a directory controls whether the directory can be traversed.) This applies equally to all wildcard commands, such as COPY and ERASE, which will effectively not see files for which you have no read permission.

· Unlike under AMOS, where you could use DIRSEQ to sort the files in a directory, it is rather non-standard to sort an actual directory under Windows and UNIX. Instead, the DIR program itself is usually relied on to sort the display rather than sorting the directory itself. Consequently a set of sorting options has been added to the A-Shell version of DIR; see switches beginning with "S" in table of DIR switches.

· Since DIR works by actually scanning the directory structures, it will find files that do not fit the AMOS "six dot three" format, or even A-Shell's extended "ten dot three" format, and thus cannot be located by non-wildcard commands or by BASIC file open statements. DIR will truncate files with names longer than "six dot three" but will use some kind of flag character, such as ">" to give you a clue that there may be more there than meets the eye.

One particularly nasty problem of this type occurs only under UNIX, which has case-sensitive filenames. Since normal files are by convention named in lower case, A-Shell translates AMOS filespecs (which are not case sensitive) to lower case. But some file transfer programs may produce upper case filenames when transferring files from AMOS to UNIX. Such files will appear in a DIR listing (which folds the displayed filenames to upper case to match the way AMOS DIR listings appear). But they will appear to be invisible to non-wildcard commands and BASIC file option operations. To avoid this problem, make sure your file transfer program has an option to force lower case and that the option is activated. To fix the problem, see the trlcs utility which is shipped with A-Shell in the bin directory.

· Blocks sizes for sequential files will differ between AMOS and A-Shell, due to differences in underlying block formats. AMOS uses 512 byte blocks with 2 or 4 byte links to connect the blocks in a sequential file, depending on the device format, and thus each full block contains 508 or 510 bytes of data. None of the other OS platforms that A-Shell runs on requires such links (they are implemented in the directory rather than in the disk blocks), so A-Shell treats each "block" as capable of holding up to 512 bytes of data. (Physical blocks are likely to be much larger these days, and in fact, the very idea of a "block" may be questionable - most platforms use a stream-of-bytes model instead - but 512 byte logical chunks are still widely recognized as a kind of traditional unit of size.) To compare files between AMOS and A-Shell, it is best to use SIZE.LIT to get the logical size, and/or DIR/H to check for an exact data match.

See Also

• PAGE as an alternative to Ctrl+S and Ctrl+Q for limiting the scrolling speed of the display.

History

2016 January, A-Shell 6.2.1425: Add switches /MAXSECS and /MINSECS.

2013 June, A-Shell 6.1.1354: Add /1 switch.

2011 June, A-Shell 5.1.1221: Remove the limit on the number of PPNs allowed per device.

Subtopics

DIR Switches


DIR Switches

Updated November 2016; see History

In the list of switches below, note that like the AMOS version, you can abbreviate any switch to the minimum number of unique characters (e.g. /C for /CONTIGUOUS, etc.).

Switch | Function
/1 | Eliminates the directory and size information from the output. When combined with the /NATIVE switch, it produces just a list of filenames (file.ext), similar to the UNIX ls -1 command. Added in 6.1.1354.
/A | Adate: displays last access date.
/AT | Atime: displays last access time.
/CDATE | Displays file "c date."
/CON | Displays a "C" to identify "contiguous" files. (Note that under A-Shell, this really just means the file is a multiple of 512 bytes.)
/CTIME | Displays file "c time". Usually used with /CDATE. See notes under CDATE for differences between the "c date" under AMOS/Windows and UNIX.
/D | Data: displays complete filespecs. (See VERIFY for notes on a use for this switch.)
/F | Full: same as /H/CON/V
/H | Display hash code
/K | Kill: delete and replace listfile
/LONG | Changes the default display layout to 10.3 format instead of 6.3 format.
/MAX:n | Display only files with n or fewer blocks
/MIN:n | Display only files with n or more blocks
/MAXDAYS:# | Omits from the display any files that have been modified more than # days ago.
/MAXSECS:# | Omits from the display any files that have been modified more than # seconds ago.
/MINDAYS:# | Omits from the display any files that have been modified less than # days ago.
/MINSECS:# | Omits from the display any files that have been modified less than # seconds ago.
/NA {:len} | NATIVE: displays files in the native format
/NOFILES | Omit filenames; just output totals
/Q | Query: prompt for confirmation on each input file. (Standard switch)
/SEXT | Sort by ascending extensions
/SNAME | Sort by ascending filenames
/SNODEV | Removes primary sort on DEVICE; see SNOxxx.
/SNOPPN | Removes primary sort on DEVICE; see SNOxxx.
/SSIZE | Sort by ascending file sizes
/SUDATE | Sort by ascending update dates
/UDATE | Display file update (last modified) dates
/UTIME | Display file update (last modified) times
/V | Display file version if available. Also see VERSYS.
/WARN | Forces DIR to display the message "Warning: skipping incompatible filespec" when applicable. This message was displayed by default (i.e., without the /WARN switch) in versions of DIR before 3.0(140).
/W:n | Wide: display in n columns (default n=4)
/? | Writes switch listing and usage info to the screen.

History

2016 November, A-Shell 6.3.1534, DIR.LIT 3.3(160): Added MEMREQ switch


CDATE

Displays file "c date." The "c date" under AMOS and Windows is the creation date, but under UNIX is the date that the file’s directory entry was last changed. This occurs whenever the file ownership or privileges are changed, or when a symbolic link is created, or when the file is moved, renamed, or copied. Because of this, the "c date" can easily be more recent than the update date.


LONG

Changes the default display layout to accommodate 10.3 format instead of 6.3 format. It also changes the default /W value from four columns to three. Filenames exceeding the maximum display length will show a ">" character following the filename. Note that the SET command LONGDIR can be used to force the 10.3 format.


MEMREQ

Added November 2016

The /MEMREQ switch displays the memory required for static variable storage for programs such as LIT, RUN and SBX files in place of the file size. When both /SSIZE (sort on file size) and /MEMREQ are specified, it also sorts based on the memory requirement.

Note that the value displayed by /MEMREQ is only a total for the combined sizes of the fixed variables in the program. While this is far short of the total operating system memory used by the program, which includes dynamic variable, stack and other auxiliary memory allocations, it is a good measure of how large your job memory partition needs to be. This is particularly true since 6.3.1518 when the string stack was moved to dynamic memory. A reasonable rule of thumb would be to set your partition size to 300-500K larger than the largest /MEMREQ value for your application. Use DIR /MEMREQ/SSIZE to find the largest values; don't forget to also check the LIT files in SYS: since some of them may have large requirements.

History

2016 November, A-Shell 6.3.1534, DIR.LIT 3.3(160): Switch added to DIR


NATIVE

This switch, /NA{TIVE}{:len}, displays files in the native format of the host operating system. The len sub-parameter (default 24) determines the maximum display width for the filespecs. If the filename exceeds that, it is terminated with ">" just as when /NATIVE is not used. This switch was added in DIR.LIT 3.0(140), A-Shell build 990 of 10 June 2007.

/NA{TIVE} causes the following other effects:

· "Incompatible files" are treated like any other files (i.e. displayed instead of skipped).

· File sizes are shown in bytes instead of blocks

· File names are shown in upper and lower case as they really are.

· When combined with /D, displays entire path for each file. Otherwise, displays just the filename + extension(s) (but for each new directory, displays the directory in native format instead of the DEV:[p,pn] format.)

· /W will default to /W:2


SNOxxx

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.


DO

DO <fspec> <argument list>

where <argument list> is a list of zero or more space-delimited textual tokens which are bound to the formal Arguments $0 through $9 referenced within the file identified by <fspec>.

The DO command forces fspec to be treated as a DO file (rather than a LIT or CMD file). This is useful in situations where the fspec in question exists in CMD and/or LIT variations as well as DO, since otherwise, the command search path would cause the CMD or LIT to be found first. It is also needed to force a file with an extension other than DO to be interpreted as a DO file (although it is not clear why you want to do that).

DO supports the command line argument ++fspec; for details see Arguments $0 through $9.

DO.LIT is invoked automatically by the command line processor if it determines that the specified file is a DO file, so it is not necessary to explicitly use "DO" except in the situations described above. DO.LIT is responsible for preprocessing the DO file to perform argument and macro substitutions.

MDO.LIT is identical to DO.LIT, but is referenced internally under different circumstances.

Comments

The maximum DO file size is approximately 122K. This is about the maximum size for a 430K partition, which is about the minimum partition needed for some other large LIT commands, such as SUBMIT. A-Shell will explicitly complain if the partition size is not sufficient.

When DO is used within a DO file to reference another DO file, the command line may contain references variables input during execution of the current DO file, $KBD0 thru $KBD9 (see K0 - K9 Commands), may contain upper and lower case functions (see Input Case), and may use the concentration operator $+ (see Concatenate Parameters).

History

2011 August, A-Shell 5.1.1227: DO.LIT / MDO.LIT 2.1(124) and SUBMIT.LIT 3.1(150) now support file-based variable command line arguments using the ++fspec syntax.


DUMP

DUMP <filespec> {,starting-block}

The DUMP command is an implementation of the AMOS command of the same name, for displaying the contents of files only; direct disk block dumps, UFD dumps, and MFD dumps are not supported. The format of the data dump is identical to that produced by AMOS, formatted in either octal or hexadecimal depending on the current job settings (see SET). The current block number displayed under A-Shell is a sequential count of 512 byte blocks starting at one (or the specified block number).

Since there is no difference between random and sequential files under operating systems other than AMOS, and the block linking mechanism is separated from the data itself, all 512 displayed bytes contain actual data; the first two or four will not contain link information as they do for sequential files under AMOS. This may mean that dumping a sequential file under AMOS and A-Shell (which have the same hash-total) will produce differing outputs, being shifted by two or four bytes each block.

Also see the notes on PAGE for how to keep the display from scrolling too fast.

Note that 512 byte "blocks" do not necessarily have any physical significance outside of AMOS. Under A-Shell we simply use it as a convenient logical unit.


ECHO

Added May 2011

ECHO functions similarly to the UNIX and Windows command of the same name. It offers similar functionality to the CMD/DO file ":< ... >" mechanism, but is more flexible and powerful, supporting the full range of special $ variables (which otherwise only work within DO files) and environment variables (e.g. %MIAME%).

Examples

ECHO Your job name is $NJ

ECHO The MIAME directory is %MIAME%

AGCMD/K0/S BROWSEFOLDER

ECHO You selected folder $KBD0

History

2011 May, A-Shell 5.1.1215: Added to A-Shell


EL, EP

EL <compil switches> <wildspec> {,wildlist}

EL and EP launch the A-Shell Editor from within A-Shell; EL the Lite version, EP the Pro version. When executed, EL/EP looks for the initialization file EDITOR.INI in [7,0]; if not found, an option to build one will be offered.

Parameters

compil switches

should be space delimited and preceded by '-' (a hyphen). The default switches are defined in EDITOR.INI.

wildspec

is a standard AMOS wildcard spec

wildlist

is an optional list of zero or more file.ext specifications, which may contain wildcards but no device or ppn

Examples

.el -x:2 -m prog.bas

.el *.bas

.el mysrc:myfile.bas,*.b?i,*.map

.el -cfg ; (displays/edits EDITOR.INI)

.el -help ; (displays help)

.el ; (launches Editor with no files)

Comments

EL/EP will look for additional options in:

EDITOR.INI

EDITOR.INI[p,0]

LIB:EDITOR.INI

If the "Save View State" button was pressed before ending the previous session of the Editor, then the current session will start with the files previously opened, plus any files mentioned on the command line.

Note that EL.LIT and EP.LIT are copies of the same program; at runtime, the program looks at its own name to determine which version of the Editor to launch.


ELSE

IF <expr>

<statements to execute if true>

ELSE

<statements to execute if false>

ENDIF

ELSE allows for the flow of control within a CMD or DO file based on various conditions that can be tested. It takes no arguments, and its usage should be clear from the example above. See CMD and DO Files for more information.


ENDIF

ENDIF is needed to terminate a conditional group of a CMD/DO statements which was started with an IF or ELSE statement. See the description on ELSE for an example, and refer to the notes on CMD and DO Files for more information. Also see the discussion of MOVE for an example of ENDIF usage.


ERASE

Updated January 2016; see History

ERASE fspec {switches}

ERASE not surprisingly erases files.

Parameters

fspec

specifies an input file, using either AMOS-style or native operating system syntax. AMOS-style filespecs may include the * and ? and [] wildcards (e.g. DSK?:[]*.TMP). Native operating system filespecs must be individually quoted, must include at least one slash, and must not contain wildcards (e.g. "./this native file.lst","/tmp/somefile.tmp"). More than one inspec may be specified, in which case they must be separated by commas.

switches

Switch | Function
/Q | Query: prompts for a confirmation before erasing each file matching the wildcard specification.
mindays:# | Erase only those files that have not been modified in at least the last ### days.
mindsecs:# | Erase only those files that have not been modified in at least the last ### seconds.
/? | Writes switch listing and usage info to the screen.
/F | forces an affirmative response to the confirmation prompt that otherwise appears automatically when interactively attempting to erase multiple files via a wildcard. Note that the switch is redundant but harmless in non-interactive situations, except in the case where the ERASE command is at the very end of a CMD file, where the mode transitions back to interactive before the command executes.

Confirmations

In response to developer requests, ERASE has been modified (see History) so as to minimize the chances of unintentional file deletes, which can easily occur when using wildcards. ERASE.LIT 3.4(124) and later will ask for confirmation when ALL of the following four conditions are met:

• It is not running from within a CMD or DO file, which is determined by whether there are any characters in the CMD/DO file left to process. To make sure they ARE more characters to process in your CMD/DO file, it would be wise to add a blank line after a final ERASE command.

• It is not executed with the /Q switch

• The command will result in more than one file being deleted.

• A-Shell was not launched with the -e switch.

For example:

.erase *.bak[]

ASTAT.BAK

ATECFG.BAK

ATECTL.BAK

ATEUPDATE.BAK

ATSYNC.BAK

SBXINP.BAK[7,6]

Total of 6 files, 149 disk blocks will be deleted

Proceed with actual file deletion ? N

%No files deleted

.

.

.erase *.bak[]

ASTAT.BAK

ATECFG.BAK

ATECTL.BAK

ATEUPDATE.BAK

ATSYNC.BAK

SBXINP.BAK[7,6]

Total of 6 files, 149 disk blocks will be deleted

Proceed with actual file deletion ? Y

Total of 6 files deleted, 149 disk blocks freed

Note that the confirmation character is based on the current language, as is the case with the /Q confirmation; in fact, they use the same routine. The messages are all from the LITMSG.xxx file too, and will default to English if not specified in the message file.

History

2016 January, A-Shell 6.2.1422: ERASE.LIT 3.4(129) now detects when running under control of PAGE so as to not disable the warning/confirmation request when deleting multiple files by wildcard. Previously a command line like PAGE ERASE *.BAK was not stopping to confirm that you really want to erase all those files, because it appeared to ERASE that it was running from the command file created in memory by PAGE.

2016 January, A-Shell 6.2.1422: When listing the files to be erased, ERASE now displays the file size in blocks next to each name.

2015 May, A-Shell 6.1.1411: Add /F switch.

2013 November, A-Shell 6.1.1365: Add confirmations.

2011 June, A-Shell 5.1.1221: Remove the limit on the number of PPNs allowed per device.


ERSATZ

ERSATZ displays the list of current ersatz device definitions. These definitions are maintained within one or more text files, each of which is referenced via an ERSATZ= statement in the miame.ini file. The ersatz devices may be used syntactically just like real device names.

Additions to the LAST specified ersatz definition file (i.e. the last ERSATZ= statement in the miame.ini) will be recognized within several seconds. Additions to any other ersatz definition file will not be recognized until you re-launch your A-Shell session.

Refer to the system parameter ERSATZ for more information on ersatz devices and usage.


EXIT

EXIT terminates a CMD or DO file, and is only needed when you would like to terminate it somewhere other than the physical end of the file (usually in conjunction with the a conditional statement involving IF). See the notes on MOVE for an example of EXIT usage.


EXPLORE

Added February 2015

.EXPLORE {<directory>}

The EXPLORE command launches the Windows explorer for a specified directory location.

If no arguments are specified, it explores the current directory. Directory format may be native Windows (relative or absolute), or AMOS-style. Examples:

.EXPLORE %MIAME%

.EXPLORE SYS:

.EXPLORE DSK0:[7,6]

.EXPLORE DSK0:2,2

.EXPLORE \\SERVER\PATH

.EXPLORE ..\..\BIN

.EXPLORE

In the UNIX/ATE environment, the directory must be PC native spec and any environment variables are evaluated relative to the ATE client.

History

2015 February, A-Shell 6.1.1401: Command added to A-Shell.


EZTYP

EZTYP <filename>

EZTYP displays the specified file, using the EZ-SPOOL file viewer. Although this command was officially renamed to "EZVUE" quite some time ago, the original command name of EZTYP has been retained in the interests of backwards compatibility and ontological confusion. Refer to EZSPL configuration, and note that the colors may be affected by settings in the INI.CLR file.

The operation of EZVUE/EZTYP is reasonably self-explanatory, particularly after a glance at the help screen, which is accessed via the ? key. However, the following topics may help fill in some of the gaps.

EZVUE can also be accessed via EZTYP.SBR, or simply by including the TYPE=ON parameter setting within the applicable EZ-SPOOL configuration file. This latter method will result in an option to preview the file being given every time your application calls SPOOL.SBR.

The name EZVUE is essentially an alias to EZTYP and came into being to highlight the VUE-like features added to the A-Shell version of EZTYP (command mode, search capability, paging, etc.).

LOOK is the name of a file viewer included with SuperVue and popular under AMOS, and that EZTYP is generally speaking a very suitable (and more capable) replacement for it. Applications which contain hard-coded references to LOOK might want to just create a LOOK.DO file that contains:

;LOOK.DO -

$R

EZTYP $0

Subtopics

Status Line Information

Printing

Wide reports

Variable rows


Status Line Information

The status line displays the current line, total number of lines, current page, total number of pages, and a percentage indicating how far the current page is from the start of the file to the end. This would all be very straightforward, except for some performance considerations which complicate the issue. But first, what is meant by the current line? Since EZVUE was designed to work with extremely large files, it does not store the file in memory. And since it does not allow changes to the file, there is no cursor. So there really is no particular current line. However, for the purposes of the status line information, the current position is taken to be the end of the last line visible on the screen.

Next, what is a page? If the file has hard page breaks, then an EZVUE page is equal to a printed page. These page breaks will display as an entire line of ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ characters on the screen. If the file does not have hard page breaks, then an EZVUE page is simply a screen-full (typically 21 lines, since three lines are used up by the command and status prompts).

Even after defining what a line and a page are, we still have the problem of determining just where we are in the file. This may seem strange, since EZVUE looks like an editor, and an editor obviously has to know exactly where you are in the file or you would not be able to edit it with the desired results. The problem, as mentioned above, is that since EZVUE was designed to view large report files with the maximum performance and minimum memory overhead (rather than be an editor), it does not load the file into memory. Instead, it uses the operating system’s seek facility, which is byte oriented, rather than page or line oriented, to move about the file. For this reason, it is not able (at least initially) to report the exact number of lines and pages in the file. Instead, it makes an estimate, using the average line size for the part of the file that it has had to scan in order to display it. To avoid giving a false impression of precision, it displays a question mark next to those line and page numbers which are only estimates.

Any example may make this clear. At the start, it only reads enough lines to display one screen full. At that point, it knows exactly which line it is on, but it can only estimate the number of lines and pages in the file, so those figures will have question marks next to them. If you then use the E command to go directly to the end of the file, it does a direct seek to the end of the file, then backtracks just enough so that it can display the last lines of the file. At that point, it does not even know which line number or page number it is currently on, since it got to the end of the file without reading it sequentially from the beginning. However, if you request to seek directly to page 50, then it will be forced to scan from the beginning of the file, line by line, until it gets to page 50. At that point, it still does not know the total number of lines or pages, but it does know the current line number and page number, and more importantly, it now knows the position of all of the pages 1-50. Thus, if you then ask to go backward four pages, it can go more or less directly to that position without having to start over again from the beginning. If you want to compute the precise number of lines and pages in the file, you can do this by requesting to go directly to a page number which is greater than the number of pages in the file (e.g. =9999). After executing that command, it will have been forced to scan the entire file, so from that point forward, it will be able to report the precise number of lines and pages in the file, and be able to go (more or less) directly to any position.


Printing

The print command (P) allows you to print an excerpt (from-to page) of the file. This much is obvious. What may not be obvious is where it gets the list of printers that you are allowed to select from. Since this was originally developed as part of EZ-SPOOL, it uses the EZ-SPOOL configuration file system for determining the names of the available printers. This system allows different sets of printers and other options to be associated with various situations, such as job name, program, account, etc.

One potential problem with printing excerpts from a file is that the file may have contained special printer control codes (typically at the start of the file) which are lost when only an excerpt of the file is printed. There is no simple and universal solution to this problem, and you will have to use a workaround approach appropriate to your situation. For example, once you realize that the file is 132 columns wide, you can select a printer whose default configuration is set for 132 column printing. (Refer to Printer Configuration for information on how you can create a logical printer that automatically starts in a particular configuration.) If your application handles printer control codes via the PREFIX and SUFFIX options in the Printer INI, rather than by embedding them in the file itself, this problem will be minimized. (All you need is enough sense to select the appropriate printer to handle the excerpt.) If you are using a terminal emulator such as ZTERM which offers a choice of printer font sizes for "local" printing, that may be another solution. (In that case, make sure to add a "Local" printer option which uses the "AUXLOC:" pseudo printer device, which in turn will route the printout back to your terminal or emulator for local printing.)

As of A-Shell version 4.7(808), another possibility for dealing with the printing difficulty just described is to use the SBR=EZPRTX parameter in the miame.ini. In this case, whenever you print from within EZVUE, it will call the subroutine EZPRTX.SBX, passing it the desired page range parameters, and let it handle the print operation. The source to a generic EZPRTX.SBX is included in the release in DSK0:[7,376], with the idea that application developers can customize it to provide more sophisticated handling of partial file print requests. (For example, you can add code to deal with the printer feature codes, printer selection, etc.)


Wide reports

EZVUE will automatically switch into 132 column mode if a cursory examination of the first several lines of the file indicates the presence of lines longer than 80 columns (unless AUTOWIDTH=OFF in the EZ-SPOOL configuration file). You can also switch between 80/132 columns with the left and right arrow keys. But if 132 columns is not enough, you can continue to hit RightArrow to shift the entire display window over, several columns at a time. Hitting the LeftArrow will reverse this process, finally returning you to 80 column mode when you hit the left margin.


Variable rows

If your terminal supports this capability, Shift+UpArrow and Shift+DownArrow (or just T for Tall/Toggle) will toggle you between the normal 24-row display and a 42-row display. On a modern high-resolution display, viewing a large file at 42 x 132 is quite reasonable and much more efficient than at 24 x 80.


FIXTRN

FIXTRN {ifx | vux | <name.pfk>} {switches}

The FIXTRN command performs the functions of the AMOS FIXTRN and SET PFK commands, allowing you to create and edit both types of function key translation tables.

Switch | Function
/D | Puts FIXTRN into decimal mode, facilitating the entry and display of binary translations.
/? | Writes switch listing and usage info to the screen.

The "traditional" types of function key translation table (such as those used by VUE and INFLD) have names that match the terminal driver, with the extension indicating the application. Thus AM62A.IFX would by the translation table for AM62A drivers when running INFLD. PCTDV.VUX would be for PCTDV terminal drivers when running VUE. These files are compatible between AMOS and A-Shell. The main difference is that under A-Shell, they are always loaded automatically from the LIB: account on disk, whereas under AMOS, you may need to load them explicitly into system or user memory. To create or edit a function key translation table for VUE or INFLD, use FIXTRN followed by "IFX" for the INFLD translation table or "VUX" for the VUE translation table, e.g.:

.FIXTRN IFX

Editing function key translation file: LIB:PCTDV.IFX

It will automatically invoke the file for the current terminal driver (PCTDV in the example above) and automatically reference the LIB: directory.

To create or edit a PFK-style function key table (one that can be used in any application and which can be manually loaded and deleted from user memory to override any other translations), specify a filename with a .PFK extension, e.g.:

.FIXTRN PILAR.PFK

Editing function key translation file: PILAR.PFK

In this case, it will not put the file in the LIB: directory, since PFK files must be loaded manually, and thus can exist anywhere.

The procedure for editing either type of file is the same (since internally, they are the same format). You start by specifying a special key to be used as the delimiter. Pick one that is not needed in any of your translations, perhaps \. For example:

Enter special delimiter key (cannot be used in a translation):\

Hit a function key (or special delimiter to exit): [181]

Current Translation: HELLO^M

Update? [y/N] Y

Enter new translation: LOG GL:^MRUN GLMENU^M

In the above example, we hit the F1 key. The program then echoes the numeric value returned by the terminal driver for that key ([181]) and displays the current translation string, if there is one. In the above example, the previous translation was "HELLO" followed by the Enter key (Ctrl+M). It then gives you the option of updating the translation. In the above example, we changed the translation to LOG GL: < Enter > followed by RUN GLMENU < Enter >. It then loops back to ask for a new key. When you are done examining or defining translations, hit the delimiter key one more time, which will cause it to save the file in the current directory:

Hit a function key (or special delimiter to exit):

Outputting updated PILAR.PFK...

537 bytes output.

To use the translations, use LOAD to load the file into memory:

.LOAD PILAR.PFK

Having done this, you can now hit the F1 key and it will act as if you typed the two commands LOG GL: and RUN GLMENU.

You can use the MAP command to check if there is a PFK file currently loaded, and DEL to remove it from memory:

.MAP

Loaded private function key table: PILAR.PFK

Free 694863

.DEL PILAR.PFK

PILAR.PFK deleted from memory

IFX and VUX modules reset

For more information on function keys and translation tables, see Function Key Translations.


FORCE

Update May 2015; see History

FORCE <jobname> <text>

FORCE allows you to force keystrokes into another job’s input stream. <text> is any string of characters. To force control characters, precede them with ^. For example:

FORCE TSKAAA RUN PROG^M

In the UNIX environment, FORCE uses the SIGUSR1 signal, which can only be delivered between processes belonging to the same effective user or if the sender is the superuser. Refer to File Ownership and Privileges for further details on dealing with the UNIX privilege issues. In the Windows environment, FORCE uses the IJC (Inter Job Communication) system, which has no privilege issues, but is subject to being turned off by the IJCFREQ command in the miame.ini. Note that the ^M refered to above is composed with the literal characters ^ and M.

FORCE.LIT supports the AMOS-style multi-line syntax:, i.e.

.FORCE TSKAAB

LOG BAS:

RUN MYPROG

15

~

TIME

The above would force TSKAAB to execute "LOG BAS:", then "RUN MYPROG", then "15", and finally a blank line (Tilde by itself is treated as a blank line.) The blank line terminates the force operation. (The TIME command would then be executed back in the current job.)

Note that under A-Shell/Windows, the response time for receiving forced commands may be several seconds. To avoid overrunning the target job, the sender will be forced to wait for each command to be acknowledged by the receiver.

It also supports forcing commands to yourself. This is useful for forcing input to a program that does not normally accept input from a command file. It is usually used with the $NJ system variable in DO files to specify the current jobname, e.g.:

;MYPROG.DO

:R

LOG BAS:

FORCE $NJ

RUN MYPROG

15

~

TIME

Note that the TIME command here will execute before the forced commands, since CMD and DO input is processed first, then typeahead. Also note that there isn't much point in this exercise unless MYPROG (in this case) doesn't accept command file input. Otherwise we could just omit the FORCE command and MYPROG would run the same from the DO file as it would with the forced input.

A-Shell still supports the non-AMOS standard single-line FORCE, in which the command is passed on the command line, e.g.:

.FORCE TSKAAB LOG SYS:^M

Note that in this mode, you have to explicitly add a ^M to the end of the line to force a carriage return.

Finally, note that the LITMSG.xxx message files have been updated for some new messages in FORCE.

History

2015 May, A-Shell 6.1.1408: Updated routine to recognize and preserve a new unique identifer field in the JOBTBL. The new version is backward compatible with earlier versions of A-Shell and has a "B" in the version number to help easily identify it.


HEAD

HEAD {outfile=}<wildspec> {switches}

The HEAD command is similar to the eponymous UNIX command and is used to display or copy to another file the first N lines of a specified file (or wildcard list of files).

Switches

Switch | Function
/D | Delete: required when an output file is specified that already exists.
/L:### | Lines: specifies the number of lines to copy or display. Default is 20.
/Q | Query: prompts for confirmation on each file.
/? | Writes switch listing and usage info to the screen.

Examples

This example displays the first twenty lines of the specified file (more or less equivalent to using PAGE TYPE <file> to display one screen-full and then aborting.

.HEAD SYS:ERRMSG.USA

This next example is similar, except it uses quotes to refer to a native host operating system file specification (note that they are case sensitive under UNIX) and also uses the /L:5 switch to limit the display to the first five lines:

.head "/vm/miame/miame.ini" /L:5

This next example creates a file called VERDIR.TXT, which consists of the first line of each BASIC source file in the current project. Assuming you adopted a standard of putting something meaningful and consistent on the first line of each source file, this could be a very useful way to compare two sets of source files (i.e. use the command below on each set of files, then sort the resulting header files and compare them using SRCCOM).

.head verdir.txt=*.bas[,*]/l:1/d

See the notes on TAIL for the same idea only counting from the end of the file.


HOST

Updated November 2016; see History

HOST {{switches} cmd {modifier}}

The HOST command is a special A-Shell command program. It exits the A-Shell command shell and returns to either the host operating system command level or host batch or shell-script file which was used to invoke A-Shell.

Switches

Switch | Function
/S | Display exit status of command.
/O | Captures the stdout of the command and displays it from within A-Shell. Maximum size of the output text is 256K; if exceeded, a warning message will be displayed at the end of the output.
/? | Writes switch listing and usage info to the screen.

The optional modifiers are same as can be used with HOSTEX.SBR.

Comments

If an AMOS command sequence is piped into A-Shell (that is if the standard input file has been redirected), for example with the following UNIX command:

$ echo "time" | ashell

then the command sequence will be executed automatically, and once the end of the standard input file is reached, control will return automatically to the host command level. In this case, at no point does A-Shell produce a command prompt, though it is possible to use the HOST command from within a .CMD or .DO file to terminate the execution of the command sequence prematurely.

The HOST command may also be used to perform a host machine function from within A-Shell without exiting, by specifying the command as a parameter. For example:

.host vi $0

may be used within a .DO file on a UNIX machine to invoke the UNIX editor vi. (You will then understand why A-Shell contains an implementation of VUE...)

TRACKER (which controls the screen output within A-Shell) is not able to monitor any output that occurs outside of A-Shell and thus it is a good idea to resynchronize the display after using a HOST command (by clearing the screen, for example).

Yet another use for the HOST command is to execute a host operating system function and redirect the output to a file, which is available for access from within A-Shell. For example, the following commands will create a detailed process status list in the file ps.lst, which is then displayed using the A-Shell EZTYP.LIT utility. This technique avoids the terminal handling problems (alluded to above) which are otherwise bothersome when trying to shell out to host operating system functions which do not know anything about the A-Shell display environment.

.host ps –ef > ps.lst

.eztyp ps.lst

Notes

• When HOST is used in ATE, the keyboard is reset to normal.

• To resolve potential confusion between switches (which start with slashes) and UNIX commands (which may also contain slashes), HOST treats anything which does not match one of the defined switches is as a cmd. But to be more explicit, you may enclose the cmd parameter in quotes. For example:

.HOST /s "/s/abcd"

The first /s will be treated as a switch, whereas the entire "/s/abcd" would be treated as a cmd.

History

2016 November, A-Shell 6.3.1534, HOST.LIT 2.0(106): reduces minimum partition memory requirement from about 265K to 3K and increases the maximum output capture buffer size (when using /O) from 256K to 512K. Note that the total memory requirement when using /O has actually increased rather than decreased, but it is only required when using /O and in that case it is dynamically allocated outside the memory partition.

2011 August, A-Shell 5.1.1227, HOST.LIT 2.0(105): expands the maximum size of the buffer available to capture the output of the command from 64K to 256K and now appends a truncation warning message to it if the buffer fills up.

2011 August, A-Shell 5.1.1227, HOST.LIT 2.0(104): is now smarter about sorting out possible confusion between switches and UNIX filespecs, both of which can contain slashes. This allows unquoted commands, such as:

HOST /s/abcd

to continue to be treated as filespecs, as they were before the switches /S and /O were added in 2.0(103).

Note that the preferred way to prevent UNIX filespecs or commands from being confused with switches is to enclose them in quotes. For example:

HOST /s "/s/abcd"

In the above command line, the /s following HOST will be treated as a switch, while the "/s/abcd" will be treated as a command to execute.

2011 July, A-Shell 5.1.1222, HOST.LIT 2.0(103): now supports a help display and two new options. Prior to this change, HOST was used without switches.

2007 April, A-Shell 4.9.986, HOST.LIT 2.0(102): supports the ability to plug in your own exit subroutine to be called when A-Shell exits via the HOST.LIT command. HOST.LIT now looks for OPR:HOST.SBX, and if it is found, it loads it and calls it before exiting. (Since the OPR: account is not in the normal SBX search path, this feature should not conflict with any existing HOST.SBX routines that may exist.) If the OPR:HOST.SBX is not found, HOST just exits in the normal way.


IF

IF <expr>

<statements to execute if true>

ELSE

<statements to execute if false>

ENDIF

IF allows for the flow of control within a CMD or DO file based on various conditions that can be tested. Refer to CMD and DO Files for more information.

Example

Here is a simple example of a DO file that takes a filename argument. If the file (with a BAS extension) does not exist, it is created by making a copy of a file called APPLIB:STDHDR.TXT. Then, in either case, the file is VUE’d.

IF LOOKUP("$0.BAS") = 0

COPY $0.BAS=APPLIB:STDHDR.TXT

ENDIF

VUE $0.BAS


IMGDSX

IMGDSX imgspec {switches}

or

IMGDSX @albumspec {/switches}

This command provides simple but flexible standalone image display capabilities, either for single images or for albums (lists) of images.

Parameters

imgspec

The filespec of the image to display. File extension of the image file must match its type and be one of the types supported by AUI_IMAGE (JPG, BMP, PCX, TIF). Remember to quote the imgspec if it is a native filespec not compatible with the AMOS 10.3 format.

@albumspec

The filespec of a text file containing a list of images to display. The format of the list is:

;(blank lines and those starting with a semicolon are ignored)

imgspec {,title}

imgspec {,title}

etc.

switches

Switch | Function
/1 | Force previous instance of IMGDSX to close before the new one appears. This applies only when launching a new session to execute IMGDSX, or launching it via ATE.
/A:hhh | Send a WM_SETFOCUS to window hhh when image has been displayed. Useful for putting focus back on the window that launched IMGDSX. See MX_FINDWINDOW for info on determining your window handle.
/B:bmsg | Set bottom status message (else bottom status line is removed from window)
/D:secs | Auto-advance delay when displaying an album. Default is five seconds. Note: use a high number (max 65535) to effectively stop the auto-advance.
/E | Close instance when Escape hit or X clicked.
/M:msg {,scale,attr,font} | Message to display in window just below image (for albums, will be overridden by image title in the album file). Attribute values are the same as those used by AUI_CONTROL .
/P | (Albums only) Append "(n of m)" page count info to /M title
/S | Stretch image to fit window
/T:title | Set title bar (else image spec is display on window title bar)
/W:l,t,r,b | Left, top, right, bottom window coordinates in units ranging from zero for the top or left edge to 10000 for the right or bottom edge. Else Window size remains as is.
/? | Writes switch listing and usage info to the screen.


ISMBLD

Updated May 2015; see History

ISMBLD fspec {/switches}

ISMBLD performs fundamental file building operations for ISAM 1.x files—i.e., creating a new file, adding an index, loading data.

Parameters

fspec

is the name of file to create or process. You may specify a directory, but do not specify the file extension. The operation works on both the data (IDA) and index (IDX) files, so specifying an extension will just confuse matters. If the file does not exist, a new IDX and, if necessary, a new IDA will be created based on the ensuing prompts for file configuration details. Otherwise it will prompt for an existing IDA file to which a new IDX can be added.

For an in-depth discussion on how to use the ISMBLD switches to maximize performance, see ISAM Performance.

switches

Switch | Function
/A | Auto-Configure Index.
/B:#### | Index block size. Allowable values are 512, 1024, 2048, 4096, 8192, 16384; the default value is 512. See Note.
/D | Change data device of existing file.
/F | "Fast" load. Aassumes no duplicate keys; aborts if any are present.
/L:# | Index level. Allowable values are 3 to 9, the default is 3. See Note.
/MI | Memory map index during load operation, causing possibly faster runs.
/MR | Memory map only the root of the index during load. This reduces the amount of memory required.
/N | Use non-exclusive mode.
/V | Verbose mode. Displays progress information (percentage complete) during the build and load, and the elapsed time for the load, plus messages confirming the /Mx and /F switches during the load.
/? | Writes switch listing and usage info to the screen.

Note: Use of these switches requires A-Shell 1122 or later; see the discussion on ISAM Performance.

See Also

• ISMDMP.LIT, ISMBLD.SBX, ISMROK.SBR.

History

2015 July, A-Shell 6.1.1412: ISMBLD.LIT 2.1(141) fixes a discrepancy between the AMOS and A-Shell behavior of the /D switch, which is used to change the IDA device. Previously, hitting ENTER to the "Enter new device name" prompt was causing an existing explicit device specification to be set to blank, meaning that the IDA is on the same device as the IDX. In contrast, the AMOS version was leaving the existing device specification alone in this case. Instead, you were expected to enter "." to remove an existing device specification. While the A-Shell version was treating "." as an invalid device.

The updated ISMBLD.LIT 2.1(141) now matches the AMOS behavior, although the prompt has been enhanced to clarify the ENTER and "." options.

While on the subject of the ISAM IDA device, please take note to remember why the feature existed in the first place: it was a workaround to the 32MB limitation of the original AMOS disk devices. In the modern world, it makes no sense to split the IDX and IDA across different devices. It is strongly recommended that you keep the IDX and IDA on the same device under A-Shell—i.e. leave the the data file device option blank.

2015 May, A-Shell 6.1.1411: ISMBLD.LIT 2.1(140) no longer stores the data file device in the IDX unless it is specified explicitly on the command line (e.g. ISMBLD DSK2:MYFILE) or to the "Data file device:" prompt. This partially rolls back a change introduced in 2.1(139) which made the data device explicit in all cases.

The explicit data device specification was causing a problem for non-AMOS-conforming devices like ARCH27: or VSK: because of limitations in the historic binary format of the IDX. It was also inviting confusion when an IDX/IDA pair was copied to another location for testing. If the data device specification was not updated using the ISMBLD /D switch, the new IDX would continue to reference the old IDA device, possibly leading to inadvertent updating of the wrong file. Note that:

• ISMDMP displays the data file device (only if it is non-blank).

• ISMDMP <file>/D can be used to change it.

• If using an explicit data file device, make sure it follows the form of three alphabetic characters followed by a number 0-66635, e.g. DSK1: or XYZ999:

2014 January, A-Shell 6.1.1373: ISAM 1.1 refinement: To avoid needlessly complaining about an invalid number of index levels in some IDX files created by ancient (particularly AMOS) versions of ISMBLD, and value < 3 or > 9 is now treated as 3, which was originally the only choice. A warning is logged to the ashlog.log file, along with a recommendation that it be rebuilt, but then it goes on to work as a legacy-format IDX file. Previously, A-Shell complained and returned ERF 35 (smashed index) for any invalid value except 255, which was, until recently, the only legacy/invalid value we had seen in the field. Note that if the file really was corrupt, it will surely generate an ERF 35 in short order anyway, so the only downside to attempting to treat it as a legacy IDX is that you might miss the warning which used to appear on the screen.

2013 April, A-Shell 6.1.1348: ISMBLD.LIT 2.1(134) adds /A switch.

Subtopics

Auto-Configure Index


Auto-Configure Index

Added April 2013

The /A switch auto-configures the IDX. Instead of prompting for the number of extra empty index blocks to allocate, it prompts for the expected total number of records to configure the index for, and then calculates optimum block size and levels. For example:

ISMBLD TEST/A

Key size: 30

Key position: 1

Size of data record: 64

Number of records to allocate: 1000

Auto-configure index for how many (expected) records: 5000000

79 index blocks will be allocated

IDX Configuration: 5 levels, 2048 byte blocks

Projected IDX blocks by level: 1,3,108,3859,138889

Primary Directory?

Data file device:

Load from file:

Note that the prompt for the number of records to allocate only determines the size of the initial empty file, which is not particularly important since the file will auto-expand as records are added. The only advantage of pre-allocating would be the slight possibility of a more efficient arrangement of disk blocks. The prompt for the expected total is actually more important, as it determines the IDX configuration, which will affect the file performance as it gets larger.

Note also that this version of ISMBLD.LIT is backwards compatible to 6.0.

History

2013 April, A-Shell 6.1.1348: /A switch added to A-Shell


ISMDMP

Updated February 2012

ISMDMP fspec {/switches}

ISMDMP displays information about and/or dumps an ISAM index.

Parameters

fspec

the name of the index you wish to display. On execution, you will be offered the following choices for output of the information:

Option | Description
TTY | Output to screen, starting with header
DDT | Output to screen, prompt for options on each block
<filespec> | Dump entire file in index order to the specified disk file

switches

Switch | Description
/D | Display and input block numbers in decimal instead of octal/hex
/V | Verbose mode. Displays additional details, assumes TTY output.
/? | Writes switch listing and usage info to the screen.

The verbose option (/V) scans the IDX file to get actual counts of the index blocks in use by level, instead of just estimating it as in previous versions of ISMDMP. To keep the scan time reasonable and focused on the most important top levels, the scan will terminate when it reaches a level which is known—from scanning the level above it—to contain more than 5000 blocks, or when twenty seconds have elapsed. You can also hit any key to terminate the scan. Regardless of how the scan is terminated, the remaining levels will be estimated, as before. Note that since it is inefficient for the top level to contain more than one or two blocks, use of this feature can help you identify files that would benefit from restructuring, either increasing the index block size or the number of levels.

ISMDMP also indicates if the IDX was built using features that require a certain version of A-Shell, e.g.:

.ISMDMP TEST/V

Size of data record: 16

Size of dir entry: 14

Size of dir block: 1024

Size of key: 10

Type of key: 200 (requires A-Shell 5.1.1122+)

Entries per dir block: 72

Index levels: 4

Count by level: 1,3,198,14223

etc.

See Also

• ISAM Performance.

History

2013 March, A-Shell 1346: Change verbose mode operation from estimating to scanning; ISMDMP.LIT 2.0(140).


ISMUTL

Updated February 2017; see History

ISMUTL <fspec>

ISMUTL allows you to create a new ISAM-A file set or perform various maintenance operations on an existing one. ISAM-A file sets consist of a data file with a DAT extension, and an index file containing from one to sixteen logical indexes with an IDX extension. Since the extensions are fixed, the <fspec> should not include an extension, and typically is just a name (e.g. ISMUTL MYFILE).

If the specified file does not exist, you will be prompted for information needed to create the file, including:

Number of records to allocate:

Size of data record:

Type of key (0=*, 1=integer, 2=concatenated, 3=binary):

Does key allow duplicates?

Is key allowed to change?

Size of key:

Position of key:

Extra index block percentage:

Loading factor:

Data file device:

The questions relating to keys will be repeated up to sixteen times if necessary to define up to sixteen indexes. These prompts are designed to be CMD file compatible with the AMOS version of ISMUTL, so that any command files you have to build ISAM-A files will work under A-Shell as they do under AMOS. However, the interpretation or significance of some of the parameters differs, as described below.

The number of records to allocate is completely ignored under A-Shell, because ISAM-A files under A-Shell are automatically self-expanding. The DAT file always starts at zero bytes, and grows with each record added.

The size of the data record is the same as for AMOS, except that the current maximum record size under A-Shell is 8196 bytes.

The "key allowed to change" option is presented for CMD file compatibility, but under A-Shell, the key can always change. (It is considered the responsibility of the application to determine this.)

The extra index block percentage and loading factor options are meaningless under A-Shell, since the index, like the data file, is self-expanding and self-adjusting. (That is not to say that it cannot benefit from reorganization from time to time, but only due to deletions, not to additions alone.)

The data file device, is also ignored, as there is no conceivable excuse for putting the DAT file on one device and the IDX on another. (This was an option under AMOS where devices were often no more than 32 MB, but in the Windows and UNIX world, this is hardly a consideration.)

When the specified file set already exists, ISMUTL instead displays a menu of maintenance options:

LOAD - load a file

CHANGE - change data device name

ADD2ND - add secondary key directory

DELETE - delete existing secondary key directory

REBUILD- rebuild primary & secondary key indexes

DUMP - dump ISAM file

STAT - display statistical information

ADDIDX - add index block

DESCRP - change key description

EXIT - exit to AMOS

Again, these options are designed to be CMD file compatible with the AMOS version, so that any existing CMD files which execute ISMUTL commands will function the same way under A-Shell.

ISAM-A under A-Shell is implemented via a clone of the Informix C-ISAM access method, which has many advantages over a homegrown implementation, but does suffer from a few small discrepancies with the AMOS implementation. Some of these were mentioned above. Another is that the data file extension is DAT (rather than IDA as for AMOS). This might create a conflict in programs that explicitly looked for that IDA file (although the MAPIDA option in the miame.ini file may handle most of those). There is also a one-block LCK file which is used for locking but which does not exist under AMOS. Another difference is that the actual record size on disk will be one byte larger than specified, due to the addition of a control byte. This, and the fact that the file grows on a record-by-record basis (unlike the AMOS version which is preallocated in blocks) makes even the data files (as well as the IDX files) not binary compatible between AMOS and A-Shell. To move them between platforms, you have to either use ISMUTL to dump on the source platform and then ISMUTL again to reload from the dump file on the target platform, or you can create a program in BASIC which reconstructs the file from the existing IDA or DAT file (directly, albeit with some programming difficulty).

History

2017 February, A-Shell 6.3.1545: ISMUTL.LIT 1.4(141) adds an option, when dumping directly from the DAT file, to dump just the active records (default), or just the deleted records, or all the records. The latter two options might be useful in exotic data recovery or other operations. For example, if you accidentally deleted some records, you could dump just the deleted records and then reload them, effectively un-deleting them. Or if you have a large file containing many deleted records, you could split it into two files—one for the active records and one to archive the deleted records—by dumping the active and deleted records separately and then using them to build two new files from scratch.

2017 February, A-Shell 6.3.1545: ISMUTL.LIT 1.4(140) adds a new feature to allow dumping directly from the DAT file rather than from one of the indices.

2010 August, A-Shell 5.1.1191: ISMUTL.LIT 1.3(134) allows 0 as the record size, needed for "pure" indexes. Previously, such an index could only be created via ALLOCATE'INDEXED.

2007 December, A-Shell 4.9.998: ISMUTL.LIT 1.4(132) increases the maximum record size from 8K to 16K.

2005 December, A-Shell 4.9.948: ISMUTL.LIT 1.4(131) eliminates the 2GB limit on the dump/load file, and also adds improved life signs (for long dumps/loads).

2005 December, A-Shell 4.9.947: ISMUTL.LIT 1.4 (130) supports options for Compressed Records and Compressed Indexes.

Subtopics

Compressed Records

Compressed Indexes


Compressed Records

ISMUTL.LIT 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.


Compressed Indexes

ISMUTL.LIT 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 six 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.


JSTAT

Updated March 2017

JSTAT <jobname>

JSTAT is useful for monitoring the status and activity of another job. It displays a dynamically updated screen full of information such as the number of reads, writes and basic instructions, both total and rate/sec over the last sampling interval. It also shows the last basic instruction, last xcall, last line number, current PPN, program, job status flags, etc. This can be useful in a variety of circumstances, such as debugging a job that appears to be in an infinite loop, or determining whether operator is actively keypunching or a remote job is safe to kill.

As with other utilities that rely on inter-job communication, such as KILL, FORCE and SEND, there are privilege issues to consider under UNIX/Linux, whereas under Windows the main issue is the IJCFREQ setting in the miame.ini. Refer to File Ownership and Privileges for more information on the privilege issue.

The job activity statistics are maintained in the JOBTBL.SYS file, making them available to be queried by utilities such as SYSTAT/W and JSTAT. Each job updates its own statistics in response to various triggers, the most universal of which is the Inter Job Communication clock, whose frequency is set by the IJCFREQ=<seconds> command in the miame.ini. Under UNIX systems, jobs can send a request message to other jobs using ITC.SBR, asking them to update their statistics immediately so as to be able to report the very latest. In order for such messages to be delivered, the jobs have to share the same effective user, or the sender has to be root. Failing that, the stats reported may be between 0-<IJC frequency> seconds old; you may also see an ITC error message displayed. Refer to Advanced Privilege Settings for more information.

History

2015 May, A-Shell 6.1.1408: Updated routine to recognize and preserve a new unique identifer field in the JOBTBL. The new version is backward compatible with earlier versions of A-Shell and has a "B" in the version number to help easily identify it.

2011 September, A-Shell 5.1.1235: Add support for new job table layout and ten character program name.


KILL

Updated May 2015; see History

KILL <jobname> {/k}{/y}

KILL is similar to, but more complex than, its AMOS counterpart, and works differently depending on whether you are running under Windows or UNIX. The additional complexity arises from the dual nature of jobs running under A-Shell. (Such jobs have both an A-Shell/AMOS nature and an underlying Windows or UNIX process nature.) It also arises from the fact that, unlike the AMOS counterpart, this version of KILL actually tries to clean up resources left in limbo by the target process.

For UNIX, KILL starts by checking if the underlying UNIX process still exists. (Under extreme circumstances, it may be possible to abort a UNIX process without A-Shell realizing it; thus leaving a phantom job in the A-Shell job table.) If the UNIX process no longer exists, it offers to clean up the resources (file locks and other queue blocks) still associated with the job. Otherwise, it sends a trappable kill signal (SIGINT, same as Ctrl+C sends) to the target process and waits a few seconds to see if the job goes away. If so, then we are done. If the process does not go away (possibly because the of insufficient privileges) then this fact is reported and nothing further can be done, unless the /K switch was specified. With /K, and provided that the user is logged into the OPR: account, it will then proceed to use a stronger (but still trappable) kill signal (SIGTERM) to abort the underlying UNIX process (causing a BASIC error 251 in the aborted program). Once this is complete, it checks to see if the job left any resources locked in the qflock.sys or jobtbl.sys files. If so, it prompts you to confirm whether you want them cleaned up.

The /Y switch will assume that the answer to this question is "Y", allowing it to be used in unattended processes. An example of where you might want to use this is in a nightly processing routine that requires all users to be either logged out or at least at a known menu. This could be accomplished (under UNIX) by executing SYSTAT.LIT/L, and then reading the resulting SYSTAT.LST file and checking to see which jobs are not in the proper state. Then a command file using KILL <job> for each such job can be generated and executed. Without the /K/Y arguments to KILL, it would only have the effect of forcing a Ctrl+C to these jobs. Since this might not be sufficient to force the wayward jobs out of their programs, you could use KILL <job> /K /Y. Or if you want to really be fancy, you could try it first without the /K /Y, then run another SYSTAT to see if it succeeded, and only then use KILL /K /Y on the stragglers.

Because of UNIX security rules, it is impossible for one user to send signals to another unless the first user has superuser privileges, or unless they are both sharing the same effective user ID. Refer to File Ownership and Privileges for help on achieving this, or on setting the SETUID bit on ashkill so that it runs with root privileges.

Under Windows, KILL uses the A-Shell Inter Job Communication (IJC) system to send a message to the target job, effectively telling it, in as friendly a manner as possible, to go kill itself. As with the UNIX version described above, the /K switch determines how lethal the operation is. Without /K, it is basically no different than a Ctrl+C (which may be trapped by the program, or ignored entirely). With /K, the instructions are to abort anything that is running, even VUE. (It is nice enough to save the file first though.) If a BASIC program is running at the time, it will be aborted with error 251 (which can be trapped, but only temporarily, because as soon as the program goes into a keyboard operation it will terminated without any further delay). Note that the IJC system clock frequency is established by the IJCFREQ parameter in miame.ini.

History

2017 January, A-Shell 6.3.1542: Updated to support localization; see LITMSG.xxx 039,### for message customization.

2015 May, A-Shell 6.1.1408: Updated routine to recognize and preserve a new unique identifer field in the JOBTBL. The new version is backward compatible with earlier versions of A-Shell and has a "B" in the version number to help easily identify it.


LICENS

Updated January 2016; see History

LICENS {/ATESRV}

LICENS provides the means to display your A-Shell license information, and to optionally update that information. Other methods of updating the license are to edit the miame.ini file directly, and to respond to the prompt which appears on startup if your license has expired.

When executed, LICENS displays information about the current license (similar to the ABOUT command), and asks if you want to update the license. It then prompts you for a new serial number, license key, and company name, verifies that they are correct, and asks if you want to save the updated information.

To display the license information, you may be logged into any account. To update the license, you must be logged into the OPR: account.

LICENS is also used to generate a license for ATE, the A-Shell Terminal Emulator. When updating the license, you will be asked whether you wish to update the license for A-Shell or ATE; select the appropriate one and proceed.

The /ATESRV switch, which is only applicable when using ATE, causes LICENS to request an ATE license from the server. You do not need to be logged in as OPR: when using the /ATESRV switch. Note that for ATE GUI terminal emulations—i.e. those ending in "G"—LICENS/ATESRV will be executed automatically when the client connects. As of A-Shell build 997.3, this is also true for all clients connecting as wyse50, am65, and am75 emulations. However, it does no harm to execute the command manually, and this is can be helpful in debugging if the server-issued licensing isn't working.)

For PC-based ATE licensing, the MAC address is now automatically added to the company name if it is not done manually.

Note

If you came to this page wanting to update your license, only to find out that LICENS does not run, the problem is that your version of A-Shell predates LICENS (version 4.8, build 830, of 30 April 2003). To update the license, you will need to use the "Old Method" described in Updating the License. In brief, you will have to run A-Shell from the host prompt with the start-up switch -k (e.g. ashell -k), which will prompt you for license information. If you need to use this method, be advised that your version of A-Shell is no longer supported! You should update to a more recent version.

History

2016 January, A-Shell 6.2.1425, LICENS.LIT 2.4(133): Changed PIC code format to XXXXXXX-XXXXXX-XXXXXX-XXXXXXX to allow various extensions and improved localization in A-Shell 6.3.

2015 May, A-Shell 6.1.1408, LICENS.LIT 2.4B(132): Updated routine to recognize and preserve a new unique identifer field in the JOBTBL. The new version is backward compatible with earlier versions of A-Shell and has a "B" in the version number to help easily identify it.

Older History

LIT | A-Shell | Date | Description
2.4(122) | 995.0.5 | 04 Sep 07 | For PC-based ATE licensing, the MAC address is now automatically added to the company name if it is not done manually.
2.3(120) | 985.0.3 | 09 Apr 07 | Supports server-based licensing of ATE clients in AM75 and AM65 emulation. You have to execute the LICENS/ATESRV command explicitly; the server will not automatically do it or you, as it would for the emulations with "G" on the end, but you can do it manually via LICENS/ATESRV.
2.2(114) | 949.0.1 | 24 Jan 06 | Implement "node" licensing model for ATE. This model permits licensing of a block of ATE nodes independent of the number of A-Shell licenses.
2.0(105) | 876.0.6 | 29 Mar 04 | LICENS.LIT no longer overwrites the version of the local ashw32 when licensing ATE.


LOAD

LOAD <fspec> {/lock} {/unlock}

LOAD <common-module-name> /c

A-Shell supports a "user memory" concept similar to that used in AMOS, and thus the LOAD command works similarly to AMOS, except for the special switches.

Switches

Switch | Function
/L | Locks the module in memory so that it cannot be deleted, except by specifying the /unlock switch on the DEL command.
/U | Unlock is needed in order to reload (update in memory) a module that was previously locked with the /lock switch.
/C | Indicates that the specified module name is not a disk file to be loaded into user memory, but the name of a COMMON module, which is to be initialized. This distinction is necessary since COMMON modules continue to be implemented via internal memory buffers within A-Shell rather than via user memory.
/?, /H | Writes switch listing and usage info to the screen.

Comments

The maximum number of modules which can be loaded into user memory per job is 96.


LOG

Updated June 2016, see History

LOG {/n} <destination>

A-Shell maps AMOS format file specifications onto host pathnames using the definitions given with the MIAME DEVICE commands in the environment configuration file. On entering A-Shell, your current working directory is translated into your current AMOS login account. If there is no mapping defined, then you enter A-Shell in a logged off state. You may use the LOG command to log in and subsequently change your login account to one with a valid mapping to an existing host machine directory.

The implementation of LOG will check for the validity of the PPN, execute any START.CMD command file (unless /N specified), and accept and display ERSATZ names. It does not accept or ask for user names. The user name as returned by the GETJTB.SBR subroutine is your user name in the host operating system environment.

The /n switch disables the normal execution of a START.CMD file in the target directory. Destination may consist of all or part of a device and PPN, or an ERSATZ device.

Examples

LOG SYS:

LOG DSK0:[1,4]

LOG DSK0:1,4

LOG DSK0:

LOG 1,4

LOG ,4

LOG MYAPP:

History

2016 June, A-Shell 6.3.1515: LOG.LIT 3.0(124) now explicitly reports a log failure to the screen.


LOKUTL

When LOKSER-type file locking is on (see the system parameter LOKSER for more information), A-Shell translates LOKSER service requests into the corresponding system locking function supported by the host operating system. Under Windows (non-server versions), there is no convenient function to display a list of the current file locks. However, under some flavors of UNIX (including AIX and Linux), a shareware utility, lslk, is available which scans the system locking tables and produces a list of locks. For those flavors of UNIX, the corresponding copy of lslk is distributed with A-Shell (or can be obtained from the web). This utility by itself is not that helpful, though, as the information displayed is in terms of inodes rather than files, and process ids rather than jobnames. The LOKUTL utility acts as a front end to lslk and is able to output a much more interesting display.

Under NT, Windows 2000 and XP Server editions, the Server Manager utility allows display of file locking information, but this is not accessible from within A-Shell.


MAP

MAP {/f}

MAP displays the contents of user memory, like its AMOS counterpart. If the /F (FULL) switch is specified, it displays the module flag codes associated with each module (from the table below) and also the module version.

Beginning with version 2.2(106), MAP displays the version number of program modules if the /F switch specified. This is particularly helpful when trying to figure out if you've got the proper version of an auto-loaded SBX or RUN file in memory.

Flag | Function
C | Module is cached in memory and will be deleted automatically as needed.
L | Module is locked (see LOAD / LOCK) and cannot be deleted except by del /unlock.
P | Module is "permanent". (AMOS terminology, indicating that it was manually loaded and thus will not be automatically deleted. Use del to delete.)
R | Module is running and cannot be deleted under any circumstances.
T | Module is temporary (will be overwritten by next module loaded).


MEMORY.LIT

MEMORY <size> {k}{m}

MEMORY is similar to its AMOS counterpart, except that it can be used at any time to change the user’s memory partition size. (Under AMOS you can only reduce your partition size after the system is booted.)

The initial memory size is set by the MEMORY statement in the miame.ini file.

Note that although A-Shell’s user memory implementation has some similarities to the AMOS equivalent, there are also several differences. For one, when you use LOAD to load modules into user memory, they do not actually take up space in the "partition" set by the MEMORY command. (Instead, space is dynamically allocated for loaded modules.) This is also true of a number of other memory allocations, such as temporary memory needed to load an SBX subroutine or for use in sorting. Thus, it is likely that you can get by with a smaller partition under A-Shell than you needed under AMOS. (On the other hand, memory is cheap, so why worry about it?)


MMAP

MMAP {switches}

Using the above format, MMAP displays the current list of files to be automatically memory mapped.

MMAP <new mmap fspec>

Using the second format, MMAP replaces the current memory map list with the one contained in new mmap fspec. The format of the list consists of one AMOS filespec per line, the same as for MMAPLIST statement in miame.ini file.

Switches

Switch | Function
/L | List, outputs to file MMAP.LST. With this switch, the output is displayed on the screen.
/?, /H | Writes switch listing and usage info to the screen.


MOVE

Updated and Reviewed April 2010

MOVE outspec = inspec {/switches}

MOVE moves files from one place or name to another, which is effectively the same as copying the file and then erasing the source file. In A-Shell, MOVE.LIT and COPY.LIT are actually the same program, so refer to COPY for further information.


PAGE

Updated September 2008

PAGE <command line>

The PAGE command can be used as a prefix to any other (non-screen-oriented) command to cause its output to be displayed one page at a time instead of scrolling. It stops after each screen-full of output and waits for any key to proceed. For example:

PAGE DUMP FILE.TXT

This will dump the contents of the file a page at a time. General paging may also be toggled by using PAGE /ON and PAGE /OFF.

This command can be very useful when dealing with commands that send lots of information to the screen very quickly, such as TYPE, DIR, DUMP, and COMPIL.

You can terminate the command by entering Q when prompted to proceed to the next page.

See Also

• A-Shell's Scrollback feature, which is supported in A-Shell/Windows and ATE.

History

2016 January, A-Shell 6.2.1422, PAGE.LIT 1.0(104): PAGE.LIT now sets a flag allowing other LIT and RUN programs to detect if they are running under control of PAGE. This is mainly for the benefit of ERASE, which see—the History notes—for more information.

2008 September, A-Shell build 1125: Adds support for syntax display (PAGE /?), and also checks and adjusts for common mistake of using PAGE <file> to display a file, instead of PAGE TYPE <file>. In other words, if the argument list consists of a single filespec, and that filespec appears to be a text file, it is treated as if the command was PAGE TYPE <file>.


PRE/OPRE

Originally, AlphaBASIC did not contain an include file facility, now achieved with ++include. To get around this problem, a pre-compiler was developed, and was used by many dealers today, particularly in the UK. This pre-compiler uses $COPY to indicate a file to be included in exactly the same way. The difference is that $COPY statements may be nested whereas ++include statements may not. The pre-compiler generates an intermediate file (.PRE) which contains the expanded source, and which is then normally compiled automatically and erased. It may be left on disk, however, by specifying the /F switch. In addition, any of the compiler line switches may be specified, and these are passed on to the compilation phase.

The pre-compiler was traditionally called PREBAS under AMOS. As with the compiler itself, A-Shell contains two versions, one for AlphaBASIC 1.3 (OPRE) and one for AlphaBASIC 1.4 (PRE). A .DO file (with the name PREBAS if desired) may be set up to use the appropriate version.

As with ++include, $COPY will accept either AMOS-format file specifications or host pathnames as arguments.


PRINT

Updated January 2009

PRINT {spooler=}<wildcard list> {switches}

The A-Shell version of PRINT functions similarly to the AMOS version and supports the switches given in the table below. As with the AMOS version, you only need to include enough characters of the switch name to specify it uniquely. Thus /NOB is equivalent to /NOBANNER, etc. Also, the default for most switches may be set by a statement (e.g. BANNER = OFF) in the INI for that printer.

If the spooler name is omitted, the default (as specified by the PRINTER= statement in the miame.ini will be used. It must match up with a spooler initialization file named %TEMP%\<spooler>.PQI or SYS:<spooler>.INI or ASHCFG:<spooler>.PQI which contains the configuration parameters for that logical printer. Under A-Shell/Windows, you can also use the special spooler name "PROMPT" (which displays a typical Windows printer selection dialog) or you can specify a printer name that is recognizable by Windows (i.e. the type that appear underneath the printer icons). In these last cases, there will be no printer initialization file, and a default configuration consisting of PASSTHROUGH=OFF and PITCH=AUTO will be used.

A-Shell does not include an internal implementation of the spooler, and instead uses the "natural" spooler for the host operating system. Thus, the precise effect of most of the option switches described will vary from one operating system to the next. See Printer Configuration for more information.

Switches

Switch | Function
/{NO}B | Controls whether a banner is sent at the start of the printout. Under Windows this has no effect. Under most UNIX versions, the default spooler behavior is to force a banner regardless, unless the option to request no banner has been specifically enabled with something like: # /usr/lib/lpadmin –p <ptr> -onobanner
/C:## | Specify number of copies of file to print.
/{NO}D | Controls whether the file is deleted after printing.
/{NO}FF | Controls whether a formfeed is sent after the last page.
/{NO}H | Controls whether a header is printed at the top of each page indicating the filename, time, date, and page number. Since this feature is not offered by most non-AMOS spoolers, the A-Shell PRINT command has to simulate it by creating a temporary file with the headers and then spooling that file in place of the original.
/{NO}LA | (Windows only) Overrides the ORIENTATION parameter in the printer ini file.
/LPP:## | When used in conjunction with the /HEADER option, defines the number of lines printed per page.
/M:## | When used in conjunction with the /HEADER option, defines a left margin size.
/{NO}PA | Passthrough switch: controls whether the file is sent "raw" to the printer or is allowed to be "cooked" by the printer driver. Refer to the discussion on PASSTHROUGH for more information on this important topic.
/OVERLAY:fspec |
/PREFIX=fspec | Allows you to specify a file that will be prepended (as a prefix) to the file you are printing (overriding any PREFIX option specified in the printer INI).
/{NO}PREVIEW | Set behavior of APEX to preview or not preview received reports. This value overrides user setting. PRINT.LIT 3.0(123).
/Q | Standard query switch – causes each matching filename to be displayed and the user given a Y/N choice of whether to print that file.
/SUFFIX=fspec | Allows you to specify a file that will be appended (as a suffix) to the file you are printing (override any SUFFIX option specified in the printer INI).
/SW:#### | Provides an alternate way of passing switches. Instead of by name, you can pass the sum of the numeric switch values, as you would in the SWITCHES parameter of SPOOL.SBR/EZSPL.SBR. PRINT.LIT 3.0(123).
/W:## | When used in conjunction with the /HEADER option, defines the position of the "Page #" at the right side of the page header.
/? | Writes switch listing and usage info to the screen.

The technique for displaying the print queue and canceling a printout varies from one operating system to the next. Under Windows, you just use the Print Manager (generally accessible by double-clicking on the printer icon in the system tray at the end of the task bar). Under Linux, the typical equivalents are lpq and lprm. To execute these from the A-Shell dot prompt, just create a DO file which uses the HOST command (e.g. HOST lpstat –t). Also, most UNIX variations have a menu-driven or even GUI utility for doing these kinds of things.


QUTL

Updated November 2016; see History

A-Shell on multi-user systems (and even stand-alone) uses a queue file, qflock.sys, in which to store information which may be shared by multiple users. This file is in the form of a linked list, analogous to the AMOS queue blocks system, and is used by the FLOCK and XLOCK subroutines.

The QUTL command is primarily intended to give some control over the FLOCK and XLOCK locks present on the system, by reading and processing the queue file. It can display which users currently have locks, and is also able to re-initialize the XLOCK and FLOCK queue lists , a process which normally requires a machine reset under AMOS, or some specially written assembly language routines. QUTL may also be used to zap a logged on A-Shell user. This will remove all locks and queue blocks associated with that user, and although the user may continue to be able run whatever program they are in, as soon as it attempts to make an XLOCK or FLOCK call, or when it exits back to the dot prompt, it will see that it has been removed from the queue and will abort with an appropriately (cryptic) error message. (Something like "your queue file has been zapped.")

When used to list the existing XLOCKs and/or FLOCKs, QUTL provides an option to output the list to a file. This, combined with the fact that you can run QUTL from a command file, provides a mechanism for nightly processing programs to check if any locks were left in use, and optionally remove them (either by zapping the queue entirely, or just the user, or by using the KILL.LIT utility).

You must be logged into OPR: in order to use the queue utility.

History

2016 November, A-Shell 6.4.1534, QUTL.LIT 3.1(129): Remove previous maximum of 20000 FLOCK or XLOCK records and reduce the fixed partition memory requirement from approximately 700K to 200K by using dynamic arrays.


RENAME

Updated June 2011; see History

RENAME <out-wildspec>=<in-wildspec1> {switches}

RENAME renames files without moving them.

Parameters

out-wildspec

may be a single file, or a wildcard specification.

in-wildspec

may be a single file, a wildcard specification, or a comma-delimited list of file or wildcard specifications.

Switches

Switch | Effect
/D | Overwrite the name of an existing output file (whose contents would then be deleted).
/Q | Queries the user for a confirmation before renaming each of the input files.

Although RENAME appears to have the same syntax as COPY (and MOVE), it is restricted by the fact that the output file location must match the input file location. This is normally used on files in the current directory, eliminating the need to specify a device or PPN.

Note that RENAME recognizes filespecs ending in a period ( "." ) as indicating a file with no extension, rather than as a wildcard.

History

2011 June, A-Shell 5.1.1221: Remove the limit on the number of PPNs allowed per device.


RUN

Added October 2016

RUN <program-spec>

RUN loads the specified program into memory and starts the runtime interpreter executing it.

Parameters

program-spec

an unqualified (e.g. PROG), partially or fully-qualified specification of a compiled A-ShellBASIC program file.

Comments

The file extension defaults to RUN if not specified. If the path is not specified, the search path starts in the current directory, then the [p,0] directory, then DSK0:[7,6] (aka BAS: ).

RUN file names, like other A-Shell filenames, are typically limited to ten characters, not counting the extension. And the RUN file locations are normally specified using AMOS-style notation, although as of 6.3.1530.0, you can use native-style file specifications as long as they are quoted. For example:

.RUN MYPROG

.RUN MYDIR:INVOICES

.RUN DSK1:SENDMAIL[100,5]

.RUN "/vm/miame/dsk0/077077/yearend.run"

Regardless of whether the path is fully specified, RUN first checks to see if the <file>.RUN is loaded into memory (see LOAD.LIT). RUN programs loaded explicitly using LOAD.LIT will remain in memory; otherwise they are removed from memory on completion.

Compiled SBX subroutines (see Subroutines vs. BASIC programs - http://www.microsabio.net/dist/doc/conref/00ashref.htm#!subroutinesvsbasicprograms.htm) have the same internal format as regular programs and thus may be run by the RUN command, provided you specify the .SBX extension, e.g.

.RUN BAS:SBXINP.SBX

Note that most SBX routines do not make sense to execute this way, but there is no technical obstacle to creating an SBX routine that can be executed both by RUN from the command prompt as well as by XCALL from within a program.

History

2016 October, A-Shell 6.3.1530: quoted native filespecs now supported with RUN, e.g. .RUN "/vm/miame/webcache/hello.run"


SAVE

SAVE <name.ext> {/delete}

SAVE, like the AMOS counterpart, saves a module from user memory to disk. The /delete switch is needed to overwrite an existing file.


SEND

Updated May 2015; see History

SEND applies to both Windows and UNIX, and although it operates differently in each case, the general idea is pretty much just like the AMOS equivalent.

SEND {switches} <target name> <message>

The two optional switches are /T and /B, which cause the message to appear on the top or bottom status line, respectively, of the target terminal, rather than at the current cursor location. This assumes that the target terminal supports status line operations; otherwise the switch is ignored.

Switch | Effect
/T | Send message to top status line
/B | Send message to bottom status line
/?, /H | Writes switch listing and usage info to the screen.

The <target name> may be either the job name or the login user name of the person you want to send a message to, or "ALL", "TODOS", or "TOUS" for everyone. (You can use the SYSTAT command to help you determine which job and user names are available.)

Under UNIX, SEND is implemented via the operating system’s signal delivery system. If the target is running PolyShell, then the message will appear in a pop-up window. Otherwise, the message will simply appear at the current screen cursor location, overwriting whatever was there previously.

Because of UNIX security rules, it is impossible for one user to send signals to another unless the first user has superuser privileges, or unless they are both sharing the same effective user ID. See File Ownership and Privileges for instructions on achieving this.

Under Windows, SEND is implemented using the "Inter Job Communication" (IJC) system, which was introduced in A-Shell 4.6. Unless the /T or /B switch is specified, the message is displayed in an independent pop-up window using the AWMSG.EXE utility which is distributed with A-Shell. The message window initially appears on top of all other windows, and does not interfere with the target A-Shell window in any way.

History

2015 May, A-Shell 6.1.1408, SEND.LIT 2.2B(123): Updated routine to recognize and preserve a new unique identifer field in the JOBTBL. The new version is backward compatible with earlier versions of A-Shell and has a "B" in the version number to help easily identify it.

2011 September, A-Shell 5.1.1235: Minor adjustment to drop the sending job name from the message (in order to allow more space for the message itself, since part of that space was taken over for the new expanded program name.)

Subtopics

SENDing to ATE


SENDing to ATE

SEND.LIT 2.2A(121) under UNIX now supports a /W switch to send a "Window" message if the terminal is a ZTERM or ATE workstation. Otherwise it acts just like SEND without a switch.

The Window version of the message launches an external application, ASMSG.EXE which must be in the path on the workstation. The best place to put it is in the directory where ATE or ZTERM is launched from (e.g. typically c:\program files\microsabio\ate\bin or c:\program files\cool.stf\zterm for windows, although it could also be the Windows directory.

The idea of using an external program to display the message is to allow sites or resellers to customize the message utility. We provide a very simple example in the SYS: directory of the UNIX releases now.

If you want to create your own, the requirement is that it support the following command line format:

asmsg.exe /T:title /M:message

To distribute the utility, you may want to add logic to your application startup to use the ATSYNC mechanism, or a standard ZTERM file transfer, to copy it from the server to the workstation. The utility is small enough that this will take nearly no time at all. We would have done this automatically within the message handler, but since file transfers can sometimes require user intervention, it seems questionable to get into that during a signal receiving routine.

Note that the existing AWMSG.EXE which is distributed with A-Shell/Windows and used by default with SEND.LIT will work fine with the UNIX version (just copy it to ASMSG.EXE). The only difference between it and the standard release ASMSG.EXE is that ASMSG.EXE displays a much bigger window.


SET

The SET command under A-Shell supports a subset of the AMOS display and settings, as well as some extensions. The functions that are fully supported are listed below, followed by notes about features that differ significantly from the AMOS counterpart. Entering SET with no specifications will display current settings, and SET/? will display options. The items marked with "A-Shell" in the "Source" column have no corresponding AMOS equivalent.

Function | Source | Displays
{NO} ABSLOOKUP | A-Shell | Always return absolute value in LOOKUP.
{NO} HASH | A-Shell | Turn on and off AMOS compatible hash codes, and applies only to text files under A-Shell/UNIX. The default is off. When on, the A-Shell hash routine will pretend as if there were a CR to go along with any LF line terminators when generating a hash code (since UNIX text files normally only have LF line terminators whereas AMOS, Windows, and DOS use CRLF).
{NO} AMOSRUNSBR |  | Execute AMOS.SBR within current process.
{NO} AUTOTPRINT |  | Turn on/off AUTOTPRINT.
{NO} CMDINP | A-Shell | CMD file input.
{NO} CTRLC |  | Ctrl+C
{NO}DEBUG {#} |  | Cause RUN programs compiled with /X:2 but not /DEBUG, to interpret the DEBUG variable as 1 (or # if specified.)
{NO} ECHO |  | Character echo.
{NO} EXTFIO | A-Shell | Extended file I/O.
{NO} FIELDEMU | A-Shell | Field Emulation.
{NO} FPROUND | A-Shell | Floating point expression rounding.
HEX |  | Set Hex output.
INFDEF |  | Change or display INFLD codes.
{NO} LATIN1 | A-Shell | LATIN1 eight-bit mode.
{NO} LOKSER | A-Shell | Turn LOKSER on/off.
LONGDIR |  | Forces DIR to act as if the /L{ONG} switch had been set.
OCTAL |  | Set Octal output (e.g. in DUMP).
PROMPT <prompt> |  | Set command prompt to <prompt>.
{NO} STRICT |  | Strict AMOS compatibility mode.
TERMINAL options |  |
TITLE definition string |  | Set top status line or window title.
TRACE options |  |
WEBCACHE | A-Shell | Set various options for A-Shell WEBCACHE system.

History

2016 October, A-Shell 6.3.1531: SET.LIT 1.2(158) adds WEBCACHE


CMDINP

This turns on and off command file input within XCALL INPUT or XCALL INFLD. The default is off, in which case these input routines do not accept input from a command file. INFLD supports a TYPE code "p" which turns on command file input, and you can force this on by adding SBR=INFDEF:p to your miame.ini file. But these methods either require a change to your program or that you exit from A-Shell and modify the miame.ini file. The SET {NO}CMDINP command, on the other hand, can be used within A-Shell, or even within a command file. For example, you might have a command file which contains:

:R

SET CMDINP

RUN MENU

15

<program inputs>

SET NOCMDINP

RUN MENU

HOST

The above command file starts by setting command input on, and then runs a menu program, and forces it to select option 15. It then continues to include the necessary prompts for the program corresponding to menu option 15, after which that program finishes and returns to the command file. Then it turns command file input back off again and starts up the main menu, which now waits for real keyboard input. Finally, when the user exits out of that menu, the command file picks up and forces A-Shell to exit.


INFDEF

SET.LIT supports an INFDEF option to display or change the list of default INFLD codes (previously only able to be set via the miame.ini SBR=INFDEF statement.) Syntax:

.SET INFDEF (display)

.SET INFDEF <codes> (replace current defaults with <codes>)

MIAMEX, MX_INFDEF allows the same capability from within a program. If opcode is 0, the current default type codes are returned in the INFDEF parameter, otherwise the current default type codes are replaced by those in the INFDEF string.

The maximum size of the default string is currently 36.

This feature is of course handy for experimenting with global INFLD TYPE codes within a single job (without interfering with other jobs). It may also be useful for changing the defaults with a single program. Note that for a particular INFLD call, you can disable the default TYPE codes by adding m to the TYPE parameter passed to INFLD.

History

2005 January, A-Shell 4.9.910, SET.LIT version 1.0(142): Function added


TERMINAL options

Updated and reviewed April 2011

SET TERM{INAL} with no further arguments displays the current terminal settings, e.g.:

.SET TERM

Current terminal settings for TSKAAA are:

Terminal driver: PCTDVG

Baud rate: 19200

Terminal width: 80

Terminal height: 24

Foreground color: 6

Background color: 0

Beveling: Auto

Sys bg color None

Win bg color 0

Win text color None

Otherwise you may specify one of the variables in the table below, along with one of the allowed values, to update the terminal settings accordingly, e.g.

.SET TERM BCOLOR 2

.SET TERM HEIGHT 32

.SET TERMINAL DRIVER AM75Z

Variable | Values | Description
FCOLOR n | n | Set foreground color to n, where n is 0 to 7. Requires Windows or color emulation.
BCOLOR n | n | Set background color to n where n is 0 to 7. Requires Windows or color emulation.
HEIGHT n | n | Set height (number of rows) to any value of less than 51. See Comments, below.
WIDTH n | n | Set width (number of columns) to any value of less than 161, less than 40 not recommended. A-Shell/Windows or ATE.
BEVEL | off, auto, program | Set beveling option to off, auto or program. A-Shell/Windows only.
SYSBCOLOR n | n | Link background color n to Windows dialog/button color (gray), where n is 0 to 7. A-Shell/Windows or ATE.
WINBCOLOR n | n | Link background color n to Windows edit box color (white) , where n is 0 to 7. A-Shell/Windows or ATE.
WINTXTCLR n | n | Link foreground color n to Windows text color (black) , where n is 0 to 7. A-Shell/Windows or ATE.
TSTATUS | on / off | Turn top status line on/off. A-Shell/Windows or ATE.
BSTATUS | on / off | Turn bottom status line on/off. A-Shell/Windows or ATE.
WSTATUS | on / off | Turn Windows status line on/off. A-Shell/Windows or ATE.
DRIVER | name | Set the TERM envrionment variable and internal terminal driver

Comments

The HEIGHT option is particularly complicated in its dependencies. For A-Shell/Windows and ATE (with any of the "G" emulations), the height may be adjusted from 1 to 50 rows. For remote terminal connections (A-Shell/UNIX or ATSD), if the terminal/emulator is AM75, the valid options are 24 and 50. However, if the emulator is ZTERM v144+, and the TERM environment variable is set to "AM75Z", then the valid options are 24-50. The DRIVER option may be used to set the terminal environment variable (which also resets the terminal and internal driver accordingly).

Note that terminal height/width can also be set via the TAB(-5,rows) and TAB(-6,cols) commands.

History

2004 August, A-Shell 4.9.897: SET.LIT supports two new commands to link A-Shell color palette numbers to Windows desktop colors, to go along with the existing SET TERM:

SET TERM WINBCOLOR n

SET TERM WINTXTCLR n

The first (WINBCOLOR) sets the "Window Background" color n, which is typically used for the background of small windows such as edit boxes, checkboxes, and listboxes (typically white).

The second (WINTXTCLR) sets the "Window Text" color n, which is typically used for text both on buttons and in edit boxes and listboxes (typically black). Note that the n here is taken from the foreground palette (unlike WINBCOLOR and SYSBCOLOR which both refer to color numbers from the background palette).

Along with SYSBCOLOR, these can now be used via ATE on UNIX servers.


TITLE definition string

The SET TITLE command takes a string argument, optionally preceded by $TS, and which may contain any literal text that you want to appear as the title. If the $TS prefix is specified, the title will appear on the top status line; otherwise it will appear on the window title bar, providing you are running A-Shell/Windows, or you are using ZTERM as your terminal emulator to connect to some flavor of A-Shell/UNIX. The following special variables may appear anywhere in the title string:

Variable | Displays
$NC | Name of last executed command (e.g. "SET", "LOG") or program.
$ND | Name of current logged in device (e.g. "DSK0")
$NJ | Your job name
$NP | Name of last program executed (same as $NC but excluding LITs)
$PA | Platform A-Shell was compiled for (e.g. "Linux", "Windows/32", etc).
$PN | Current p,pn (e.g. "[7,6]")
$VA | Version of A-Shell (e.g. "4.6(753)")
$VP | Version of current program or command (e.g. "1.0(123)")

If the title definition string contains any of the above variables, the title will be automatically updated when the value of that variable changes. For example, if the title is defined via:

SET TITLE Job $NJ running $NP version $VP in $ND:$PN

Then whenever the program name (excluding LITs) or the current logged in device or PPN changes, the title line will be updated, and would appear something like this:

Job TSKAAB running MYPROG version 1.0(123) in DSK0:[7,6]

If you do not specify the $TS prefix (for top status line) and you are not running on either A-Shell/Windows or using ZTERM as your emulator, then the title will just be ignored.

If you do specify the $TS prefix and you are running PolyShell, then the title on the top status line will be updated whenever you switch to that window. If you have job-specific information in the title string, then it is highly recommended that you use SET TITLE on each of the processes running under PolyShell; otherwise, when switching to a job or session with no title definition, the previously displayed title will remain, possibly causing confusion for the user.


TRACE options

Updated October 2016; see History

These are equivalent to the identically-named TRACE options in the miame.ini file. Since they are primarily used only for debugging, it is a handy convenience to be able to turn them on temporarily for a single job or program execution without having to modify the miame.ini file and re-launch the session. These variables accept only ON or OFF settings.

Note that depending on the operating system you are running, some of the options may not appear. For example, signals are only available under UNIX.

In most cases the output of the traces go to the ashlog.log file, which is in the same directory as miame.ini, unless specified elsewhere with the LOGDIR= command in the miame.ini.

Note that any attempt to set any other parameter, even if it is a valid parameter under AMOS, will result in the same error message ("?Invalid function").

With ATE or A-Shell/Windows most log messages can also be captured/displayed in the Debug Message window (use Ctrl+Shift+DoubleClick somewhere on the window) by opening the Properties dialog (right click on the debug message window) and activating the "Show System Traces" option along with any desired trace options.

See the table in the TRACE system paramater topic for a full listing of all options.

History

2016 September, A-Shell 6.3.1526 and SET.LIT 1.2(156): updated to support TRACE flags JOBLCK and EXEC, which were added in 6.3.1518.0.


WEBCACHE

Added October 2016

Note: this documentation is in progress, and is pretty rough. It is complete as far as it goes, but has not yet been organized into a normal and coherent form.

Dev Note 1529.0.2 of 30 September 2016

SET.LIT 1.2(157) now supports options to manage and configure the new webcache feature:

Option | Description
(blank) | display current webcache settings
? | display usage information
ENABLE | enable
DISABLE | disable
CLEAR | erase all files in local webcache
REFRESH <spec> | remove files from cache matching spec
REPO <url> | set the web repository directory
<option,...> | set options...

options:

Option | Description
PROG | activate webcache for programs (RUN, LIT, SBX)
OPENI | activate webcache for sequential input file opens
LOOKUP | activate webcache for LOOKUP operations

Dev Note 1531.0.2 of 05 October 2016

SET.LIT 1.2(158) adds new flags DLL, ALL, and ATE.

DLL flag causes A-Shell to attempt web download of missing DLLs from repository; if possible, it downloads them directly into the executable directory, else into the webcache directory.

.SET WEBCACHE ENABLE,DLL

ALL flag sets all options but not ENABLE itself, equivalent to PROG, OPENI,LOOKUP,DLL and any others to come in the future.

.SET WEBCACHE ENABLE,ALL

ATE pseudo-flag tells SET to pass the webcache flags and repo info to the ATE client. Note that if you want to assign different options and/or repository directory to ATE, use the following sequence:

.SET WEBCACHE REPO <repo for ATE>

.SET WEBCACHE ENABLE,<options...>,ATE ! forward options & repo to ATE

.SET WEBCACHE REPO <repo for server>

.SET WEBCACHE ENABLE,<options...> ! set server options only

History

2016 October, A-Shell 6.3.1529, 1531, 1532: WEBCACHE function added to A-Shell. The module includes a basic description, the SET.LIT options for WEBCACHE , new functions WEBRUN.LIT, MX_WEBCACHE.SBR and ? tab(-10, AG_WEBCACHE). The file CMD:TESTCACHE.CMD has been added to A-Shell as a convenience to make it easy to test the webcache; it contains the commands SET WEBCACHE REPO http://www.microsabio.net/testrepo and SET WEBCACHE ENABLE,ALL,ATE.


SHLEXC

SHLEXC filespec

SHLEXC, short for "Shell Execute," causes your PC to execute the file you've specified, using the Windows file association list of applications. This is the A-Shell command line equivalent of executing a file from Explorer. If you issue, for example, the command:

shlexc %MIAME%\miame.ini

Windows checks the file association list to find out the application associated with ".ini" files (let's say it's Notepad), launches Notepad, and loads the file "miame.ini."

The filespec can be in either A-Shell or native (Windows) format, and supports embedded environment variables (as shown above).

History

2017 January, A-Shell 6.3.1542, SHLEXC.LIT 1.0(103): Enhanced using XSHLEX.SBX so that it now works in server environments with ATE or ZTERM clients, auto-transferring the file to the client if necessary. Requires XSHLEX.SBX and ATEAPX.SBX in BAS:


SORT

Updated and Reviewed August 2010

SORT filespec

SORT performs line-by-line reordering of text files. It prompts for the necessary options, so it is largely self-explanatory, as shown in the following example.

sort somefile.txt

Record size: 80

Key length: 10

Key position: 1

Key order (A/D{N}{F} or ? for help) : ?

Enter: A(scending) or D(escending) followed optionally by N and/or F

N=natural (more 'human' - group digits, ignore spaces, etc.)

F=fold (treat upper/lower case as equivalent)

Key order (A/D{N}{F} or ? for help) : AN

Key length:

It prompts for up to three sets of key parameters (length, position, order). The file is then sorted in place, replacing the original. The "record size should be set to the length of the longest line in the file.

Unlike BASORT.SBR, there is no option for binary or floating point key types, as this is intended purely for sorting text files. The "natural" sort order option (see History, below) uses an algorithm by Martin Pool that relaxes the strict ASCII byte-by-byte sorting rules to yield something more likely to seem natural to humans. For example, "100 Main St." would sort after "99 Main St."

History

2017 January, A-Shell 6.3.1542, SORT.LIT 1.1(106): now supports localization; see LITMSG.xxx 056,### for message customization. Also, the display has been updated to show the number of records sorted.

2009 January, A-Shell 5.1.1136, SORT.LIT 1.1(104): now supports the "natural" sort option and also the fold (case insensitive) option. The options may be specified individually for each key by appending "N" (natural) and/or "F" (fold) to the A or D currently used to specify Ascending or Descending.


SRCCOM

SRCCOM {listfile=} oldfile, newfile {switches}

SRCCOM compares two source files, reporting the differences. This is useful, for example, when comparing two versions of a program to see what has changed between them. It is most useful when the differences between the files are few; when they are substantial, it becomes both overwhelmed and overwhelming.

Switch | Effect
/B | Brief listing – same as /Q but without line numbers
/Q | Quick listing – list only the lines that differ between the two files
/?, /H | Writes switch listing and usage info to the screen.

Under UNIX, there is a much more powerful file comparison utility call diff, and in some cases, diff3, which can compare three files at a time. See the notes on DIFF, a A-Shell front-end to diff.

Note also that SRCCOM.LIT includes the list file name and switches in the listing header, matching the format of the AMOS version.


SUBMIT

Updated November 2014; see History

To submit a task:

SUBMIT ctlfile {do-params} {switches}

To kill a task:

SUBMIT /K seqno | pidno | jobno

To list tasks submitted by this job that are currently running:

SUBMIT

SUBMIT accepts the command line argument ++fspec, for which see History, below.

The A-Shell SUBMIT command is similar to the AMOS counterpart, in that it causes a new process to be launched, either now or at a specified later time, which executes commands specified in the control file. Under AMOS, this is managed by a background job called the Task Manager. Under A-Shell, there are actually three different possibilities, depending on the operating system and whether the /after and /next switches are used:

· Windows

· UNIX Immediate

· UNIX Via Scheduler

In all cases, like its AMOS counterpart, SUBMIT requires a control file (typically with a CTL extension) which functions more or less just like a command or DO file (i.e. containing the commands necessary to run the job, along with any keyboard inputs.) Programs running under the control of SUBMIT will automatically take their input from the control file, even if they wouldn’t normally accept input from a command file. The do-params are processed in the same way as the argument list to a DO file; see Arguments $0 through $9 for details. When the control file runs out of input, the process terminates. The preferred way to terminate the process is for the program to cleanly exit back to the control file, and for the control file to end, optionally with a LOGOFF command. See the SBR option SUBMIT2 for related information.

Switches

Switch | Effect
Do file parameter | Unlike the AMOS implementation, the A-Shell version of SUBMIT allows DO file parameters to be passed to the control file (which can use the $0-$9 syntax, just like normal DO files, to represent the formal parameters). Any space-delimited tokens following the control file name and preceding the first switch (marked by a slash) will be passed to the control file as DO parameters.
/I "inifile" | Forces the child process to use a different A-Shell configuration file than the parent process. Note that the inifile name should be a native file specification, and must be enclosed in quotes (to prevent the slashes in the file spec from being confused with switches).
/L logfile | (UNIX only) Overrides the default log file name. (Specify an AMOS-type filename.)
/J jobname | Functions just like the -j switch to A-Shell (allows you to give the background process a specific name). Otherwise, a name of the form TASxxx (TASAAA, TASAAB, ...). will be generated automatically.
/BA buffile | Activates the auto-snapshot feature of INFLD and appends each snapshot to the specified file. The default file extension is BUF, and the default location is MEM0:[1,1] (if it exists) or the current login directory where the first snapshot occurs. Works internally by passing the –ba <buffile> switch to the child A-Shell process and by adding the |S type code to the INFDEF (default INFLD parameter) string.
/BC buffile | Same as the /BA option except creates a new snapshot buffer file (overwriting any existing one).
/CU | Will display the group for each job, if applicable. Requires A-Shell 6.4.1540 or greater, and use of group licensing.
/W: # | (UNIX only) Wait # minutes for the submitted process to complete, then kill it. If # is omitted, the submitter will wait indefinitely. This may seem to defeat the purpose of running a process in background, but can be useful either when the main objective is to look at the LOG file, or when you want to run processes that otherwise would not accept input from a command file. Note that the minutes argument was added in SUBMIT version 3.1(143) of 05 June 2006, A-Shell build 957.
/K seqno| pidno|job | (UNIX only) Kill a process currently running. To identify the process, you may specify either the "sequence number", the "process id (pid) number", or the job name (which you can get by using the SUBMIT display mode, with no arguments). Note that unless you are the superuser, you may not be able to kill any background processes other than those that you have launched.
/AFTER:{+}timspc | (UNIX only) Causes the control file to be submitted via the UNIX ‘at’ background processor, instead of as a child to the current job. (See note above about the ‘at’ processor.) The timspc argument may be specified using the form M-D-Y{,HH:MM}. The M-D-Y portion must be specified simply as zero for today. The optional {+} makes the time specification relative to now. Examples: /AFTER:0,23:00 (11 PM tonight) /AFTER:06-30-03,00:30 (12:30 AM on June 30, 2003) /AFTER:+1-0-0 (one month from now).
/NEXT:timspc | (UNIX only) Equivalent to /AFTER:+timspc.
/? | Writes switch listing and usage info to the screen.

Comments

Note that there are a number of differences between SUBMIT.LIT under A-Shell and submitting a task to the AMOS Task Manager. First, with SUBMIT.LIT, there is no task manager; instead, the process runs as a child to your current process. Second, there is no queue; the task starts executing immediately (and there is no particular limit to how many tasks you can submit this way with overlapping execution). Third, none of the AMOS embedded control file directives (which contain the $ symbol) are supported under A-Shell. Fourth, although you can use the SUBMIT.LIT program to check on the status of background tasks (and even kill them), under A-Shell, you can only do so for tasks which you have submitted (unless you are the Superuser).

History note: 1227 note comes from DO.LIT

2016 December, A-Shell 6.3.1540: Implement /CU switch to display group.

2014 November, A-Shell 6.1.1398: Improve granularity and therefore responsiveness of /W (wait) operation. Display wait times in hundredths of seconds.

2011 November, A-Shell 6.0.1240: Remove the limit on the number of PPNs allowed per device.

2011 August, A-Shell 5.1.1227: DO.LIT / MDO.LIT 2.1(124) and SUBMIT.LIT 3.1(150) now supports file-based variable command line arguments using the ++fspec syntax.


Windows

Here, SUBMIT only partially simulates the Task Manager by launching a new instance of A-Shell to run the specified task. This is acceptable for tasks which have explicit outputs or side effects (for example, a report or series of COPY commands), but it does not really run in "background", and there is no LOG file. In the Windows environment, if you want to schedule a task that is launched by the operating system at the specified time, you should just use the Windows Task Scheduler (Programs | Accessories | System Tools | Scheduled Tasks).


UNIX Immediate

In the case of A-Shell/UNIX without the /after or /next switches, A-Shell launches a new process to run the specified task as a child of the current process. However, unlike the Windows case, the new process does run in background, with all of its screen output being written to the LOG file (e.g. a file with the same name and location as the ctlfile, but with a LOG extension.) If the parent exits before the child does, the child task will continue to run but will be marked as a zombie.

In the above case, if there is an error during the attempt to launch the new instance of A-Shell (perhaps because the ashell executable is not in the PATH or the MIAME environment variable is not defined), then information about the error will be written to the standard A-Shell log file (ashlog.log, in the directory where the miame.ini is).


UNIX Via Scheduler

The case of A-Shell/UNIX with the /after or /next switches is the most similar to the AMOS Task Manager. The task is submitted to the UNIX at manager, which, like the AMOS Task Manager, keeps track of it in a queue until it launches it at the specified time. The process will run with the same login identity and environment as the process that submits it, but since it runs as a child to the at manager, it is independent of the original submitter (and thus not subject to becoming a zombie.) As in the prior case, all output that would otherwise have gone to the screen is sent to the LOG file instead.

The at manager is similar to the more familiar cron manager, both of which can be found on almost any UNIX/Linux system. The cron manager is more suited to tasks that are to be run at regularly scheduled intervals; you submit jobs to it via the crontab command. The at manager, on the other hand, is more suited to jobs that are to be run once at a specified time in the (immediate or distant) future. To submit jobs to be run by the at manager, you can use the UNIX at command. SUBMIT.LIT just acts as a front-end to at to allow you to use the simpler AMOS command syntax.


SYSTAT

Updated March 2017; see History

SYSTAT {switches}

SYSTAT displays "system statistics" like the following:

Status of A-Shell/32 Ver. 6.3.1543.9 on Thursday, February 23, 2017 22:42:51

TSKAAA TSKAAA Ty DSK3:347,0 RN SYSTAT 12292 4546K

1 jobs allocated on system, 1 in use

Total memory on system: unknown

Sys Uptime is unknown

DSK0 797761 MB free DSK1 797761 MB free

DSK3 797761 MB free DSK2 797761 MB free

4 devices on system, total free blocks may be shared among devices

The lines which correspond to the individual jobs are actually formatted identically to the AMOS version of SYSTAT, except that the memory size is always shown in K, to make room for the UNIX process id, which displays (under A-Shell/UNIX) between the program name and the memory size. The available job states are currently only "RN" and "^C", unlike the AMOS version which shows many more states.

Note that in the list of devices, one or more of the pseudo AMOS-like devices may share the same physical disk device on the host operating system, and thus the number of blocks free is the same. In the example above, DSK0, DSK1, and DSK2 are all hosted on the same device, while DSK3 is apparently not accessible.

Note also that beginning in SYSTAT.LIT 3.0(161) of December 2009, the display format is automatically widened, but only if necessary, to prevent numeric overflow of the available disk blocks (more than 999,999,999 blocks).

Switches

The A-Shell version of SYSTAT offers a number of switches which can be listed with SYSTAT/?.

Switch | Description
A | Displays all of the "allocated" jobs (i.e. those listed in TRMDEF.INI) even if no corresponding process has been launched.
ATE | Identifies ATE connections (in place of the pid); either "ATE/SRV" to indicate that the license was issued by the server, or "ATE/PC" for other ATE connections. The ATE version number will be displayed in place of the memory partition size (added in A-Shell build 1138).
B | Displays only background jobs.
C | Controlling Terminal: Displays the controlling terminal’s device identification.
CU | Like /C but displays both the machine name and unique identifier (in place of the user name and login columns).
E | MAC Address: Displays the client MAC address if known.
F | Displays only foreground jobs (i.e., jobs with display devices attached).
H | Displays available disk space in "human-readable" units (GB or MB) rather than 'blocks'. This feature added in SYSTAT 3.0(161), A-Shell build 1169 of Dec 09.
I | Displays IP address. This feature added in SYSTAT 3.0(150).
K | Kill Phantoms: Checks for and kills phantom jobs under UNIX.
L | Sends the output of the display to the file SYSTAT.LST in the current directory rather than to the screen. This is useful when you want to examine the state of the users programmatically.
M | Displays the minimum amount of free (unused) memory so far in the life of each job, instead of the allocated amount. This can be useful in judging whether your memory partitions are reasonably sized.
N | Eliminates the display of the devices. This is particularly useful when you have a lot of devices, especially if some of them are slow to respond due to being offline or connected over a WAN.
P | Pause after each page of display. Also see the notes on PAGE.LIT for another way to get the same effect.
R | Display "Real" jobs only. Omits PolyShell control jobs from the display.
S | Sort the display of users by job name.
SU | Sort the display of users by user name.
ST | Sort by job type (daemon, pshell, background, foreground)
V | Display the A-Shell version running for each job. This is useful during updates or in situations where the executable may be loaded from different places in order to verify that all users are on same version. (See history)
W | Display in Wide mode, totals several of the columns.
X | May be used with /L to force the new layout in the file version. (See history)
Z | Kill Zombies: Similar to /K but for zombies rather than phantoms.
ZS | Identical to /Z except that it skips zombies that were launched via SUBMIT. Such jobs predictably become zombies if the submitting job exits, even though they may continue to function as intended. Thus you may not necessarily want to kill them along with other zombies.

History

2017 March, A-Shell 6.4.1546, SYSTAT.LIT 3.2(178): (UNIX) Reduce the excessive ITC error messages (one per job) to just one overall when the /W mode is unable to send ITC messages due to privilege issues. Allow clean exit with Q or ESC from paging mode.

2015 May, A-Shell 6.1.1408, SYSTAT.LIT 3.1B(171): Updated routine to recognize and preserve a new unique identifer field in the JOBTBL. The new version is backward compatible with earlier versions of A-Shell and has a "B" in the version number to help easily identify it. Also: Added new switch /CU.

2011 September, A-Shell 5.1.1235: SYSTAT 3.1(164): Enhancements to support the revised job table layout:

• Screen layout adjusted slightly to allow for ten character program name. (File layout with /L remains as before to preserve compatibility with programs that generate a listing and then parse it.)

• Add new switches /V and /X.

Note that this version of SYSTAT will continue to work with the older job table, but older versions of SYSTAT will not see the program name or A-Shell version for jobs running A-Shell 5.1.1235+

2011 June, A-Shell 5.1.1221: Remove the limit on the number of PPNs allowed per device.


Controlling Terminal

The C switch displays the controlling terminal's device identification rather than the user's name. Under UNIX, the user's name is set by the UNIX login, whereas the terminal device is determined by the user's connection to the host. Under Windows, the controlling terminal device name will be the network ID of the workstation (i.e. the machine name or, lacking that, the IP address.) In either case, a suffix one or more suffixes is usually added to distinguish between multiple connections originating from the same device. Examples:

ID | Meaning
pts/1:571 | UNIX: first pseudo-terminal (network connection), process ID = 571
ttyS1:1009 | UNIX: connection on serial port S1, process ID = 1009
JACKT42:01 | Windows: machine name=JACKT42, first A-Shell window on that machine


MAC Address

This switch (E) displays the client MAC address if known. (In practice, this will only be known when the client is ATE.) This could be useful for distinguishing between clients that share an IP address due to some kind of proxy server, and those that are really from the same PC.

Note that "MAC" stands for "Media Access Control," or physical hardware address, and is represented with a code like 00:0E:0C:50:B2:44

History

2006 January, Shell 949, SYSTAT.LIT 3.0(155): Switch added


Kill Phantoms

The K switch checks for and kills phantom jobs under UNIX. These can occur when the underlying UNIX process is somehow destroyed (such as by a kill –KILL operation performed by a superuser) without A-Shell being able to trap and recognize it. If such a process is found, SYSTAT will then remove it cleanly from the job table, and output both an asterisk in column seven of the display, as well as a more descriptive message on the following line.


Wide

Updated March 2017 (second paragraph added).

The W switch displays in wide (132) column mode (if terminal supports it). This allows the display of additional job status information, including the number of disk reads, writes, queue locking operations, commands (or programs) executed, BASIC instructions executed, keystrokes entered, and accumulated time logged in.

The job activity statistics are maintained in the JOBTBL.SYS file, making them available to be queried by utilities such as SYSTAT/W and JSTAT. Each job updates its own statistics in response to various triggers, the most universal of which is the Inter Job Communication clock, whose frequency is set by the IJCFREQ=<seconds> command in the miame.ini. Under UNIX systems, jobs can send a request message to other jobs using ITC.SBR, asking them to update their statistics immediately so as to be able to report the very latest. In order for such messages to be delivered, the jobs have to share the same effective user, or the sender has to be root. Failing that, the stats reported may be between 0-<IJC frequency> seconds old; you may also see an ITC error message displayed. Refer to Advanced Privilege Settings for more information.


Kill Zombies

This switch (/Z) is similar to /K but for "zombies" rather than "phantoms". A zombie is a job that is trying to exit but cannot because it lacks some kind of critical resource (like a terminal or its original parent). Unlike phantoms, zombies can be a significant drain on the CPU resources of the system. In most cases, zombies are related to some kind of messy telnet disconnection. (Activate TRACE=SIGHUP in the miame.ini or using SET.LIT and then examine the ashlog.log file for further information about such disconnects.)


TAIL

Update December 2012

TAIL {outfile=} <wildspec> {/switches}

The TAIL command is similar to the eponymous UNIX command and is used to display or copy to another file the last N lines of a specified file (or wildcard list of files).

Switches

Switch | Effect of Switch
/D | The delete switch causes TAIL to overwrite the existing outspec.
L:## | The lines switch causes TAIL to display or copy ## lines. The default is 20. As of A-Shell 1264, TAIL supports a UNIX-inspired variation of the /L:# switch, i.e. /L:+#, which causes the display/output to start at specified line #, rather than starting that many lines from the end. For example: .TAIL MYFILE.LST/L:+2 displays the entire file except for the first line. This can be useful for removing the first N lines from a file. For example, to remove the first line of a file, you could use the following command: .TAIL MYFILE.LST = MYFILE.LST/L:+2/D
/Q | The query switch causes TAIL to prompt for confirmation on each file.
/? | Writes switch listing and usage info to the screen.

See the notes on HEAD for examples.

History

2012 December, A-Shell 1264: Add support for the /L:+# variation on the "L" switch, as noted above.


TELNET

Updated May 2014; see History

TELNET <connection'name>

(Windows only) TELNET launches ATE (the A-Shell Terminal Emulator) to establish a session with the specified connection. The connection name must have been previously defined using ATECFG (which see).

You can terminate the session either from the remote host (i.e. by logging out) or by entering |d (vertical bar, D).

TELNET also supports an ATEAUTH.SBX hook, allowing you to preconfigure aspects of the connection properties before the dialog is displayed or the connection takes place. If ATEAUTH.SBX exists in the %MIAME%\DSK0\007006 directory, it will be called via:

xcall ATEAUTH, connection'name, status

Parameters

connection'name (String) [in]

is the name of the connection configuration.

status (Num) [out]

may be set to a non-zero value by the SBX to abort the connection. It is pre-cleared, so the SBX doesn't need to update it unless it wants to abort.

History

2014 May, A-Shell 6.1.1385, TELNET.LIT 2.1(142): Added the ATEAUTH.SBX hook.

2008 December, A-Shell 5.1.1131, TELNET.LIT 2.0(135): now uses AG_WINSETTINGS to reload the window settings after you select a connection profile, allowing the previously saved settings from that connection to be restored. Previously, the session saved settings were not being restored unless you used a desktop shortcut that explicitly specified the connection profile name (so it would bypass the dialog allowing you to select a connection.)


TELSER

TELSER <port#> <startup-command> {/switches}

(Windows only) TELSER allows you to turn your current A-Shell/Windows session into a single-client telnet server. That is, it proceeds to listen on the specified port for a standard telnet client connection, at which point, the remote telnet client takes over the session. This is a rather advanced (or perhaps obscure) capability, which is mainly of use for remote support (sort of like pcAnywhere) or for environments where your application was written to depend on the capabilities of a particular terminal emulator.

Switches

Switch | Effect of Switch
/S | Display waiting window on task bar (otherwise it becomes invisible).
/T:tdv | Forces the client connection to use the specified terminal driver. Otherwise it will negotiate the terminal type with the client terminal emulator.
/?, /H | Writes switch listing and usage info to the screen.


TYPE

TYPE <filespec> {switches}

TYPE displays the specified file on the screen (similar to the cat utility under UNIX).

TYPE <file>/P is functionally equivalent to PAGE TYPE <file>; see the notes on PAGE.

TYPE will display control characters in "caret notation" (i.e., using a printable character preceded by a ^). For example, nulls will display as ^@, escapes will display as ^[, etc.

Switches

Switch | Effect of Switch
/P | Page mode: stops after each screen page
/S | Slow mode: displays only ten lines per second
/?, /H | Writes switch listing and usage info to the screen.


U

U simply takes the command line which follows it and writes it to a command file called SYS:U.CMD, so that it can be easily recalled later just by typing U. For example:

.U dir/udate/cdate/adate *.bas[],*.run[*,0]

After executing the above command, you would then be able to enter just u then < Enter > to execute the command:

dir/udate/cdate/adate *.bas[],*.run[*,0]

Since recording one command is of limited value (given that you can use ^r to retrieve previously typed commands from the command history buffer), you can make unlimited copies of the U.LIT command under different names, which will work the same way but which will record their command lines in the correspondingly named command files.

Example

.COPY U2=SYS:U.LIT

.U2 DIR/UDATE/CDATE/ADATE

The above would create a command file called U2 which could be later executed to execute the DIR/UDATE/CDATE/ADATE command line.


VERIFY

VERIFY <dir-file-spec> {/F}

VERIFY reads a previously created directory listing and compares it to the actual files, reporting whether they agree or differ. The /f switch outputs the results to the file VERIFY.LST; otherwise it is displayed to the screen.This is a standard and very useful technique for verifying that a particular installation of files is up to date or not corrupted. (It seems amazing that there is no equivalent utility packaged with Windows or UNIX, although the RPM package manager of Linux does have a similar capability.

The specified directory file must have been created with the DIR.LIT /D/V/H switches. For example, when building a release of A-Shell, we execute the following commands:

.dir ashell.dir=dsk0:[]/d/v/h/k/sname

(The /k switch is needed to overwrite a previous copy of ashell.dir, and the /sname switch adds the optional nicety of listing the files sorted by name.)

The resulting directory listing looks something the example below, with each line containing the complete filespec of a single file, followed by the version number and the hash code:

DSK0:ABOUT.LIT[1,4] 1.0(103) 656-123-417-74

DSK0:APPEND.LIT[1,4] 2.1(111) 352-256-456-10

DSK0:ASTAT.LIT[1,4] 2.2(131) 121-772-424-00

DSK0:ATECFG.LIT[1,4] 1.0(100) 260-132-704-07

DSK0:C.LIT[1,4] 1.0(100) 167-604-517-71

DSK0:CHAT.LIT[1,4] 2.2(118) 632-367-207-57

DSK0:CLS.LIT[1,4] 1.0(100) 167-604-517-71

You may use VERIFY on this file to check if the standard files that come with A-Shell are still in sync with the release versions:

.VERIFY OPR:ASHELL.DIR

The output looks something like this (hopefully):

DSK0:ABOUT.LIT[1,4] VERIFIED

DSK0:APPEND.LIT[1,4] VERIFIED

DSK0:ASTAT.LIT[1,4] VERIFIED

DSK0:ATECFG.LIT[1,4] VERIFIED

DSK0:C.LIT[1,4] VERIFIED

DSK0:CHAT.LIT[1,4] VERIFIED

DSK0:CLS.LIT[1,4] VERIFIED

If the version or hash of the actual file does not match that recorded in the directory listing, it will report the discrepancy, for example:

DSK0:DIR.LIT[1,4] ?Version mismatch is - 1.5(125) MDL = 1.5(124)

This would indicate that the actual version of the file DIR.LIT is 1.5(125) while the release version as recorded in the directory listing is 1.5(124). (MDL stands for Master Directory Listing)


VERSYS

Updated September 2009; see History

VERSYS <wildspec>

The VERSYS displays version and resource information associated with an A-Shell LIT program that relates to the environment in which it was created. For example:

.VERSYS DIR

DIR.LIT -- A-Shell Version & System Information:

File Version: 1.5(125)

System Resource: ashell[74]

System Resource: cmdlin[24]: max devs = 300, max ppns = 512

The file version can also be gotten from the DIR/V command. But DIR/V cannot tell you the details about the ashell and cmdlin resource files, which were used to compile this copy of DIR. Periodically we update these resource files, which when used to re-generate the LIT commands, may create subtle differences which are not reflected in the version number.

VERSYS.LIT shows the program header flags for RUN and LIT files (which indicate how the program was compiled and whether it is compatible with AMOS). Note that it cannot distinguish whether /A was used when compiling (although it can distinguish /AV, which implies /A), and it cannot tell between /X:1, /X:2 and /D, all of which show as /X and are incompatible with AMOS). This version of VERSYS is backwards compatible with A-Shell 4.8.

History

2009 September, A-Shell 5.1.1159, VERSYS.LIT 3.0(107): was modified to support the run header bit indicating that the program uses dynamic variables. It identifies those programs compiled under 1159 as "5.1.1159 only", and newer ones as "5.1.1160+".


VUE

Updated May 2016; see History

VUE <file> {switches}

A-Shell contains an implementation of VUE with a similar look, feel, and functionality to AlphaVue version 3.0 under AMOS. Most basic commands and display mode features are implemented, although the emphasis is on general utility and not on being a perfect emulation of the AMOS version. Some extended features have been added to accommodate the needs of our more demanding users; see Special Commands.

Switch | Effect of Switch
/C | Enable command file input (including in display mode). Characters are input from the current command file and interpreted as if they were typed. Note that it is critical to know which mode the session will start in (display vs. command) since the interpretation of the commands would differ between the modes. See the START command in the ini.vue file for info on starting in a specified mode.
/R | Read-only mode. All functions work normally except you cannot save the file. You might want to consider EZTYP as an alternative to this.
/T | Trace steps involved in locating and processing the ini.vue file. Useful for debugging.
/W | Start in 132 column (wide) mode.
/Y | Automatically answer affirmatively to the question about whether to create a non-existent file.

The Help command is fully implemented. Enter Help while in command mode to get several successive screens showing all available VUE commands, which are also listed in tables in this documentation. Also available from the VUE command line are help screens for INFLD (e.g. >HELP INFLD), INMEMO, TCRT, and SPOOL. To create your own help screen for the subject "ABC," create a file called ABC.HLV in [7,1] and invoke it by entering "HELP ABC" on the VUE command line.

History

2016 May, A-Shell 6.3.1511, VUE edit 370: VUE now disables AutoMouse on the ATE client during the VUE session, then restores the prior settings on exit. Previously, this only occurred for A-Shell/Windows local mode. Note that if the ATE version is prior to 6.3.1511.0, AutoMouse will get disabled on entry into VUE, but not restored on exit.

2011 April, A-Shell build 1214, VUE edit 307: VUE now uses the AG_STATUSLINES feature to save the present status line configuration and then enable the bottom status line (which is used by VUE to display important information during editing). On exit, the previous status configuration is restored.

2010 November, A-Shell build 1196, VUE edit 305: A new variation of the >FORMAT command allows reformatting (wrapping) one line at a time to a specified width:

>FORMAT #

where # is the desired wrap width.

Unlike the standard FORMAT command, which reformats a paragraph using word wrap so that each line is as long as possible without exceeding the current width specified by the WIDTH command, FORMAT # operates on only the current line, wrapping it at exactly the specified width. This is mostly just a convenience for getting an overview of an extremely long line (as an alternative to successively using the >MARGIN # command, or RightArrow, to view one screen width at a time).

2010 November, A-Shell build 1196, VUE edit 304: The old line length limit of 2022 bytes has been greatly expanded. For existing files, the new limit is 1000 bytes longer than the longest of the first 100 lines in the file. For new files, the limit is 4K.

Also, the line concatenation function (^o) now beeps and otherwise does nothing when the concatenated line would exceed the current limit. (Previously it just truncated without warning.)

Subtopics

INI.VUE

Function Keys

Special Commands

Command Mode Commands

Display Mode Commands

Extended Display Mode Commands


INI.VUE

Updated October 2011("ASCII7" added)

As with the AMOS version, A-Shell’s VUE starts by searching for an INI.VUE file. The search path consists of the current PPN, the [p,0] directory, and DSK0:[7,0]. If found, the contents are processed in much the same way they would be if they were typed in VUE’s command mode. Launch VUE with the /T switch to display details about INI.VUE processing.

The set of INI.VUE commands is shown below. Most of the options work under A-Shell as they do under AMOS, with a few exceptions as noted.

Command | Value(s) | Default | Action
$ |  |  |
ASCII7 | Boolean |  | All characters with the 8th bit set are display as dimmed question mark. Even when not set, certain problem characters which appear to AM* and WY* terminals as commands are also handled this way.
AUTODELETE | Boolean or number |  | Toggles autodeletion of old auto update history notes (see UPDATE) or sets the maximum number to keep before deleting older ones.
AUTOSAVE | Number | Zero | If not zero, forces file to be automatically saved after every <number> changes. Each character counts as one change, some commands count as five changes.
BAKDIR |  |  | = <UNIX directory spec> Allows you to put the .BAK (backup) files into the specified directory, rather into the current directory. Applies to UNIX only, and generally only to the standalone version.
CHARINS | Boolean | False | Start in character insert mode, vs. overwrite mode; use ^q during editing to toggle; also see INSERT.
COLOFFSET | Number | 0 | Set number of first column (see COLUMN).
COLUMN | Boolean | False | Displays cursor column number during editing, either on bottom status line or upper left corner of screen.
CRNL | Boolean |  | Determines if file will be output with CRNL or just NL line terminators. Default=true for Windows or if OPTIONS=CRNL in miame.ini, otherwise false (normal UNIX case.)
CVTWARN | Boolean | True | Controls whether you get a warning that it will convert the CRLF line terminators (AMOS/Windows format) to native format terminators (LF for UNIX).
DEFAULT | Ext1, Ext2, ... Extn |  | Define up to 25 default extensions (to check if none specified on cmd line).
DRAW | Boolean | False | Change cursor advance direction.
ENCRYPT | Boolean | False | Causes any file written out by VUE to be encrypted using EFS. Ignored if EFS not enabled. See EFS in the index for more details.
GO | One to several lines |  | Specifies command(s) to execute on GO exit. ’%’ expands to file.ext; ‘@’ expands to ext.
INSERT | Boolean | False | Start in line insert mode; use ^\ during editing to toggle. Also see CHARINS.
LCKFILE | Boolean | False | Lock file while editing level 1.
LOCKSTRICT | Boolean | False | Lock file while editing level 2.
MODEM | Boolean | False | If true, command mode display output is minimized.
MOUSEPOS | Boolean | True | Disable mouse position. This normally defaults to ON (mouse wheel enabled), and is always re-enabled on exit. However, it defaults to OFF if OPTIONS=NOWHEEL is set in the miame.ini, and in any case, VUE always restores the original global setting on exit.
NARROW |  |  | Forces VUE to start in the normal 80 column mode.
PCNAV | Boolean | False | Forces the Home and End keys to go to beginning/end of line instead of file.
QUITWARN | Boolean | True | Enables warning when quitting after changing file.
SEARCHFOLD | Boolean | True | If true, search is not case sensitive.
SHORT |  |  | Forces VUE to start in the normal 24 row mode.
START | "End" or "Command" | blank | Specify starting position: end of file, command mode, or top of file (blank).
TAB | Number | 8 | Specify <number> spaces per TAB. If 8, use TAB character. If not 8, use spaces.
TALL | Number | 42 | Forces VUE to start in a display mode consisting of the specified number of rows. If equal sign and value are omitted, VUE begins with 42 rows.
UPDATE | Boolean or sc{,ec} |  | Automatically adds a note to the top of the file whenever the file is updated. Note includes date, time, edit time, and operator. If the sc,ec parameters are specified (in place of ON), they specify the characters to insert at the beginning and end of each update entry, e.g. UPDATE = !,*. (See AUTODELETE)
UPDSSL | Boolean | False | Force shifted status line to be the same as unshifted status line.
WIDE | Number | 132 | Forces VUE to start with width set to <number> columns. If equal sign and value are omitted, is treated like WIDE = 132.
WIDTH | Number |  | Determines column for wrap if WRAP=true. Default=screen width-2.
WRAP | Boolean | False | If true, cursor wraps after column specified by WIDTH.

Subtopics

AUTODELETE

AUTOSAVE

COLOFFSET

DRAW

GO

LCKFILE

LOCKSTRICT

MODEM

MOUSEPOS

PCNAV

QUITWARN

UPDSSL


AUTODELETE

The AUTODELETE and UPDATE commands (also available from Command Mode) are similar to the "d/VUE" commands of the same names. The both relate to an optional feature in which an automatic update notation is added to the top of the file whenever you finish out of it. The notation looks something like this:

!*! Updated on 02-Oct-98 at 06:33 PM by Jack; edit time: 0:45:23

Appropriate default comment markers ("!*!", "/*" and "*/", or ";*;") are determined on the basis of the file extension. If the file extension is not recognized, the feature is turned off. If you prefer to define your own comment markers, then use the UPDATE = <sc>{,<ec>} syntax (where <sc> is the "start comment" sequence and <ec> is the optional "end comment" sequence).

When the UPDATE feature is active, AUTODELETE may come in handy to automatically remove older entries (so you do not accumulate an infinite number of them or have to manually remove them). Setting it to ON results in just the last entry being preserved. If you specify a number instead, it will save that many entries before deleting older ones. See the notes on Special Commands for information about the related ^SE and ^_E commands.


AUTOSAVE

This causes the file to be automatically saved after the specified number of changes are made during an edit session. Single-character operations are counted each as one change; more complicated operations (e.g. replace, line and word delete, block operations, etc.) are arbitrarily counted as five changes. A reasonable number might be something in the vicinity of 1000. A value of zero disables the operation. (To aggravate your mates and waste a lot of resources, you can set the value to 1.) When triggered, the file is saved exactly as if a manual SAVE command had been issued. Note that even after several such SAVE operations, you can still recover your original file by using QUIT to exit and then making a copy of the .BAK file. (e.g. .COPY MYFILE.OLD=MYFILE.BAK).


COLOFFSET

The COLOFFSET command (both at the command level and in INI.VUE) adjusts the starting column number. By default, VUE calls the first column #0. If you want the first column to be numbered 1, then use >COLOFFSET 1 at the VUE prompt or add COLOFFSET = 1 to INI.VUE. This was added to A-Shell in Build 938 of 25 August 2005.


DRAW

This controls whether you can invoke a d/VUE-inspired feature of the same name in which the control commands ^S^H, ^S^J, ^S^K and ^S^L can be used to change the default cursor advance direction to left, down, up and right (default), respectively. This feature can be handy for laying out forms, but if accidentally invoked could wreak havoc on a blind typist, which is why it is not enabled by default.


GO

This command specifies the action or sequence of commands to execute when the file is exited with the G or GO command. The sequence starts with the first command following the equals sign, and continues until the $ is encountered. The special character % may be used to refer to the name of the file being edited (without any extension) while the @ character refers to the file’s extension.

Under the standalone implementation of VUE, the GO command must be limited to a single line (e.g. GO=compil %$)


LCKFILE

This command can be used to force VUE to create a separate <file>.lck file while <file> is being edited with write privileges. The purpose of this is to allow yet another way for external editors to detect that a file may be in the process of being modified by VUE.


LOCKSTRICT

As of VUE 3.2(284) of 5 December 2006, VUE reverts the locking under Windows back to the way it was prior to 3.2(280), meaning that although it prevents two Windows users from VUEing the same file in update mode, it allows read-only access to a file that is being VUE'd. Starting with 3.2(280), we made the locking more strict to better coordinate locking between cross-platform users, but this had the undesirable side effect of making it impossible to compile a program in one job if it was being VUE'd in another. To activate the stricter locking, you can now add the following to the INI.VUE:

LOCKSTRICT = TRUE

Otherwise, the more permissive style locking will be in force. Note that the permissive locking is not believed to be reliable in cross-platform environments. (In such cases, or whenever you have mixture of VUE and EDITOR users, you should probably use the LCKFILE=TRUE option.)


MODEM

This command (also available from Command Mode) toggles between the normal display mode and a mode in which the amount of output characters is minimized. This mainly affects the way Command Mode works. In standard mode (MODEM = OFF) the entire screen is cleared and repainted when switching between Display and Command Modes. When MODEM = ON, only the top one or two lines of the screen are used for Command Mode, leaving the rest of the Display Mode screen display intact. This abbreviated command mode is particularly appreciated by modem (or other slow baud rate), as well as people who tend to forget what they were doing when the screen is suddenly cleared.


MOUSEPOS

Reviewed July 2010

This command may be used at the command level or in ini.vue to disable caret position with the mouse. This may be useful on some laptops with very sensitive touch pads, which otherwise may cause the typing position to jump around unexpectedly (considered rather bad behavior in a program editor). Default is TRUE.

History

2010 July, A-Shell 5.1.1188: Function added to A-Shell


PCNAV

Added November 2011

The typical PC interpretation of the HOME/END keys is supported via the switch PCNAV = TRUE. When enabled, the HOME (^^) and END (^E) keys go to the start and end of the current line, rather than the start and end of the file, as they do in the traditional VUE command set. This difference has been a long-standing irritation to people accustomed to using typical PC editors.

To go to the start or end of the file when PCNAV=TRUE, the following new extended key commands have been implemented:

Key Combo | Standard VUX Translation | Function
CTRL+_ HOME | ^_^^ | start of file
CTRL+_ END | ^_^E | end of file

History

2011 November, A-Shell 6.0.1241: Function added to A-Shell


QUITWARN

This command controls whether you get a warning message and request to confirm when you attempt to quit out of an editing session after making changes to the file. (Of course if you still quit accidentally, you can always retrieve the .BAK backup file, but you must do that before you edit the file again.)


UPDSSL

This may be set to ON to force VUE to keep the shifted status line (if there is one) equal to the unshifted status line. (This prevents the line from "blinking" when you hit the Shift key.) This is only an issue in certain terminal emulation environments.


Function Keys

The MIAME environment contains full function key support, but these will only be usable within the editor if the appropriate function key translation files exist in account DSK0:[7,0]. These are files with the same name as defined for your terminal in the TRMDEF line of the MIAME configuration file, and extension .VUX. PCTDV.VUX and PCTDVG.VUX are supplied with A-Shell/Windows, either of which may be copied or renamed if your A-Shell/Windows terminal driver is going by a different name. Under A-Shell/UNIX, there are several available terminal drivers (am62a, am62c, am65, am75, wyse50, etc.), each of which needs its own VUX file.

The FIXTRN utility may be used to create, query or edit function key translation tables.

Under UNIX, the line terminator is a single \n, or LF character. Under AMOS and Windows, a CR-LF character pair is used. VUE is the only A-Shell module which under UNIX will automatically convert from the either format and will always save files in the current native format.


Special Commands

A-Shell/Vue is mainly intended for the convenience of those already familiar with some other version of VUE, (e.g. AlphaVue, XED, or d/VUE). Since the A-Shell/Vue supports mainly just the "core subset" of features that most people use, there did not seem to be much need to document it in detail here. However, there are a few editing features that are either non-standard extensions or just plain exotic, such that many people are not aware of them. Since it would be a shame to live without these features, they are hereby revealed.

Push/Pop: Although these are supported in virtually all other versions of VUE, A-Shell/Vue offers a useful enhancement on the idea by providing a stack of up to ten push/pop locations. The standard PUSH and POP commands access this stack in the usual LIFO fashion, but if you specify a numeric stack location (e.g. >PUSH 5) it uses that entry directly. Thus is becomes something more like a "bookmark". Note that whenever you directly access the push/pop stack this way, it resets the "stack pointer" to that location, which will affect the operation of any subsequent "unadorned" PUSH or POP command. Note also that current implemention of POP restores the original screen position, whereas earlier versions positioned the window so that the popped line was the fifth line.

Edit History commands: In addition to the automatic edit history feature (see UPDATE and AUTODELETE) above, there are also a couple of features which ease the maintenance of manual edit history notation. One is based on XED, and is invoked with ^_E (Ctrl+Shift+Underline+E), while the other is based on d/VUE and is invoked with ^SE (Ctrl+S followed by E). They both start by searching the file for the current edit number as defined by either a VEDIT = ### statement or a PROGRAM xxxxx, #.##(###) statement. (VEDIT is the symbol used by AMOS assembly language source files to define the edit number. If you want to use it with other program types, you will probably need to comment out the line to avoid compiler troubles.) Both commands search first for VEDIT, then for PROGRAM. If either is found with an acceptable syntax, it reads the three-digit edit number. Then, in the XED version, it increments the number within the VEDIT or PROGRAM statement and uses it to construct a two-line edit history entry, which inserts at the line where the cursor was, using the following format:

![124] October 02, 1998 05:59 PM Edited by jack

! _

(The idea is that you will then add in your own information describing the purpose of the edit.)

In the d/VUE version, the current edit number is not incremented, and the only thing inserted into the file at the position of the cursor is the current edit number in [###] notation. This form is particularly useful for commenting individual changes in a program and associating them with the program’s edit number.

Use the Command Mode HELP command to get a complete list of all the available commands.

History

2004 April, A-Shell 879: The following were added:

· Implement primitive 'bookmarks': these are similar to the multiple push/pop capability except that there is no concept of a hierarchy or stack. ^sm creates a bookmark for the current line. ^sn jumps to the next bookmark. ^sc clears the bookmark from the current line. The feature is handy when working on several sections in a large file and you want to jump between them.

· Implement the append macro feature (^_a).

· ^_f formats the current paragraph. (Same as >FORMAT).

· (UNIX, standalone mode) A new ini.vue feature, BAKDIR=<nativedirectory>, causes the .BAK file to be put in the specified directory, rather than in current directory. This can help avoid confusion in cases where .BAK files might not be recognized properly by other people or programs.

· (standalone) The display of the file path on the status line is now more intelligent, expanding it out with the current dir info if not specified on the command line, and trimming the first part of it if too long. This is particularly helpful when simultaneously editing multiple copies of a file in different directories.


Command Mode Commands

Updated October 2011("ASCII7" added)

Command | Action | Command | Action
ASCII7 | characters with the 8th bit set are displayed as a dimmed question mark. | App <file> | copy marked block to specified file
Blanks # | insert # blank lines | N)ext | search forward for text string
Center | center line | Pop {#} | restore curs. loc. {from slot #}
Clear | clear block marks | Push {#} | save cursor location {in slot #}
Copy | copy block | Q)uit | exit, no update
Delete | delete block | R)eplace | search and replace string
F)inish | update file & exit | Save | save current changes w/o exit
Format | format paragraph | S)earch | search for string (from start)
G)o | finish and compile | Short | switch to 24 row (normal) display
Global | global replace string | U)nyank # | remove # of lines (or write)
Help | display help file | U)nyank <file> | copy marked block to file
L)ine # | goto to line # | Y)ank # | bring # lines from current file
Move | move block | Y)ank <file> | bring in specified file


Display Mode Commands

Added May 2010

Command | Action | Command | Action
ctrl+a | Previous word | ctrl+p | Mark block
ctrl+b | Insert line | ctrl+q | Toggle insert char mode
ctrl+c | Cancel changes to line | ctrl+r | Previous page
ctrl+d | Delete character | ctrl+s | Extended command leadin #2
ctrl+e | End of file | ctrl+t | Next page
ctrl+f | Insert character | ctrl+u | Start of line
ctrl+g | Control char leadin | ctrl+v | Next word
ctrl+h | Same as LeftArrow | ctrl+x | Next match (search)
ctrl+i | Tab | ctrl+y | Clear to end of line
ctrl+j | Same as DownArrow | ctrl+z | Delete line
ctrl+k | Same as UpArrow | esc | Toggle display/command mode
ctrl+l | Same as RightArrow |  | Toggle line insert mode
ctrl+k | Same as Return | ctrl+^ | Top of file
ctrl+n | End of line |  | Extended command leadin #1


Extended Display Mode Commands

Added May 2010

Precede the commands in the following table with Ctrl+Underscore.

Command | Action
C | Copy marked block
D | Delete marked block
E | Increment VEDIT or PROGRAM value, insert dated note
K | Capture macro keystrokes
P | Playback macro keystrokes
Q | Toggle insert mode (same as Control-Q)
R | Undo last Control-Z or Control-Y
S | Center current line
U | Clear (unmark) marked block
V | Move marked block to cursor position
X | End macro keystroke capture

Precede the commands in the following table with Ctrl+S.

Command | Action
ctrl+a | Pop
ctrl+b | Copy current line to scrap buffer
ctrl+d | Copy marked block (to cursor location)
ctrl+g | Move marked block (to cursor location)
ctrl+o | Playback scrap buffer
ctrl+p | Unmark block
ctrl+s | Center display vertically around current row
ctrl+t | Push
ctrl+v | Toggle capitalization of current word
ctrl+z | Delete marked block
d | Output current date
e | Output edit number ([nnn] - from VEDIT or PROGRAM statement)
u | Output user name
t | Output current time


WEBRUN

Added October 2016

WEBRUN url {args}

WEBRUN.LIT is the front-end to RUN.LIT which enables A-Shell's WEBCACHE system. WEBRUN downloads the specified program from url into the webcache directory and then runs it, passing any args to it. If url contains spaces, it must be quoted, and if any args are specified, there must be at least one space between url and the args. If the url filename has no extension, .run is assumed. It also enables the webcache feature and all options—equivalent to SET WEBCACHE ENABLE,PROG,OPENI,LOOKUP—and sets the default URL based on URL given minus the filename.

Note that this command bypasses the normal search path: it will ignore a copy of the target program in the current [p,pn], [p,0] or [7,6] directories.

Examples

.WEBRUN http://www.mysite.com/app1/myprog

This command:

• enables all webcache options

• sets the repo to http://www.mysite.com/app1

• checks local webcache for myprog.run; if not there, tries to download it from the URL.

• tries to execute it from the webcache dir.

.WEBRUN "http://www.another site/app2/prog2.run" /demo

Similar to previous example except that it also passes the command line switch "/demo" to the target program prog2.run.

History

2016 October, A-Shell 6.3.1529 and 1531: WEBCACHE function added to A-Shell. The module includes a basic description, the SET.LIT options for WEBCACHE , new functions WEBRUN.LIT, MX_WEBCACHE.SBR and ? tab(-10, AG_WEBCACHE).


WSET

TRACKER is a Debug/MicroSabio product for AMOS which keeps track of all output sent to the screen. In doing so, it manages to implement the -1,148 (save screen area) and -1,149 (restore screen area) TCRT calls for those terminal types that do not perform these functions in firmware. Tracking is enabled and disabled with the WSET command.

A-Shell includes a functional equivalent of TRACKER that is permanently enabled, and so the -1,148 and -1,149 TCRT codes are always available for terminals on an A-Shell system. The WSET command is included mainly for compatibility and to prevent A-Shell rejecting it as an illegal command, though some of the operational switches are implemented. It always responds as the AMOS version does when tracking is already enabled:

%TRACKER flag already set

Allocated TRACKER buffer located - TRACKER 2.0C already installed

The TRACKER /?, /M, and /N operational switches have been implemented.


XY

Added February 2017

XY x y

XY x,y

The two syntaxes shown above, identical except for the space versus comma, both position the cursor on the screen at position x,y. This is the equivalent of the BASIC statement ? tab(x,y).

XY = m

The above syntax is the equivalent of the BASIC statement ? tab(-1,m).

XY -n m

The above syntax is equivalent to the BASIC statement ? tab(-n,m).

History

2017 February, A-Shell 6.3.1545: Add usage help display, add support for XY x,y syntax.


ZTXFER

Updated October 2016; see History

This is the A-Shell implementation of ZTERM's AMOS-to-PC file transfer routine. It can be used when transferring files to/from an A-Shell host and a connected PC that is running either ZTERM or ATE. Binary transfers are performed unless ASCII is specified with the /A switch. The following syntax can be displayed by entering ZTXFER with no arguments. See also the discussion on the ATE environment variable.

Note that ZTXFER requires an FTP server, so it won't work on most Windows servers unless an FTP server has been specifically set up.

To send from host to PC:

ZTXFER{/A} host-name PC-name

or

ZTXFER{/A} host-name

To send from PC to Host:

ZTXFER{/A} host-name=PC-name

or

ZTXFER{/A} =PC-name

Using with ATE

ZTXFER supports wildcards if the client is ATE. Examples:

Copy all files from current directory to PC:

.ZTXFER *.* C:\VM\MIAME\DSK0\111222

Copy all RUN files from PC to current directory

.ZTXFER = C:\VM\MIAME\DSK0\111222\*.RUN

Copy A*.B* from PC to BAS:

ZTXFER BAS: = C:\VM\MIAME\DSK0\111222\A*.B*

ZTXFER also supports an /ATE switch to force alternative transfer protocol—i.e. using ATE terminal channel. This was already automatic for transfers between an ATE client and a Windows server, but now can be forced in other situations. For example, under UNIX, FTP/SFTP transfers may be blocked by some security or other obstacle, while the ATE terminal channel would work.

Comments

See FTP Debugging for tips on debugging ZTXFER FTP-based transfers.

Also see ATEAPX and ATEGFK for alternate file transfer possibilities.

History

2016 October, A-Shell 6.3.1531: ZTXFER.LIT 1.4(108) implements /ATE switch.

2014 March, A-Shell 1381: ZTXFER.LIT 1.3(107) now supports filenames that exceed the 10.3 file.ext format. Also now treats server destination of "*" or "*.*" as equivalent to ""—i.e. uses file.ext from PC.

2013 December, A-Shell 1370: ZTXFER.LIT 1.3(106) now supports PC to Windows server file transfers using the AG_GETFILEDATA protocol introduced in 6.1.1357 and vastly improved in 6.1.1370.0. PC to server file transfers are now typically 1 MB/sec, without requiring any special servers or ports. For the UNIX server world, it also supports a new /2 switch to invoke the new FTP/SFTP protocol (implemented in ASHNET.DLL 1.6.139) if it is available.


ZXPWIN

ZXPWIN {<pcdir=>} {(ext)} <file>

(UNIX only) ZXPWIN is a handy utility for A-Shell/UNIX users running the ZTERM terminal emulator. It transfers the specified file to the PC and launches it using the Windows application appropriate for the file type (thus combining two or three steps which might otherwise be done manually.)

If the optional <pcdir=> argument is not specified, then the file is transferred to the default directory, whatever that may be. Otherwise, it is sent to the specified PC directory.

If you have ZTERM Build 143 or higher, you can use PC environment variables, such as TEMP, but enclosing them in % (e.g. ZXPWIN %TEMP%=ABC.TXT)

The optional (ext) argument may be used to force the source file extension to be changed during the transfer. This is particularly useful since the extension determines which Windows application will be launched. For example, if you wanted to transfer a BAS file to the PC and view it in Notepad, you would want to specify (TXT). Otherwise, the default application for BAS files would probably be the Visual Basic editor, which is probably not present, and even if so, is probably not what you wanted.

Since parentheses are significant to most UNIX shells, if you are going to specify a ZXPWIN command as part of an ashell command line (which will be processed by the shell), you will need to enclose the parentheses in quotes (e.g. ashell ZXPWIN %TEMP%="(TXT)"ABC.BAS)

The file argument can be in native or AMOS format.

Examples

ZXPWIN TEST.DOC

Transfer the file TEST.DOC to the PC in the default transfer directory and launch the Windows application which is associated with DOC files (probably Word or WordPad).

ZXPWIN %TEMP%=(CSV)TEST.PRT

Similar to the previous example, except that we will send the file to the PC directory defined by the PC’s TEMP environment variable, and we will rename the file TEST.PRT to TEST.CSV on the PC (so that we launch the spreadsheet program). This would be most appropriate if the TEST.PRT file was actually in comma-delimited format.

HOST ashell ZXPWIN %TEMP%="(DOC)"TEST.BAS

The above command launches a new instance of ashell, which in turn executes the same ZXPWIN operation as in the previous example. Note that we must enclose the (DOC) argument in quotes since the shell (which will process the ashell command line) would otherwise strip off the parentheses.

ZXPWIN C:\TEMP=(TXT)/vm/miame/miame.ini

This command transfers the miame.ini file (note the use of the native UNIX filespec) to the C:\TEMP directory on the PC, renaming it to miame.txt, and then launching the TXT file viewer (which is probably Notepad).


CMD/DO File Description

A-Shell supports CMD and DO files, more or less just like AMOS does, with a few extensions which are noted in the following topics entitled Global DO File Parameters and Special $ Variables. For readers who may not be completely familiar with CMD and DO files, a brief overview is presented here.

CMD and DO files are basically equivalent to BAT files under DOS or shell scripts under UNIX. They are simply text files, with .CMD or .DO extensions, containing LIT commands which are executed as if they were entered at the command prompt. The only difference between CMD and DO files is that CMD files do not support argument substitution and macro expansion, whereas DO files, like their DOS and UNIX counterparts, do support these function. Note that DO files do not have to take advantage of argument substitution, thus making CMD files somewhat redundant.

In addition to the normal commands that make sense at the command prompt, CMD and DO files also support some special commands and symbols which only make sense within CMD and DO files, and which allow them to be somewhat more program-like. Consider the following sample DO file (MAIN.DO), then see the following sections for more information.

Example: MAIN.DO

$D 100 MENU ; defaults for $0 and $1

:T ; trace (echo) commands

LOG DSK0:[150,$0]

:R ; don’t trace commands

IF LOOKUP ("MENU.DAT") = -1

:<Sorry, no MENU.DAT here

>

GOTO DONE

ENDIF

RUN $1

;DONE ; (this is a label)

IF "$NU" <> "admin" ; force all users except "admin"

HOST ; to exit A-Shell

ELSE

:<

Now returning to cm prompt...

>

ENDIF


Arguments $0 through $9

The formal arguments $0 through $9 within the DO file are replaced by the first through tenth space-delimited tokens on the command line that invokes the DO file, with the first token being the one following the name of the DO file itself on the command line. Thus, if the command line was:

DO MAIN 22 GL

then $0 will be replaced by "22" and $1 by "GL". This differs from DOS (which uses %0 through %9) and UNIX (which uses $0 through $9), both of which use the zero parameter to refer to the name of the batch or script file itself rather than the first user argument.

Since the space is used as a token delimiter, a special trick is needed to create a single argument that contains a space. Angle brackets may be used for this purpose to combine multiple tokens into a single argument. For example, in the following command line:

DO MAIN 22 <GL OPTION1 OPTION2>

"GL OPTION1 OPTION2" will be treated as $1.

In addition to the literal text arguments just described, DO also accepts file-based variable arguments using the syntax ++fspec, which get replaced at execution time by the contents of the first line of the file specified by fspec.

For example, if the first line of the file MYDATA:C.TXT contained "THIS DATA", then the DO file command line:

DO MAIN 22 ++MYDATA:C.TXT

would expand to:

DO MAIN A B <THIS DATA>

The <brackets> are employed when the line contains embedded spaces so that the entire line is treated as a single argument.

Note that "DO" in the above examples is optional and included only for clarity. It is only needed when the filespec argument following it (e.g. "MAIN") is ambiguous, i.e. when it might refer to SYS:MAIN.LIT or CMD:MAIN.CMD rather than CMD:MAIN.DO.


Default Arguments

To establish default values for arguments which are not specified on the command line, the DO file can begin with the special command $D followed by the defaults for $0, $1, etc. Arguments not specified in this list will have no default. You can also specifically skip over a default argument by inserting just a $ in the argument’s position on the $D line. For example:

$D DEF0 $ DEF2

This would set the default for $0 to "DEF0", the default for $1 to nothing, and the default for $2 to "DEF2".

The $D command, if present, must be on the first line of the DO file.


CMD/DO File Comments

The comment character is the semicolon ( ; ), unlike UNIX which uses the pound sign ( # ) and DOS which uses "REM". The comment character may appear anywhere in the command line, with the exception that labels, which have the same syntax as a one-word comment, must start in column one. (See the line ";DONE" in the sample file MAIN.DO above.)


Colon (:) Commands

Certain special commands begin with the colon, which must be in the first column.

Command

Meaning

:< .... >

outputs the text between the opening and closing angle brackets; may span multiple lines. This is the normal way to print operational messages on the screen from within CMD and DO files.

:t (trace)

causes all commands from that point forward to be traced—i.e., be displayed on the screen. This is very useful for debugging, but may be too verbose for normal use.

:r (respond)

causes just the output of commands to be displayed; the commands themselves do not display. This produces a somewhat cleaner looking result.

:s (silence)

silences all output. Unfortunately, this is the default, if neither :t or :r are supplied first.

:x (exit)

causes the CMD or DO file to exit. This is equivalent to the EXIT command.

:k (keyboard)

stops and waits for keyboard input. The input is then processed by whatever process is currently in effect (i.e. either a program or the command line processor itself). For example:

SET CTRLC
:<This command erases all files!!!
Hit ENTER to proceed or ^C to abort: >
:K ; ^C will abort here; ENTER will just proceed
ERASE *.*

:p (partial)

may be used in conjunction with :k to append the keyboard input to a partial command line. For example:

:R
:<Enter name of file to display: >
:P
EZTYP
:K


IF / ELSE / ENDIF Statements

These statements are similar to their BASIC Plus counterparts. The following functions and expressions are supported by IF, with the same syntax as for BASIC:

ABS | ACS | ASC | ASN | ATN | CHR
COS | DATN | DEVICE | EXP | FACT | FIX
FIX | INSTR | INT | LCS | LEFT | LEN
LEN | LOG | LOG10 | LOOKUP | MID | RIGHT
RND | SGN | SIN | SPACE | SQR | STR
TAN | TIME | UCS | VAL |  |

The most useful of the above functions, LOOKUP, works slightly differently than the BASIC Plus equivalent. Instead of returning the file size, it always returns –1 if the file exists, else 0. See the example in the MAIN.DO file above.

The following operators are supported:

Relational Operators |  | Mathematical Operators
Symbol | Meaning | Symbol | Meaning
= | Equal | + | Addition
<> | Not equal | - | Subtraction
# | Not equal | * | Multiplication
> | Greater than | / | Division
>= | Greater than or equal | ^ | Raise to power
< | Less than | ** | Raise to power
<= | Less than or equal |  |


GOTO and EXIT Statements

GOTO is similar to the BASIC GOTO statement, except that it can only jump forward in the CMD or DO file. The syntax of a label consists of a semicolon followed by the label name. (See the label ";DONE" in the sample MAIN.DO file above.)

EXIT causes an immediate exit to the A-Shell command prompt, even if you are currently nested multiple levels deep in a CMD or DO file.


LOOKUP Statement

The LOOKUP statement is a variation of the LOOKUP function (see IF statements above). The syntax is:

LOOKUP <fspec>/Optional message if not found

If the specified file is not found, the optional message (following the /, which is mandatory) is displayed and execution continues with the following line. Otherwise, the following line is skipped. Typically this is used with GOTO to create a conditional branch, as in the following:

LOOKUP $0/$0 does not exist!

GOTO DONE ; (EXIT might also be appropriate here)

VUE $0

;DONE


Special $ Variables

The DO file processor supports various special information variables (or built-in macros) which take the form $x or $xx (where x is alphabetic). The supported variables are listed here; those that are A-Shell extensions are noted at the end of the list.

Variable | Value
$: | Original device (e.g. "DSK0:")
$P | Original ppn (e.g. "7,6")
$$ | Real dollar sign
$TM | Time of day in 24 hour HH:MM format (e.g. "13:27")
$TD | Current date in YYMMDD format
$TW | Current day of week as a number (0=Mon, 1=Tue,...)
$NJ | Current job name (e.g. "TSKAAA")
$NT | Current terminal name
$ND | Current terminal driver name
$NS | Current OS (e.g. "AIX")
$SV | Current OS version
$UX | Current radix (e.g. "8" or "16")
$LG | Current language (e.g. "ENGLISH")
$LY | Yes character (e.g. "Y")
$LN | No character (e.g. "N")
$NU | Current login name (e.g. "root")

The following are supported only under A-Shell:

Variable | Value
$HF | Current host full path (e.g. "/vm/miame/dsk0/001004")
$HD | Current host disk (e.g. "dsk0")
$HP | Current host ppn (e.g. "001004")
$HM | MIAME env var definition (e.g. "/vm/miame")

These special information variables are typically used in IF statements or in output messages.

It is necessary to quote these variables when comparing then in IF statements. For example:

IF "$NU" = "jack" ; (correct)

IF $NU = jack ; (incorrect)


Global DO File Parameters

This is another A-Shell extension that functions something like the special $ information variables, except that their values may be set from within a BASIC program. Once set, they retain their value for the duration of that session (unless specifically over-written by a BASIC program). There are ten possible global DO file parameters, and they may be invoked on a command line using %0 through %9. The DO file processor substitutes these formal parameters for their values before passing them on to the DO file. For example, consider the command line:

XYZ ONE %3 TWO %0

Assuming that global parameter %3 had previously been set to "gee whiz" and global parameter %0 had previously be set to "humdinger", then this command would be processed as if it were:

XYZ ONE <gee whiz> TWO humdinger

"ONE" would be substituted for $0, "gee whiz" for $1, "TWO" for $2, and "humdinger" for $3.

There is no particular limit on the size of these variables, although there is limit of 200 characters on the length of any expanded command line.

To set global parameters, use XCALL MIAMEX as follows:

xcall MIAMEX, 79, status, g0, g1, g2, g3, g4, g5, g6, g7, g8, g9

The values of the variables g0 through g9 (all of them optional, all of them string or unformatted) will be plugged into the corresponding global parameters. Any of the parameters g0 through g9 that are not specified will cause the corresponding variable to be cleared. Status (F,6) will be returned as 0 for success, else error.

See the sample program MIAMEX.BAS in [7,376] for an example of setting and even retrieving these global DO parameters. (Although they were designed to be used with DO files, there is nothing stopping you from using them for holding and passing parameters amongst your own programs.)


K0 - K9 Commands

The CMD/DO file processor supports a variation of the :K command to input keyboard responses into variables which can tested in IF statements and used as DO file parameters. The following sample CMD file provides an example:

:R

:<Enter desired ppn: >

:K0

:S

:<Enter password: >

:K9

IF "$KBD9" = "SECRET"

DOLOG $KBD0

The special command :K0 is like :K, in that it waits for a line of input, but instead of passing the input to the current program, it simply stores it as $KBD0. The same concept applies to :K1 thru :K2 ($KBD1 thru $KBD9). The special $KBDn variables may be tested in an IF statement or passed as a command line argument to a DO file.

Note that when using $KBDn in an IF statement, it must be quoted (as in the example above.) However, when using it as a DO file command argument, it should not be quoted. (In the example above, the DO file DOLOG.DO will see the $KBD0 on its command line and convert it to whatever had been entered to the "Enter desired ppn" prompt.)

$KBDn variables cannot be used in any other context, even within a CMD/DO file. Unlike other special $xx variables which can appear in DO files, which are expanded by DO.LIT when it loads the DO file, the $KBD variables cannot be expanded until after the input operation takes place, and thus it is left to individual commands (currently just IF and DO) to interpret them.

This feature requires LIT files of at least the versions shown below:

IF.LIT 1.0(106)

DO.LIT 2.1(121)

MDO.LIT 2.1(121)

History

December 2004, A-Shell 4.9.909: Function added to A-Shell


Input Case

DO.LIT 2.1(121) supports the ability to specify the upper or lower case version of a $KBDn variable on the command line, which can be handy when building case-sensitive UNIX commands from input strings. The following example makes this clear:

;TEST.CMD

:<Input something >

:K1

DOTEST $KBD1 LCS($KBD1) UCS($KBD1)

;DOTEST.DO

:<Command line: $0 $1 $2

>

Assuming that the user had input "SiLly" in response to the prompt in TEST.CMD, the output of the DOTEST command would be:

Command line: SiLly silly SILLY

Note that these two functions , LCS($KBDn) and UCS($KBDn), are the only ones supported on the DO command line.

History

December 2004, A-Shell 4.9.909: Function added to A-Shell. Requires DO.LIT 2.1(121) or later.


Concatenate Parameters

DO.LIT 2.1(122) supports a mechanism for concatenating parameters on the command line (before they are bound to the $0 thru $9 formal parameters). The syntax consists of prepending $+ to the start of a parameter that you want to combine with the prior parameter. For example, consider a generic DOTHIS.DO file consisting of the following command:

HOST $0 $1 $2 $3 $4 $5 $6 $7 $8 $9

If you executed it with:

.DOTHIS play ina $+gada $+davida real loud

The resulting host command would be:

play inagadadavida real loud

Note that "real" and "loud", which started out in positions $4 and $5, got shifted by the concatenation down to $2 and $3.

You can also use the $+ operator in the middle of an argument to avoid the argument renumbering problem just described, i.e.:

.DOTHIS play ina$+gada$+davida real loud

In this case, it is more clear that there are only 4 arguments ($0 thru $3) being passed to DOTHIS. This technique is mainly of interest in conjunction with $KBDn variables and the UCS/LCS functions where you may want to concatenate some folded keyboard input with a hardcoded value, and doing do so directly would interfere with the interpretation of the $KBDn and LCS() / UCS() syntax. For example:

:R

:<Enter command: >

:K0

:<Enter ini file: >

:K1

DOTHIS /vm/miame/bin/ $+LCS($KBD0) -i /vm/miame/ $+LCS($KBD1)

Assuming the user input "ASHELL" to the first prompt and "MIAME.INI" to the second, then the DOTHIS.DO file would execute:

HOST /vm/miame/bin/ashell -i /vm/miame/miame.ini

Without the concatenation, the user would have had to enter the entire paths or do without the LCS() function.

History

January 2005, A-Shell 4.9.910: Function added to A-Shell.


Introduction to A-Shell BASIC

This is a new (2014) section in the documentation, and the authors are working on it "in place." The hope is that over time this section will present a complete reference for A-Shell BASIC. In the meantime, please be advised that the material is not complete, though it is acurate and up to date as far as it goes.

A-Shell BASIC, referred to in this documentation as "ASB," is the primary programming language used for developing applications in A-Shell. A super set of AlphaBASIC, which was introduced in 1976 by Alpha Microsystems, it shares many features with other BASIC-like languages, while adding a number of features particularly useful for developing vertical market applications in Windows and Linux environments. These include a mechanism for precise memory layout of structures (MAP statements), various integrated, cross-platform, file access methods, and the ability to call external routines written in C or ASB. It is partially compiled to p-code, which is then executed within the A-Shell runtime environment.

Because most of the users of ASB are already familiar with AlphaBASIC, documentation for the common features has not been a priority. But over time, as new programmers come into contact with ASB who are not familiar with its predecessor, the need for a more complete reference to the language has become more pressing. The following sections attempt to provide the necessary details so that both newcomers and long-time A-Shell developers can get the most out of ASB. Please feel free to post any questions you have about the language or the documentation to our forum.

Subtopics

Naming Programs

Sample Program I

Sample Program II

Program Structure


Naming Programs

Like all file names, A-Shell BASIC programs consist of two parts: a base name or stem, and an extension.

The base name of your program can be up to ten characters.

The extension of your source code files can be anything you want, such as .PPP for Perry's Perilous Programs; A-Shell doesn't care. When you compile a program using A-Shell's COMPIL command, it will work on any filename you specify, such as CONFUSED2.PPP, 222MUCH.ABC, 1234567890.BAS, etc.

By convention, source files are named with extensions of either BAS or BP, with the latter being recommended.

BAS is the historical reference, and has been used as the extension for BASIC programs of all types and on all platforms for many years. In the case of A-Shell, BAS always has the benefit of being automatically recognized by COMPIL. To compile a program with the extension BAS, you do not need to specify the extension; the compiler knows to look for a BAS file with the stem name you have specified. So "COMPIL ABC" will result in the file ABC.BAS being compiled, whereas the same command results in the program source file ABC.XYZ being ignored.

The other common extension is BP, and there are a few good reasons to use it instead of BAS.

• Many email programs will not allow the sending of BAS files, recognizing them as programs. So if you ever need to send program source files via email, you should not use BAS extensions.

• BAS is also the default source file name for Microsoft's Visual Basic programs. Since it's easier for you to rename your programs than to get Microsoft to rename its programs, not using BAS is a good idea just to avoid confusion in the Windows world.

• BP can serve as an indicator that this program (a) was written in and for the A-Shell environment rather than the older and mostly deprecated Alpha Micro environment, and (b) contains A-Shell extensions which require the /X:2 switch when compiling.

• When compiling using the /X:2 switch (use A-Shell extensions), the compiler will find and act on BP files as well as BAS files without you having to specify the extension. If you have a file ABC.BP, for example, the statement COMPIL ABC/X:2 will result in ABC.BP being compiled.


Sample Program I

Here is a program called "Hello" whose purpose is to print the phrase "Hello World":

PRINT "Hello World"

END

The program must exist first as a text file, typically with a BAS or BP extension, created in any text editor such as VUE or APN. Assuming the file is assigned the name HELLO.BAS, it can be compiled from the A-Shell dot prompt as follows:

.COMPIL HELLO.BAS

The compiler responds:

Phase 1 - Parse source and generate object code

Phase 2 - Adjust object file and process errors

Memory usage:

Total work space - 18600 bytes

Label symbol tree - 16 bytes

Variable symbol tree - 20 bytes

Declaration tree - 16 bytes

Structure symbol tree - 16 bytes

Data statement pool - 0 bytes

Variable indexing area - 0 bytes

Compiler work stack - 16 bytes

Excess available memory - 1911620 bytes

End of compilation

The compiled program will typically have a .RUN extension, can be seen and manipulated with file commands such as DIR, SIZE, COPY, etc., and can be executed with the RUN command. For example:

.SIZE HELLO.RUN

Size is 56 bytes

.

.RUN HELLO

Hello World

.


Sample Program II

Here is a slightly larger sample program that provides a better sense of the typical ASB program structure and illustrates a few features of the language, including:

• program statement assigns a version to the RUN module (visible with DIR/V)

• ! (exclamanation point) starts a comment up thru the end of the line

• ? (question mark) is an alias for PRINT, outputting text to the screen or a stream file

• ; (semi-colon) at end of print statement stifles CRLF output.

• ++include reads in source code from external file, like #include in C

• map statements define variables in a fixed layout

• dimx allocates a dynamic array

program factor,1.0(100) ! factorization example

!-------------------------------------------------------

!Edit History

![100] April 05, 2014 12:51 PM Edited by jack

! created as example

!-------------------------------------------------------

on error goto TRAP

++include ashinc:types.def ! extended data type defs (e.g. BOOLEAN)

define TRUE = -1

define FALSE = 0

map1 params

map2 nf,i,4 ! the number to factor

map2 nx,i,4 ! working value

map2 i,i,4 ! loop counter

map2 count,i,2 ! # of factors found

dimx factors(1),i,4, auto_extend ! array of factors

input "Enter number to factor: ",nf

nx = nf

i = 2 ! first factor to consider

do while i <= nx

if fn'is'factor(i,nx) then

nx /= i

count += 1

factors(count) = i

? "found ";i;" target now ";nx

repeat

endif

i += 1

loop

? "Factors of ";nf;": ";

if count then

for i = 1 to count

if i > 1 ? ",";

? factors(i);

next i

elseif nf = 1 then

? 1 ! only factor of 1 is 1

else

? "none found"

endif

?

end

TRAP:

? "Error #";err(0)

end

!---------------------------------------------------------

! return TRUE if candidate is a factor of target

!---------------------------------------------------------

function fn'is'factor(candidate as i4, target as i4) as BOOLEAN

if (target mod candidate) = 0 then

fn'is'factor = TRUE

endif

endfunction


Program Structure

The structure of an ASB program is rather loose, consisting of one or more lines satisfying the following syntax:

{line #}{label:}{statement} {! comment}

Line numbers can be used as labels, for the purpose of GOTO or GOSUB calls, but are typically deprecated in modern usage. Labels can also be used as the target of a GOTO or GOSUB statement, but in modern usage are mostly limited to aesthetic or code clarification purposes.

Statements are terminated implicitly by the end of the source text line (LF or CRLF), or explicitly by the comment character "!". To extend a logical statement over multiple source text lines, use the "&" character to indication continuation, e.g.

statement'syntax$ = lineno$ &

+ label$ & ! optional comment may follow "&"

+ statement$ ! another comment

As shown in the example above, comments may follow the & continuation character without interfering with the continuation. However, be careful about ending a comment with the & continuation character, since it effectively extends the comment to the next line. For example, in the following, the "print b" statement will become part of the comment at the end of the previous line, due it it ending in & ...

print a ! don't end a comment with &

print b ! else following line (this one) will be part of comment

Multiple statements may also be combined on a single source text line by separating them with a colon, e.g.

if SWAP then &

V1 = V1+V2 : V2 = V1-V2 : V1 = V1-V2 ! 3 statements on a line

Note that while the above form is typical in older code, the style—if without endif, continuation, multiple statements per line—like the archaic verb "LET", is generally deprecated now in favor of the more readable:

if SWAP then

V1 = V1 + V2

V2 = V1 - V2

V1 = V1 - V2

endif

Statements fall into the following categories:

• Declaration of Variables

• Control Structures

• Compiler Directives

• User-Defined Functions and Procedures

• Assignment Statements

• I/O Statements

• Miscellaneous Statements


Edit, Compile, Run

Programming largely consists of a repeating iteration of Editing, Compiling, and Running programs (with occasional breaks for snacks). The following overview and tips should help you get started on the A-Shell version of this timeless activity.

Editors

Although you can use any text or program editor you like, most A-Shell programmers use one or both of the following:

VUE is an old-school full-screen plain text editor, vaguely similar to the famous UNIX editor vi. Its strong points are that it is:

• built in to A-Shell, which means it can be launched from the dot prompt or via an XCALL within a program

• available as a standalone executable in the UNIX environment

• platform independent

• very fast and responsive if you know the keyboard commands

A-Shell Programmer's Notepad ("APN") is a modern Windows program editor / IDE, similar to other IDEs such as Visual Studio. Its strong points are:

• follows typical Windows conventions so will be instantly familiar to most programmers experienced with other Windows editors

• multi-file, multi-window

• understands ASB syntax and A-Shell directory structure so is able to recognize/locate/open ++include files

• integrated compiler - click on errors in the output window to jump directly to the file/line for editing

• can be extended with scripts written in Python

• supports workspaces and projects

• syntax highlighting, call tips, code completion, undo/redo

Compilers

The ASB compiler processes your source code (typically with a .BAS or .BP extension), creating a run module (typically with a RUN, LIT, or SBX extension, depending on the intended use). There is really only one compiler, but it is packaged in a number of forms to match your working style:

From the A-Shell dot prompt:

• COMPIL.LIT, e.g. .COMPIL MYPROG/M/I/X:2

• COMPLP.LIT - variation (supporting the AMOS BASICPlus) that assumes .BP file extension, /X:1

• OCMPIL.LIT - variation (supporting the original AMOS BASIC 1.3) that assumes /13

From within a program (if you want to create your own compilation wrapper), you can invoke the compiler using:

XCALL MIAMEX, MX_COMPIL, filename, switches, ...

From the Windows shell prompt:

>COMPIL.EXE <switches> <program>

(The COMPIL.EXE package is also used by APN for integrated ASB compilation.)

From the UNIX shell prompt:

$ compil <switches> <program>

Execution

There are three forms of compiled programs, identified by the file extension. All have essentially the same internal format but are executed in different ways:

• RUN modules (e.g. PROG.RUN) are executed using the RUN command from a dot prompt or from within a CMD or DO file, e.g. (RUN PROG)

• SBX modules (e.g. PROG.SBX) act as subroutines and are called from within another program using the XCALL statement. (See Subroutines vs BASIC programs for details on differences between SBX and RUN modules).

• LIT modules (e.g. PROG.LIT) act as system commands and are executed from the dot prompt, or from within a CMD or DO file, by specifying just the module name.

A running program can also launch another LIT or RUN program, either as a subroutine using XCALL AMOS, or by chaining to it using the CHAIN statement.

Examples

RUN modules from the dot prompt or a CMD or DO file:

.RUN MYPROG

.RUN APP:MYPROG/ARG1/ARG2=5

.RUN DSK2:MYPROG.RUN[100,2]

LIT modules from the dot prompt or a CMD or DO file (see Command Search Path) :

.LOG SYS: ; LOG.LIT

.DIR/W ; DIR.LIT

.TEST.LIT ; TEST.LIT

From within a program:

XCALL FOOBAR,1,2 ! call FOOBAR.SBX; search [p,pn], [p,0], DSK0:[7,6]

CHAIN "INVOIC" ! link to INVOIC.RUN; search [p,pn], [p,0], DSK0:[7,6]

XCALL AMOS,"RUN TEST" ! execute TEST.RUN as subroutine


BASIC Keywords

Notes on Source:

• Says where this particular keyword was first used.

• Abbreviations used: "AB" = AlphaBASIC; "Plus" = AlphaBASIC Plus.

Notes on Switches:

• The column entry shows the compiler switch(es) required to enable this feature.

• When more than one switch is listed, "or" is implied—i.e., just one of the switches is required.

Keyword | Source | Switches | Description
ABS | AB |  | See Numeric Functions.
.ACCOUNT | A-Shell | X:2 | See Dot Variables.
ACS | AB |  | See Trigonometric Functions.
ALLOCATE | AB |  | Allocate a random file.
AMOS | Plus | X:1 | Execute AMOS commands as subroutines.
AND | AB |  | See Expressions.
.ARGCNT | A-Shell | X:2 | See Dot Variables.
.ARGSIZ | A-Shell | X:2 | Returns the size of the specified argument passed to the current SBX, function, or procedure.
.ARGTYP | A-Shell | X:2 | Returns the type of the specified argument passed to the current SBX, function, or procedure.
ASC | AB |  | See String Functions.
ASN | AB |  | See Trigonometric Functions.
ATN | AB |  | See Trigonometric Functions.
AUTO_EXTERN | A-Shell | X:2 | Enables or disables the visibility of variables defined globally.
AUTOCAP | d/BASIC |  | See String Functions.
BYTE | AB |  | BYTE(X) reads memory-mapped ports.
CALL | AB |  | Unstructured subroutine call.
CASE | Plus | X:1, RC | Label option within SWITCH.
CHAIN | AB |  | Provides the ability to pass command line arguments. CHAIN <string expr> is supported in all compiler modes, including the ability to include command line arguments in the <string expr>, which must start with a program name, optionally followed by an arbitrary string of arguments, e.g. CHAIN "progxx /hard and /fast". Use CMDLIN or LSTLIN.SBR to retrieve the parameters in the target program.
CHR$ | AB |  | See String Functions.
.CLEAR | A-Shell | X:2 | Removes all the elements of the array without destroying the array itself.
CLOSE | AB |  | Close file.
CMDLIN | Plus | X:1 | Retrieve command line.
COS | AB |  | See Trigonometric Functions.
DATA | AB |  | List of data elements with program.
DATE | AB |  | See System Functions.
.DATE | A-Shell | X:2 | See Dot Variables.
DEBUG | A-Shell | X:2 | See TRACE and DEBUG Statements.
DEFAULT | Plus | X:1, RC | Default label option within SWITCH
DEFINE | Plus | X:1, RC | Define a symbolic constant.
DEFSTRUCT | A-Shell | X:2 | See Defined Structures.
DEFTYPE | A-Shell | X:2 | Defines an alias for a data type.
.DEVICE | A-Shell | X:2 | See Dot Variables.
DIM | AB |  | Dimension an array at runtime. Deprecated; use DIMX.
DIMX | A-Shell | X:2 | Enhanced dynamic array allocation. See Dynamic Arrays (DIMX).
DIVIDE’BY’0 | Plus | X:1 | Treat division by zero as zero rather than error. See NO'DIVIDE'BY'0.
DO | Plus | X:1, RC | Repeat loop while (or until) a condition is (or becomes) true. See DO / WHILE / UNTIL.
Dot Variables | A-Shell | X:2 | Read-only system variables.
DPRINT | A-Shell | X:2 | Like PRINT but creates a static text control using the current default GUI (proportional) font and with the sunken attribute. Intended for displaying data fields.
ECHO | Plus | X:1 | Set terminal echo mode; same as XCALL ECHO.
EDIT$ | Plus | X:1 | See String Functions.
++ELIF... |  |  | See Conditional Compilation.
ELSE | AB |  | Final alternative clause within IF statement, which see.
ELSEIF | A-Shell | X:2, RC | Intermediate alternative clauses within IF statement. See ELSEIF Clauses .
END | AB |  | Terminate execution of program.
ENDFUNCTION | A-Shell | X:2 | Marks end of a function.
ENDIF |  |  | See IF … ENDIF.
ENDPROCEDURE | A-Shell | X:2 | Marks end of a procedure.
ENDSTRUCT | A-Shell | X:2 | See Defined Structures.
ENDSWITCH | Plus | X:1, RC | End of SWITCH statement.
EOF | AB |  | See File-Related Functions.
EQV | AB |  | See Expressions.
ERF | AB |  | See File-Related Functions.
ERR | AB |  | See System Functions.
ERRMSG | Plus | X:1 | See System Functions. Returns the text of the error message associated with the specified error number from the SYS:ERRMSG.xxx file.
ERROR | A-Shell | X:2 | Force error within compilation. Also see MESSAGE.
$EXIT | A-Shell | X:2 | Special exit label within function / procedure.
EXIT | Plus | X:1 | Exit from inner-most loop or block (DO, FOR, SWITCH).
EXITFUNCTION | A-Shell | X:2 | Exit the current function.
EXITPROCEDURE | A-Shell | X:2 | Exit the current procedure.
EXP | AB |  | See Numeric Functions.
.EXPERIENCE | A-Shell | X:2 | See Dot Variables.
.EXTENT | A-Shell |  | Returns the "extent" of the subscript number.
++EXTERN | A-Shell | X:2 | Exposes individual global variables.
FACT | AB |  | See Numeric Functions.
.FALSE | A-Shell | X:2 | See Dot Variables.
FILEBASE | AB |  | Set numeric offset for first file record.
FILL$ | Plus | X:1 | Copies the given expression, partially or multiple times, up to the specified length. See String Functions.
FIX | AB |  | See Numeric Functions.
FOR | A-Shell | X:2 | See FOR … NEXT.
 | AB |
FOREACH | A-Shell | X:2 |
FUNCTION | A-Shell | X:2 | Begin definition of function.
GETKEY() | Plus | X:1 | Input a character.
GOSUB | AB |  | Same as CALL.
GOTO | AB |  | Jump to specified line number or label.
IF | AB |  | Traditional form of IF statement.
 | Plus | X:1, RC | Block-structured form of traditional IF statement; see IF … ENDIF.
++IF |  |  | See Conditional Compilation.
++INCLUDE | AB |  | Include specified file at compile time; see INCLUDE.
 | A-Shell | X:2
INPUT |  |  | Input field(s) from keyboard or file; see INPUT.
INSTR | AB |  | Substring search; see INSTR().
 | A-Shell | X:2 | Extended version substring search; INSTR().
.INSTRR | A-Shell | X:2 | Searches a string for a pattern, like INSTR(), but in reverse.
INT | AB |  | See Numeric Functions.
IO | AB |  | IO(X) pseudo reads from memory-mapped I/O port.
.ISNULL | A-Shell | X:2 | Tests for the NULL condition. See Ordered Maps > Special ORDMAP Functions.
.JOBNAME | A-Shell | X:2 | See Dot Variables.
.KEY | A-Shell | X:2 | Returns the key associated with the element currently indexed by the iterator. See Ordered Maps > Special ORDMAP Functions.
KILL | AB |  | Delete a file.
.LAST_LABEL | A-Shell | X:2 | See Dot Variables.
.LAST_ROUTINE | A-Shell | X:2 | See Dot Variables.
LCS$ | AB |  | See String Functions.
LEFT$ | AB |  | See String Functions.
LEN | AB |  | See String Functions.
LET | AB |  | Assignment statement.
.LINENO | A-Shell | X:2 | See LINENO, PAGENO.
LOG | AB |  | See Numeric Functions.
LOG10 | AB |  | See Numeric Functions.
LOOKUP | AB |  | Return size of file in blocks. See File-Related Functions.
LOOKUP ("fspec") |  |  | Function version of LOOKUP statement.
LOOP | Plus | X:1, RC | See DO / WHILE / UNTIL.
MAP Statement | AB |  | Variable declaration.
MAX | AB |  | See Expressions.
MEM | AB |  | See System Functions.
MESSAGE | A-Shell | X:2 | Output message during compilation. Also see ERROR.
MID$ | AB |  | See String Functions.
MIN | AB |  | See Expressions.
.MONTH | A-Shell | X:2 | See Dot Variables.
.NEST_LEVEL | A-Shell | X:2 | See Dot Variables.
.NEXT | A-Shell | X:2 | See Ordered Maps > Special ORDMAP Functions.
NO’DIVIDE’BY’0 | Plus | X:1 | Force divide by zero to generate error 10 (default). See DIVIDE'BY'0.
NOECHO | Plus | X:1 | Set terminal noecho mode. Same as XCALL NOECHO.
NOT | AB |  | See Expressions.
.NULL | A-Shell | X:2 | See Ordered Maps > Special ORDMAP Functions.
ODTIM | Plus | X:1 | See String Functions.
.OFFSET | A-Shell | X:2 | Returns the offset to the specified member variable within the specified structure.
.OFFSIZ$ | A-Shell | X:2 | Returns the combination of the specified structure member's offset and size.
ON - GOSUB | AB |  | Call one of list of subroutines, based on value.
ON - GOTO | AB |  | Goto one of list of labels, based on value.
ON ERROR GOTO |  |  | Specify error handling routine.
OPEN | AB |  | Open file.
OPEN for APPEND | Plus | X:1 | Enhancement to OPEN #CH, FSPEC, APPEND.
OR | AB |  | See Expressions.
PAD | AB |  | See String Functions.
PAD | A-Shell | X:2 | Pad a string with spaces (function).
.PAGENO | A-Shell | X:2 | See LINENO, PAGENO.
.PGMNAME | A-Shell | X:2 | See Dot Variables.
.PGMVERSION | A-Shell | X:2 | See Dot Variables.
PRAGMAs | Plus | X:1 | Compiler directives.
PRINT | AB |  | Output variables and expressions to screen or file.
PROCEDURE | A-Shell | X:2 | Start definition of a procedure.
PROGRAM | AB |  | Program header declaration.
RANDOMIZE | AB |  | Initialize random number generators—both RND(x) and RND2()—using a randomly selected seed.
READ | AB |  | Read from file.
READL | AB |  | Read record and lock. See file access statements
READ'ONLY |  |  | File open mode modifier. See OPEN.
REDIMX | A-Shell | X:2 | Re-dimensions an array originally created with Dynamic Arrays (DIMX).
REPEAT | Plus | X:1, RC | Jump to top of loop structure to begin next iteration.
RESTORE | AB |  | Reset DATA access pointer to beginning.
RESUME | AB |  | Resume to line after last error.
RESUME WITH ERROR | A-Shell | X:2 | Special version of resume used with functions and procedures.
RETURN | AB |  | Return from unstructured subroutine (see GOSUB, CALL).
 | A-Shell | X:2 | Return value from XFUNC.
RIGHT$ | AB |  | See String Functions.
RND | AB |  | See Numeric Functions.
RND2 | A-Shell | X:2 | See Numeric Functions.
RTRIM | AB |  | See String Functions.
SCALE | AB |  | Declare scaled arithmetic.
SGN | AB |  | See Numeric Functions.
SIGNIFICANCE | AB |  | Set output/format significance of floating point values.
SIN | AB |  | See Trigonometric Functions.
.SIZEOF | A-Shell | X:2 | Returns size of previously mapped variable.
SLEEP | Plus | X:1 | Sleep for specified seconds. Same as XCALL SLEEP
SPACE | AB |  | See String Functions.
SQR | AB |  | See Numeric Functions.
SRND2 | A-Shell | X:2 | See Numeric Functions.
STEP | AB |  | Set loop counter increment. See FOR … NEXT.
STOP | AB |  | Program stop, wait for CR to continue.
STR$ | AB |  | See String Functions.
STRIP | AB |  | See String Functions.
STRIP | Plus | X:1 | Returns var with all trailing spaces removed. Also STRIP$(var).
STRSIZ | AB |  | Sets the default value for all unmapped string variables.
SWITCH | Plus | X:1, RC | Conditional execution based on value of an expression.
TAB(X,Y,Z) | A-Shell | X:2 | Extension of tab(x,y) with z indicating attributes to assign to the subsequent text.
TAN | AB |  | See Trigonometric Functions.
.TERMINAL | A-Shell | X:2 | See Dot Variables.
THEN | AB |  | Separates IF condition from statement. See IF.
TIME | AB |  | See System Functions.
TO | AB |  | See FOR … NEXT.
TPRINT | A-Shell | X:2 |
TRACE | A-Shell | X:2 | See TRACE and DEBUG Statements.
.TRUE | A-Shell | X:2 | See Dot Variables.
UCS$ | AB |  | See String Functions.
UNLOKR | AB |  | Release lock on file or record.
UNTIL | Plus | X:1, RC | Repeat loop while (or until) a condition is (or becomes) true. See DO / WHILE / UNTIL.
.USERNAME | A-Shell | X:2 | See Dot Variables.
USING | AB |  | See Expressions.
VAL | AB |  | See Numeric Functions.
VXCALL | A-Shell | X:2 | Varition of XCALL that uses a string expression for the subroutine name, rather than a literal.
WEND | d/BASIC | /D | Same as ENDIF.
WHEN | d/BASIC | /D | Same as IF.
WHILE | Plus | X:1, RC | Repeat loop while (or until) a condition is (or becomes) true. See DO / WHILE / UNTIL.
WORD | AB |  | WORD(X) reads memory-mapped ports.
WRITE | AB |  | Write to random file.
WRITECD | A-Shell | X:2 | Output comma delimited values.
WRITEL | AB | X:1 | Write record not previously locked.
WRITELN | Plus | X:1 | Same as WRITEL but leave record locked.
WRITEN | Plus | X:1 | Same as WRITEL but leave record locked.
WRITETD | A-Shell | X:2 | Deprecated; see WRITECD for important note.
XCALL | AB |  | Call external subroutine.
XFUNC | A-Shell | X:2 | Call an external (SBX) function.
XGETARG(S) | A-Shell | X:2 | Retrieve XCALL parameters. See XGETARG, XGETARGS, XPUTARG.
XOR | AB |  | See Expressions.
XPUTARG | A-Shell | X:2 | Return XCALL parameters. See XGETARG, XGETARGS, XPUTARG.
XREAD, XWRITE | A-Shell | X:2 | Allow record access via explicit record numbers.
.YYMMDD | A-Shell | X:2 | See Dot Variables.


File Access Methods

Caution: documentation in progress. These are some rough notes which we will use to finish this section.

It could contain forward links to the various I/O Statements section as well as to commands such as ISMxxx, CREATE, etc.

ISAM - we should reread the INTRODUCTION chapter in the AMOS ISAM UserGuide. But our version should also compare the A-Shell implementation to both the AMOS version and also to ISAMA

For RANDOM and SEQUENTIAL files, Chapter 16 of the AMOS Basic manual might provide some background. Again, our version should highlight things relevant to A-Shell, such as:

• Unlike in AMOS, there is really no such thing as a "contiguous" (aka RANDOM) file in Windows or UNIX. The underlying files are sequentially allocated; the random access feature is supported in a layer above that, partly in the OS, partly in A-Shell.

• Because of that, A-Shell in some cases has to guess whether a file was intended to be RANDOM or not, based on whether it is a multiple of 512 bytes as all AMOS RANDOM files would be. This mainly becomes an issue when using the LOOKUP statement, which returns a negative # for "random" files, and a positive # for "sequential" files. Some applications might actually depend on that and thus misbehave, for example, if a sequential file just happened to be a multiple of 512 bytes. In general, modern programs should not rely on the arbitrary unit of 512-byte blocks and instead should use the size in bytes (see SIZE.LIT, SIZE.SBR). Also see the system options ABSLOOKUP and EXTFIO.

• For SEQUENTIAL files (aka "streams"), A-Shell (unlike AMOS) supports the ability to seek directly to a byte position; see MX_FILEPOS.

• For RANDOM files, A-Shell (unlike AMOS) supports the ability to expand them incrementally in place, whether manually (see MX_EXPFIL), or automatically (see system options NOAUTOX, and MX_SETOPTIONS/MX_GETOPTIONS GOP_AUTOX_RAN)

• For ISAM 1.x I think we already have a section somewhere discussing the enhancements in A-Shell relative to AMOS.


Variables

ASB variables may be defined via any of the methods listed below.

Subtopics

Data Types

Arrays

Implicit Variable Declarations

System Variables

Dot Variables


Data Types

Updated July 2016; see History

ASB supports the data types shown in the tables below.

Scalar Types

Type | Source | Code | Description
Floating Point | BASIC Plus | F,4 | 32 bit IEEE float
 | AlphaBASIC | F,6 | 48 bit AMOS float
 | BASIC Plus | F,8 | 64 bit IEEE float
Binary, little endian | AlphaBASIC | B,1 | 8 bit unsigned
 |  | B,2 | 16 bit unsigned
 |  | B,3 | 24 bit unsigned
 |  | B,4 | 32 bit unsigned
 |  | B,5 | 40 bit signed (two's complement)
 | A-Shell | B,6 | 48 bit unsigned
 |  | I,6 | 48 bit signed (two's complement)
Integer, AMOS format | BASIC Plus | I,1 | 8 bit signed (two’s complement)
 |  | I,2 | 16 bit signed (two’s complement, little-endian)
 |  | I,4 | 32 bit signed (two’s complement, 2301 order)
String | AlphaBASIC | S,# | fixed length string of # bytes [AB]
 | A-Shell | S,0 | variable length string (dynamically sized, always with trailing null)
Unformatted (raw bytes) | AlphaBASIC | X,# | fixed length raw bytes
 |  | (none) | May be declared implicitly by leaving type,size specifier in MAP statement blank and defining lower-level MAP statements.

Compound Types

Type | Source | Example | See Note #
Multi-level MAPs | AlphaBASIC | MAP1 CUST MAP2 NAME,S,30 MAP2 CUSNO,B,4 MAP2 TOTSALES,F,6 | 1, 2
Defined Structures | A-Shell | DEFSTRUCT ST_CUST ! define structure layout MAP2 NAME,S,30 MAP2 CUSNO,B,4 MAP2 TOTSALES,F,6 ENDSTRUCT ... MAP1 CUSREC,ST_CUST ! define instance of structure ... READ #CH, CUSREC ! read/write entire struct at once ? CUSREC.NAME ! use structvar.member notation for fields |

Table Notes:

1 Also known as "records"

2 Any MAPn level with higher-numbered levels defined within it

History

2016 June, A-Shell 6.3.1516, compiler edit 763: Added variable types B6 and I6. See following topic.

Subtopics

B6 and I6 Variables


B6 and I6 Variables

Added July 2016

B,6 and I,6 variables—little endian 48 bit unsigned and signed integers, respectively—were added to A-ShellBASIC in 6.3.1516.0 and compiler edit 763. They are not supported under AMOS. These extend the range of integers that can be stored properly as integers to nearly as great as the range of integers that can be represented precisely by the F,8 data type. The range of B,5 variables is just slightly less than the corresponding range of integers that can be stored precisely in the F,6 data type.

B,6 and I,6 variables can be used like any other numeric variables in statements, expressions, parameter passing, etc., with the following reminders:

• Beware that A-Shell run-time versions prior to 6.3.1516 will not properly deal with programs containing B,6 or I,6 variables. Earlier versions of the compiler will report the problem clearly (?Illegal size for variable type), but the run-time will simply misinterpret any values held in those variables, probably treating the value as 0.

• As with any conversion between types, when converting from B,6 or I,6 to other types, the receiving variable must be large enough to hold the converted value, else the result will be truncated, wrapped, or otherwise corrupted without any error condition being raised. For B,6 and I,6, the only other data types that can hold the entire range of possible values are F,8 and S,15+. In the case of string, you must set SIGNIFICANCE 15 to avoid exponential notation for large values.

• As with any conversion from a floating point value to an integer variable, the fractional part will be truncated, and if the source value exceeds the range of the destination variable type, the result will be wrapped around, without any error being raised.

• See ASHINC:MINMAX.DEF for definitions of the minimum and maximum integer values that can be held by each integer type.

• Bitwise operators (AND, OR, NOT, XOR, EQV) now operate out to 48 bits. Previouslyi it was 40 bits.

• Built-in XCALLs, while having access to the new extended range of integers, have not necessarily been updated to take advantage of them. Unless the the documentation explicitly indicates otherwise, you should assume a 32 bit limit for general numeric parameters.

• Decimal, octal, and hex constants and symbol definitions now support values extending to 48 bit integer or F8 floating point; previously it was 40 bit integer or F6 floating point. You may optionally append an "L" to the end of such literal constants to make explicit that you want them to be encoded into the RUN file using the larger format, but this isn't necessary as the compiler will do it automatically as needed.

• The Fn'Dec2Hex$() and Fn'Hex2Dec() functions in the SOSLIB have been updated to support the new 48 bit integers. Make sure to download and recompile with the updated fndec2hex.bsi and/or fnhex2dec.bsi modules if you plan to use these functions with values larger than 32 bit values.


Arrays

The scalar and compound data types may be combined into arrays as follows:

Description

Example

Fixed arrays of scalars

MAP1 SALES(25),F,6

Fixed compound arrays

MAP1 CUST(10)
MAP2 NAME,S,30
MAP2 CUSNO,B,4
MAP2 SALES(25),F,6
...
for I = 1 to 10
? NAME(I),CUSTNO(I)
for J = 1 to 25
? SALES(I,J)
next J
next I

Dynamic arrays of scalars

ECOUNT = 1000
ESIZE = 50
dimx MESSAGES(ECOUNT),S,ESIZE ! dynamically allocate array
...
redimx MESSAGES(2000) ! increase extent of array
...
redimx MESSAGES(0) ! discard array

Dynamic arrays of structures

dimx CUSRECS(50),ST_CUST ! array of 50 ST_CUST structures
...

? CUSRECS(25).CUSNO ! element.member notation

Dynamic auto-extended arrays; may be either scalar or structure types

dimx CUSRECS(0),ST_CUST,auto_extend
...
CUSRECS(N).NAME = "MicroSabio" ! auto-expand to N elements
! if needed (on assignment)

Ordered Maps

dimx $CAPITALS, ordmap(varstr;varstr) ! map of strings
...
$CAPITALS("FRANCE") = "PARIS"

dimx $STATES, ordmap(varstr;varx) ! map of blobs/structures
...

Map1 STATE,ST_STATE

...

$STATES(“California”) = STATE ! load structure into map

...

STATE = $STATES(“California”) ! retrieve structure from map by key

? STATE.POPULATE, STATE.CAPITAL, … ! access members

Multi Level List

dimx $JSONDOC, mlist(varstr) ! JSON doc stored as multi-level list
...
$JSONDOC(.pushback) = name$ + ":" + value$ ! push name:value pair on end of list

Subtopics

Ordered Maps

Multi-level List MLIST

Dynamic Arrays (DIMX)

Dynamically-Sized Variables


Ordered Maps

An ordered map is a type of associative array that maps keys to values, maintaining an order to the keys. The concept is similar to an indexed file with a single variable length key and a single variable length data structure (either a simple string or a multi-member structure), with no duplicate keys allowed.

History

2015 July, A-Shell 6.1.1414, compiler edit 742: Add ordmap(varstr;varx) and .ISNULL(var)

2013 June, A-Shell 6.1.1354, compiler edit 638: .CLEAR function added

2012 June, A-Shell 6.1.1300: Ordered maps introduced; (varstr;varstr) only

Subtopics

Declaration / Creation

Destruction

Clearing

Element assignment and removal

Accessing elements

Iterators

Parameter passing

Special ORDMAP Functions

Passing Ordered Maps

Ordered Multi-Map ORDMAPM


Declaration / Creation

Updated July 2015

DIMX $aryname, ordmap (varstr; varstr)

DIMX $aryname, ordmap (varstr; varx)

where

$aryname is the name of the ordered map. It follows the normal rules of ASB variable names except that it must begin with a $. Also note that although $aryname is an array, and you will need to use parentheses to reference it later, e.g. $aryname("some key") = "some value", the parentheses are omitted from the declaration.

ordmap(<keytype>;<datatype>) specifies the type of the key and the type of the data element. As of edit 1300, the only <keytype> supported was varstr (variable length string) and the only <datatype> supported was also varstr. Edit 1414 added support for <datatype> varx (variable length binary object, i.e. blob, structure, X type variable). Support for other types may be added in the future.

The ordered map grows dynamically as items are added to it and the keys and data are all variable length, so there is no need to declare any sizes.


Destruction

REDIMX $aryname()

This is similar to the syntax for destroying other dynamic arrays, except here the parentheses must be empty.

As with other dynamic arrays, the ordered map arrays will be automatically destroyed when they go out of scope—i.e. when the function or procedure in which it was declared returns, or for global and module scope arrays, when the program ends or SBX returns. Explicit destruction is not typically necessary.


Clearing

Added June 2013

.CLEAR $aryname()

The "dot-clear" statement removes all the elements of the array, without destroying the array itself.

Dimx $capitals,ordmap(varstr;varstr) ! declare array

Print .extent($capitals()) ! initial extent is 0

$capitals(“california”) = “sacramento” ! add an element

$capitals(“nevada”) = “carson city” ! add another element

Print .extent($capitals()) ! extent is now 2

.clear $capitals() ! clear all elements

Print .extent($capitals()) ! extent is now 0

Note: Requires compiler version 638 or higher to compile this statement, and A-Shell version 6.1.1354 or higher to execute it, otherwise you'll get an illegal syntax code error.


Element assignment and removal

Updated July 2015

Once declared, elements (i.e. key,value pairs) can be added to the ordered map with standard array assignment syntax, except that the array subscript (the key) is a string rather than a numeric value:

$capitals("california") = "sacramento" ! for ordmap(varstr;varstr)

$products(“SKU12345”) = PROD’REC ! for ordmap(varstr;varx)

If the specified key exists already, the operation will replace the value of the existing element. To delete an element, a special value .NULL ("dot null") is assigned:

$capitals("california") = .NULL

Note: Assigning an empty string (“”) to the value of a key does not delete the item!


Accessing elements

Updated July 2015

To refer to the value of an element (i.e. use it as a source string in an expression), just use the standard array syntax with the key as the subscript:

print "The capital of "; state$; " is "; $capitals(state$)

For ordered maps with unformatted elements (i.e. blob, binary, structures, X type), you can use the subscripted array reference in the same was as you would the MAP1 (X type) variable or structure,e.g.

Map1 Prod’rec

Map2 sku$,s,10

Map2 price,f,6

Map2 qtyonh,I,4

…

Dimx $products,ordmap(varstr;varx)

…

Prod’rec = $products(“AB-1234”) ! retrieve map element into structure

? “Product “;sku$;” price is “;price;” qtyonh is”;qtyonh

…

Write #ch, $products(“AB-1234”) ! or use element directly as structure

The traditional mapped “structure” in the above example could also be replaced with a formal structure (defined via DEFSTRUCT), in which case after retrieving the element into the structure, you would use the structure.member syntax to access the members.

Note that when accessing ordered map elements by key, just as with indexed file access, you really need to test for the possibility that the element does not exist. A non-existent element will return the special value .NULL, which for varstr type elements can be tested for with a standard string comparison, i.e.

City$ = $capitals(state$)

If City$ = .NULL then

? “capital of “;state$;” is undefined”

Else

? “capital of “;state$;” is “;City$

Endif

For varstr elements, attempting to print the .NULL value will display “<null>”, which may be acceptable in some casual situations.

For varx elements, the .NULL value cannot be tested with a simple string comparison, and attempting to reference members of a null structure will result in undefined values. Instead, you must use the function .ISNULL(var) to test it, so the above example should really be coded as:

Prod’rec = $products(“AB-1234”) ! retrieve map element into structure

If .ISNULL(Prod’rec) then

? “No such product defined”

else

? “Product “;sku$;” price is “;price;” qtyonh is”;qtyonh

endif

The .ISNULL(var) test works equally well for both varstr and varx elements, so the best strategy is to use it in all cases, thus avoiding difficult-to-diagnose bugs resulting from accidentally attempting to compare a varx value to the .NULL string value. So the varstr example above would be better coded as:

City$ = $capitals(state$)

If .ISNULL(City$) then ! (better than testing if City$ = .NULL)


Iterators

Updated July 2015

To access elements from a collection without knowing the specific keys, an "iterator" is used. Iterators are special variables which act as pointers into a collection, allowing you to sequence through the elements of the collection. But because BASIC doesn’t normally allow pointers, our iterator behaves as if it were a temporary read-only variable containing the value of the current element.

To iterate through a collection, a "foreach" loop is used:

foreach $$i in $aryname({startkey}) ! fwd iterator

print $$i ! print the element value

print .key($$i) ! print the element key

next $$i

foreach’reverse $$j in $aryname() ! reverse iterator

print $$j ! print the element value

print .key($$j) ! print the element key

next $$j

Note: the above example assumes varstr elements; for varx elements, you wouldn’t try to print the $$i or $$j iterator values directly; instead you would assign them to a structure and then access the members, i.e.

Prodstruct = $$i ! copy iterator value to structure

print Prodstruct.field1 ! print a field of the element value

print .key($$j) ! print the element key

Although this is similar to a standard for/next loop, there are some noteworthy differences:

• First, unlike the standard for/next loop where the loop variable must have been previously defined, in the foreach loop, the iterator variable ($$i in the example above) is created on the fly and exists just for the duration of the loop. Iterator variables must all start with $$ (which should not be used for any other variable type.) Since it is destroyed at the end of the loop, the same iterator variable name can be used in other foreach loops.

• Unlike the standard for/next loop, here there is no explicit ending value. The starting value is the first item in the collection (unless the optional startkey parameter is specified.) The concept is similar to sequencing through an indexed file until the end, except in this case if the specified startkey doesn’t exist, the entire sequence will be empty and the loop will be skipped.) To omit the startkey, use empty parens, e.g. $aryname().

• The order of the sequence will be according to the key. You can specify a reverse sequence by using the keyword foreach’reverse instead of foreach. (Note however that for the reverse iterator, the startkey option is ignored; it always starts at the highest key in the collection.)

• Adding, deleting or modifying keys while iterating will render the iterator unpredictable, and thus should be strictly avoided. You may, however, modify the values of elements as you iterate, keeping in mind that the iterator itself is read-only (so you would have to use the .key() function as in the examples above; further description below).

Within the loop, the iterator variable (e.g. $$i) will contain the value of the current element in the sequence. This is a read-only variable! And its type matches the element type of the ordered map (string for varstr, unformatted for varx).You can also access the key of the current element using the special "dot function" .key(<iterator>) as in the example foreach loop above. To modify an element's value, use the .key(<iterator>) function as the key. For example, the loop below would prefix each element with "Beautiful " and fold the capital name to upper case (assuming varstr elements):

foreach $$i in $capitals() ! fwd iterator

$capitals(.key($$i)) = "Beautiful " + ucs($$i)

next $$i

Here's another example which copies the ordered map $cap1 to a new ordered map $cap2:

dimx $cap1, ordmap(varstr;varstr)

...

! make copy of $cap1 into $cap2

dimx $cap2, ordmap(varstr;varstr)

foreach $$i in $cap1()

$cap2(.key($$i) = $$i

next $$i


Parameter passing

Ordered map element values, being variable length strings or unformatted blobs, may be passed as parameters to functions, procedures and subroutines just as you would an ordinary S,0 (dynamic string) or X,0 (dynamic unformatted blob) variable or expression. But note that since references to ordered map elements are essentially expressions, they're effectively read-only and thus attempts to update them via XPUTARG will have no effect. For example:

call FoldUpper($capitals("california")) ! passes "sacramento"

print $capitals("california") ! (unchanged by procedure)

...

Procedure FoldUpper(name$ as s0)

name$ = ucs(name$)

xputarg 1,name$ ! this doesn’t change calling param

! (if it was an ordered map value)

EndProcedure

There is currently no way to pass an entire ordered map to a function or procedure as a parameter. However, as of A-Shell 6.1.1398 / compiler edit 734, there are a few XCALL subroutines which are capable of receiving and/or returning an entire ordered map, for which case the syntax is the map name with an empty set of parentheses, e.g. $ary(). When applicable, this feature is documented with the subroutine itself; for example, see the CGIUTL opcode CGIOP_GETPARARY.


Special ORDMAP Functions

Modified July 2015; see history

Function | Description
.EXTENT($a()) | Returns the extent of the ordered map $a, which is equivalent to the overall number of elements in the map. If the map has not yet been initialized (i.e. the compiler has seen the dimx statement but it was not yet executed at runtime, or it was executed and then freed with redimx), .EXTENT will return -1. Note that .extent functions effectively the same way on other array types.
.ISNULL(var) | Tests for the .NULL condition. See example below.
.KEY($$i) | Returns the key associated with the element currently indexed by the iterator.
.NEXT($$i) | Advances the iterator, returning the associated key or .null if no more. This is mainly used internally by the next $$i statement, which is translated to something like: if .next($$i) # .null <repeat loop>
.NULL | Does not operate on anything but may be used to test for a null element as opposed to one whose value is "". It may also be used in an assignment to delete an element, i.e. assigning an element the value .null deletes that element.

.ISNULL() Example

A$ = $MYMAP(KEY$)

IF A$ = .NULL THEN ? "No such key in map" ! old method (now deprecated)

IF .ISNULL(A$) THEN ? "No such key in map" ! new method

Both methods of checking for .NULL are equivalent, provided that the map contains only string elements and A$ is a string. The .ISNULL(var) method is preferred, as it works for non-string elements also. See examples notes under Accessing elements for more details.

History

2015 July, A-Shell 6.1.1413: Add ISNULL.


Passing Ordered Maps

Added October 2016

Beginning with A-Shell 6.3.1520, ordered maps may be passed by reference to functions and procedures. Conceptually and syntatically this is very similar to passing other kinds of DIMX arrays by reference. On the calling side, you specify the array in the parameter list using an empty set of parentheses, for example...

dimx $mymap, ordmap(varstr;varstr)

...

call MyProc($mymap()) ! pass $mymap() array by reference

On the receiving side you declare the local name for the array in the parameter definition also with an empty set of parentheses, with the "as clause" specifying the ordered map type, e.g.

Procedure MyProc($m() as ordmap(varstr;varstr))

$m("foo") = "bar" ! updating m$() updates $mymap() directly

As with other DIMX array passing, the compiler does not attempt to determine if the source and destination array formats are compatible, but the runtime system enforces a degree of sanity, in this case, complaining if you attempt to pass an ordmap(varstr;varx) to an ordmap(varstr;varstr) or vice versa.

History

2016 August, A-Shell 6.3.1520: Add capability to A-Shell.


Ordered Multi-Map ORDMAPM

Added October 2016

Collection type ORDMAPM is equivalent to ORDMAP except it supports multiple keys of the same value. This structure is typically known as an ordered multi-map but we went with ORDMAPM instead ORDMMAP or ORDMULMAP or ORDMULTIMAP because it seemed easier to read and type.

As with the standard ORDMAP, ORDMAPM collections declared with the DIMX statement and support the same two variations (one with a variable length string value, the other with a variable length binary/blob value; both with a variable length string key):

DIMX $mymap, ORDMAPM(varstr;varstr)

dimx $mymap, ordmapm(varstr;varx)

Note that are no promises regarding the internal order of elements with the same key, nor of which of those elements will be the one returned when retrieving an element by key. However, iterating through the entire array will return all of the elements. In addition, iterating from a specific key will also return all of the matches for that key.

For example:

dimx $MM, ORDMAPM(varstr;varstr)

...

foreach $$i in $MM(key$) ! will iterate through all of the elements

.... ! matching $key, followed by all of the

next $$i ! elements after $key

History

2016 August, A-Shell 6.3.1520: Add capability to A-Shell.


Multi-level List MLIST

Added October 2016

DIMX $M, MLIST(VARSTR)

DIMX $M, MLIST(VARX)

MLIST (short for "Multi-level LIST") is a bidirectional linked list, with the added feature that each element may contain a link to a child MLIST. Aside from the links, each element may contain a variable length string (varstr) or blob (varx). The MLIST is effectively a kind of tree structure, useful for representing a variety of real-world data such as disk directories and XML/JSON documents, where the ability to maintain a particular order and to efficiently insert, delete, and splice elements or branches at arbitrary points is required.

Unlike the ORDMAP and ORDMAPM collections, there is no direct access to an element by its key; there is only direct access to the first and last elements in the list, with the ability to iterate forwards, backwards, or down from there. The order of the elements in the list is preserved based on the order in which you build it.

The syntax for assigning and accessing elements is similar to that for ORDMAP, modeled on single-dimension array syntax. But instead of using string keys for the array index as in ORDMAP, the MLIST uses various special dot-variables which act as pseudo-keys. In addition, there are several new dot-statements and dot-functions and dot-members to perform operations particular to MLISTs that cannot be easily represented with existing statements and functions. These are summarized below, following by descriptions and syntax for the various operations..

Dot-Variable | Description
.FRONT | first element, e.g. ? $M(.FRONT)
.BACK | last element, e.g. ? M(.BACK)
.PUSHFRONT | add new element to front, e.g. $M(.PUSHFRONT) = X
.PUSHBACK | add new element to end, e.g. $M(.PUSHBACK) = X
Dot-Statement | Description
.POPFRONT | remove first element from list, e.g. .POPFRONT $M()
.POPBACK | remove last element from list, e.g. .POPBACK $M()
.SPLICE | splice elements from one list to other
.SORT | sort elements in list by value, e.g. .SORT $M() .SORT $kids() sorts according to the collating sequence, just as the ordered map does
Dot-Function | Description
.REF($$i) | returns a reference to iterator location, used when modifying an element by iterator, e.g. $M(.REF($$i)) = X
.BEFORE($$i) | specifies insertion position, e.g $M(.BEFORE($$i) = X
Dot-Member | Description
.SUBLIST | specifies sublist of element, e.g. $$i.SUBLIST, or $M(.BACK).SUBLIST
.KEY | $$i.KEY is equivalent to .KEY($$i)

All of the following descriptions and examples will assume the prior definition of these two MLISTs:

dimx $m, MLIST(varstr)

dimx $m2, MLIST(varstr)

History

2016 August, A-Shell 6.3.1522: Added MLIST to A-Shell

Subtopics

Adding MLIST Elements

Deleting MLIST Elements

Retrieving MLIST Elements

Splicing Lists

Multi-level List Operations

MLIST Parameter Passing

MLIST Example


Adding MLIST Elements

New elements may be added to the front or back of a list using array assignment syntax equivalent to that used for the ORDMAP collection, except instead of string keys, you must use one of the special dot-variable pseudo keys:

$m(.PUSHFRONT) = X ! add new element to front; assign value X

$m(.PUSHBACK) = X ! add new element at back; assign value x

You may also insert an element into the middle of the list using the special dot-function .BEFORE($$i). In the following example, we scan the list until locating an element whose value is "something", and then insert a new element before it:

foreach $$i in $m()

if $$i = "something" then

$m(.BEFORE($$i)) = x ! insert new element before $$i position

exit

endif

next $$i

Modifying existing elements uses the same syntax as adding or inserting new elements, except with a different set of dot variables and dot functions:

$m(.FRONT) = y ! change value of first element to y

$m(.BACK) = y ! change value of last element to y

To update the value of an element by iterator, you must use the special dot function .REF($$i) to return to updateable reference to the iterator (since $$i by itself is a read-only copy of the value of the element).

foreach $$i in $m()

$m(.REF($$i)) = $$i + "y" ! update value of each element

next $$i


Deleting MLIST Elements

Elements can be deleted by assigning the special value .NULL to them, using the element modification syntax given above. For example:

$m(.FRONT) = .NULL ! delete the first element

$m(.BACK) = .NULL ! delete the last element

foreach $$i in $m()

if $$i = "something" then

$m(.REF($$i)) = .NULL ! delete the element

exit ! always exit foreach loop

endif ! after removing an element, as it

next $$i ! may invalidate the iterator

In addition, you can use the following dot-statements to delete:

.POPFRONT $m() ! delete first element

.POPBACK $m() ! delete last element


Retrieving MLIST Elements

X = $m(.FRONT) ! retrieve value of first element into X

X = $m(.BACK) ! retrieve value of last element into X

foreach $$i in $m() ! access by iterator

X = $$i ! X receives value of iterated element

next $$i


Splicing Lists

One or more elements from one list can be spliced on to another using the dot-statement .SPLICE. Note no elements are actually allocated or deleted in this operation; they are just moved from the source list to the destination list. The general syntax for the .SPLICE statement is:

.SPLICE dst-list-ref, src-list-ref {, count} {, dstpos}

See the next topic for information on dstpos.

If count (number of elements to move) is not specified, the operation moves all of the elements starting from the src-list-ref position. The list-ref parameters may be list base references, e.g. $m(), or they may be references to a particular element by iterator reference, e.g. .REF($$i). For example:

.SPLICE $m(), $m2()

The above case splices the entire $m2() list to the end of the $m() list. Afterward, the $m2() list will be empty (but still valid).

.SPLICE $m(), $m2(), 1

Same as the previous case except only the first element of $m2() is spliced to the end of $m().

To splice to some position other than the end of the destination, specify a position via an iterator reference. For example, to move append the 3rd and 4th items from $m2() the end of $m1()...

count = 0

foreach $$i in $m2()

count += 1

if count = 3 then ! 3rd iterated item

.SPLICE $m(), .REF($$i), 2 ! splice 3rd & 4th items

exit ! iterator corrupted after splice! must exit!

endif

next $$i

The .REF($$i) iterator technique also works for the destination, i.e. to insert at a destination other than the end of the target list. To splice from an arbitrary Xth position in the source to the Yth position in the destination, use a double-nested foreach loop:

! splice count elements from position srcpos in m1$() to dstpos in m2$

idst = 0 ! counter for dest position

foreach $$i in $m2()

idst += 1

if idst >= dstpos then ! $$i is the dst splice-to position

isrc = 0

foreach $$j in $m1()

isrc += 1

if isrc >= srcpos ! $$j is the src splice-from position

.splice .ref($$i), .ref($$j), count

exit ! must exit after splice!

endif

next $$j

exit ! must exit after splice!

endif

next $$i

Note: as with other modifications to a collection, the use of .SPLICE corrupts the iterator; thus you must exit from the foreach loop after the .SPLICE operation. (In the above example, we have to exit from both loops.)

History

2016 October, A-Shell 1532: .SPLICE now accepts limited use of a reverse iterator, but only when the count is 1. Also, the third argument, count, can be any numeric expression.

Subtopics

SPLICE Parameter DSTPOS


SPLICE Parameter DSTPOS

Added November 2016

The fourth parameter, dstpos, allows you to specify the splice position in the destination array. dstpos may be:

Value | Meaning
-1 (default) | indicates end of the $dst() array
0 | indicates the start of the $dst() array
n (n > 0) | indicates after the nth item in $dst() array

Note that this option only applies when the destination parameter is expressed as a base array, as in the above example. Attempting to specify the dstpos parameter when the first parameter is an iterator or other individual element reference will result in a syntax error.

Examples

If $kids() contains the list: "john", "fred", "sally", "pilar" and $pets() contains the list: "dog", "cat", "mouse", "lizard" then:

.SPLICE $kids(), $pets(), 1, 0

would splice "dog" to the start of the $kids() array.

.SPLICE $kids(), $pets(), 3, 2

would splice the first 3 pets ("dog", "cat", "mouse") after the 2nd kid, i.e. in between "fred" and "sally".

.SPLICE $kids(), $pets(), 0, -1

would be the same as

.SPLICE $kids(), $pets()

i.e. would splice all of the pets (count=0), to the end of the kids (-1).

.SPLICE $kids(), $pets(), 0, 0

would splice all of the pets to the start of the kids array.


Multi-level List Operations

The sublists in an MLIST structure are themselves MLISTs, so all of the above operations work the same way on sublists. However, you do need a special dot-member, .SUBLIST, to specify when you are referring to the sublist for an element, rather than to the element as a member of the parent list.

There are two ways to create a sublist, both involving the use of the special .SUBLIST qualifier.

Documentation on the first method is not yet ready for publication.

~~~~======= !=== <this first method doesn't yet work> === ~~~~=======

The first way to create a sublist is to splice elements from another list on to the .SUBLIST member of an element in the destination list, for example:

.SPLICE $m(.BACK).SUBLIST, $m2()

The above statement splices the list $m2() as a sublist of the last element in $m(). Note that without the .SUBLIST modifier, the $m2() list would have been spliced on to the $m() list, just before the last element.

foreach $$i in $m()

if $$i = "something" then

.SPLICE $$i.SUBLIST, $m2, 3

exit

endif

next $$i

In the above example, we scan the $m() list for an element with value "something", and then splice the first 3 elements of the $m2() list as a sublist of that target element.

~~~~~~~~~======= !=== <this method works> === ~~~~~~~~~=======

The second way to create a sublist involves passing it as a parameter to a function or procedure, which is dealt with in a separate section below, after the discussion of deleting sublists.

To delete a sublist, assign .NULL to the target element, either using one of the dot-variable pseudo-keys, or using an iterator to target the element:

$m(.BACK) = .NULL ! delete sublist from last element of $m()

foreach $$i in $m()

if $$i = "something" then

$$i.SUBLIST = .NULL

exit

endif

next $$

The above examples delete the sublist without deleting the element itself. Deleting the element will also delete any sublist(s) attached to it.


MLIST Parameter Passing

MLISTs can be passed by reference to functions and procedures. This is similar to the way it works with ORDMAPS (see 1520.0) except that with MLISTs there is also a variation for passing sublists.

To pass a regular MLIST to a function or procedure, use the following syntax (nearly identical to that for ORDMAPs except for the "AS" clause):

call Proc( $m() ) ! passing the entire $m list by reference

Procedure Proc( $mloc() as MLIST(varstr) )

$mloc(.PUSHBACK) = "new element"

EndProcedure

The above example adds the element "new element" to the MLIST $m(). Note that the local list $mloc() is effectively just an alias for the $m() list. As with passing ORDMAP arrays and other DIMX arrays by reference, you have to initialize the array first in the calling routine.

The pre-initialization requirement does not apply to sublists though, which are automatically initalized when passing them to another routine:

call Proc( $m(.back).SUBLIST )

In the above example, the SUBLIST for the last element of the $m() list is passed to the Proc procedure (given in the previous example). Note that the procedure does not know, or care, that the caller passed a sublist rather than an MLIST base reference; they are indistinguishable from the perspective of the procedure. Also note that since the sublist gets auto-initialized if necessary, the same syntax works regardless of whether the sublist initially exists.

You can also pass a sublist of an iterator, e.g.

foreach $$i in $m()

if $$i = "something" then

call Proc($$i.sublist)

endif

next $$i

In the above example, for each element in the MLIST $m() whose value is "something", we pass the sublist to the Proc procedure, which adds a "new element" to the end of that sublist.


MLIST Example

Here is an example of an MLIST usage, following up on the MLIST exercises from the 2016 Developers Conference: a set of routines to parse a JSON document into an MLIST. This was posted the A-Shell forum, which see if needed.

The representation scheme chosen here is that each MLIST element contains one of the following:

code:

[] (sublist contains array)

{} (sublist contains object)

string (string scalar)

scalar (number, true, false, null)

"name":"string" (name:value pair)

"name":scalar (name:value pair)

"name":{} (value part of pair is object in sublist)

"name":[] (value part of pair is array in sublist)

So for the following JSON document (a common sample found on the Internet)...

code:

{ "store": {

"book": [

{ "category": "reference",

"author": "Nigel Rees",

"title": "Sayings of the Century",

"price": 8.95

},

{ "category": "fiction",

"author": "Evelyn Waugh",

"title": "Sword of Honour",

"price": 12.99

},

{ "category": "fiction",

"author": "Herman Melville",

"title": "Moby Dick",

"isbn": "0-553-21311-3",

"price": 8.99

},

{ "category": "fiction",

"author": "J. R. R. Tolkien",

"title": "The Lord of the Rings",

"isbn": "0-395-19395-8",

"price": 22.99

}

],

"bicycle": {

"color": "red",

"price": 19.95

}

}

}

... the MLIST representation would appear as shown below (using the Mlist'Multi'Level'Display() routine from mlistdemo.bsi; note that the ">" characters are just to indicate the nesting level) ...

code:

> {}

> "store":{}

> "book":[]

> {}

> "category":"reference"

> "author":"Nigel Rees"

> "title":"Sayings of the Century"

> "price":8.95

> {}

> "category":"fiction"

> "author":"Evelyn Waugh"

> "title":"Sword of Honour"

> "price":12.99

> {}

> "category":"fiction"

> "author":"Herman Melville"

> "title":"Moby Dick"

> "isbn":"0-553-21311-3"

> "price":8.99

> {}

> "category":"fiction"

> "author":"Evelyn Waugh"

> "title":"Sword of Honour"

> "price":12.99

> {}

> "category":"fiction"

> "author":"Herman Melville"

> "title":"Moby Dick"

> "isbn":"0-553-21311-3"

> "price":8.99

> {}

> "category":"fiction"

> "author":"J. R. R. Tolkien"

> "title":"The Lord of the Rings"

> "isbn":"0-395-19395-8"

> "price":22.99

> "bicycle":{}

> "color":"red"

> "price":19.95

In other words, the JSON document was mapped onto an MLIST 5 levels deep:

• The top level contains just one element - {} - i.e. a single JSON object.

• Attached to that parent node is a sublist consisting of of a single name:value pair, where the name is "store" and the value is another object, stored in its sublist.

• The contents of the store object at the next level down consists of two name:value pairs. The first is a "book", whose value is an array of books; the second is "bicycle", whose value is another object.

• Below "books":[] we have an array of objects, each of which has a sublist containing a series of name:value pairs representing attributes of the books.

• And so on.

Representing the JSON document in an MLIST like this may not seem like a great simplification over the original text format, particularly in this case where the JSON was already nicely formatted for human reading—although in general, that isn't necessarily the case. The advantage the MLIST structure is that because it is normalized it is thus more amenable to the use of generic routines (possibly with custom callback functions) to perform routine operations such as walking the tree, searching, formatting, etc. The Mlist'Multi'Level'Display() display routine is a simple example of such a generic routine which is able to format with standard indentation any such document.

See the module FNMLISTJSN.BSI in the the SOSLIB:ASHINC:[907,010] for a set of ready-to-use MLIST/JSON helper routines, and MLISTJSON1.BP in the EXLIB:[908,053] for a complete working example.

Although there are a couple of helper functions to read text from the file and grab the next token, the bulk of the logic translating between the JSON and MLIST representations is all in this relatively simple (but recursive) routine:

code:

!---------------------------------------------------------------------

!Function:

! parse a JSON array or object, up to final "]" or "}"

!Params:

! $json() (mlist) [ref] - parsed JSON data stored here (see notes at top)

! endtoken$ (s) [in] - ending token to look for ("]" or "}")

!Returns:

! >= 0 for success

! < 0 for error

!Module vars:

! chin, workbuf$

!Notes:

!---------------------------------------------------------------------

Function Fn'MLJ'Parse($json() as mlist(varstr), endtoken$ as s2:inputonly) as i4

map1 locals

map2 token$,s,0

map2 status,i,4

map2 bdone,BOOLEAN

map2 subendtoken$,s,2

level += 1

do

! get next [,{,],},name:{,name:[, or scalar from file

token$ = fn'mlj'next'token$()

switch token$

case "[" ! parse a new array

case "{" ! parse an object

$json(.pushback) = token$

subendtoken$ = ifelse$(token$="[","]","}")

status = Fn'MLJ'Parse($json(.back).sublist,subendtoken$)

if status >= 0 then

$json(.back) += subendtoken$

else

$json(.back) += " !!Error: missing terminator: "+subendtoken$

endif

exit

case "]"

case "}"

status = ifelse(token$=endtoken$,0,-1)

bdone = .TRUE

exit

case "" ! no more data (error?)

bdone = .TRUE

status = -1

exit

default

switch token$[-1,-1]

case "{" ! name:{

case "[" ! name:[

$json(.pushback) = token$

subendtoken$ = ifelse$(token$[-1,-1]="[","]","}")

status = Fn'MLJ'Parse($json(.back).sublist,subendtoken$)

if status >= 0 then

$json(.back) += subendtoken$

else

$json(.back) += " !!Error: missing terminator: "+subendtoken$

endif

exit

default

! add an name:value, or scalar element to our list

$json(.pushback) = token$

exit

endswitch

exit

endswitch

loop until bdone

if status < 0 then

Fn'MLJ'Parse = -1

endif

level -= 1

EndFunction


Dynamic Arrays (DIMX)

Rewritten December 2011

{qualifier} DIMX arrayname(expr1,...,exprn),type{,sizeexpr {,AUTO_EXTEND}}

{qualifier} DIMX arrayname(expr1,...,exprn),structname {,AUTO_EXTEND}

DIMX declares an array whose element size and extent may be determined at run time. The size of the array can be changed explicitly after the initial DIMX using REDIMX or, with the AUTO_EXTEND keyword, it can be extended automatically.

Arguments

qualifier

An optional keyword to qualify the scope and longevity of the array. Valid qualifiers are STATIC, PRIVATE and PUBLIC. (See MAP Statement Extensions)

expr1,...,exprn

One or more expressions (literal values, variables or arithmetic expressions) evaluated when the statement is encountered at runtime. The number of expressions given determines the number of dimensions of the resulting array.

type

standard variable types (F, B, X, S, I)

sizeexpr

Arithmetic expression (evaluated at runtime) for the size of each element in the array

structname

Name of a structure previously defined with DEFSTRUCT. See Defined Structures and Dynamic arrays of structures.

AUTO_EXTEND

This keyword (case insensitive) causes the array to be automatically extended as required by direct assignment statements. See notes below for more details.

Examples

IMX FDATA(COUNT),F

STATIC DIMX SDATA(COUNT1,A*B,C),S,len(S2$)

PRIVATE DIMX CUSARY(0),ST_CUS,AUTO_EXTEND

The first DIMX statement above represents a simple example of allocating a single-dimensioned array of COUNT (evaluated at runtime) items, each of them a floating point value (using the default floating point size). This is similar to the original DIM statement.

The second statement declares a three-dimension array of string elements whose size matches the logical length of the string S2$ (evaluated at the time the DIMX statement is encountered). The STATIC qualifier would make sense only within the context of a function or procedure; see MAP Statement Extensions for further notes.

The third statement declares an auto-extending array of ST_CUS Defined Structures. The initial size of this array is 0 elements, but will grow automatically as assignments are made to it; see comments about AUTO_EXTEND in the notes below. The PRIVATE keyword would limit access to the array to routines within the same ++include file. In order for that to make any sense, the statement would have to appear at the top of the ++include file, above any functions and procedures. Furthermore, the ++include file would need to be positioned at the top of the main program, or otherwise in arranged so that the run time flow of execution encountered the DIMX statement before it encountered any other references to it.

Notes

· DIMX allocations are automatically freed (and memory recovered) when the RUN or SBX in which they are created exits. DIMX allocations that occur within functions and procedures are automatically freed on return from the routine, unless the STATIC qualifier is used.

· To reset (i.e. delete / free) a DIMX allocation explicitly, use REDIMX to set the subscript extents to zero.

· The contents of a DIMX array (including any extensions to it due to the AUTO_EXTEND feature) are always pre-cleared to nulls.

· The maximum size of an individual DIMX array is determined by the MALLOCLIMIT (default 8MB) option in the MIAME.INI. The limit is tested whenever a DIMX or REDIMX operation takes place, including implicit REDIMX operations triggered by AUTO_EXTEND.

· When an array is automatically extended by the AUTO_EXTEND it will be extended somewhat beyond the amount actually needed for the assignment (on the theory that subsequent expansions are likely to follow). The exact amount of extra expansion is based on a heuristic that is subject to change, but as of build 1191, it consists of the smallest of 110% of the minimum amount required, and 150% of the previous array size. But in no case will the excess expansion (beyond what is immediately needed) be more than 128K. Also see the EXTENT dot function.

· The MALLOC trace option will trace DIMX and REDIMX memory allocations (along with most other memory allocations/de-allocations), making it a useful debugging tool.

· Because there is no support for it under AMOS, DIMX is not normally supported by the /RC compiler switch. However, you can override that (i.e. cause DIMX to be allowed when compiling in /RC mode) by adding the statement "OPTIONS=RC_DIMX" (without quotes) to MIAME.INI. Just be careful to make sure that you don't actually try to execute that statement when running your program under AMOS.

· Global DIMX arrays can be made visible to functions and procedures either via the ++EXTERN mechanism documented in Referencing DIMX Variables or via Dynamic Overlays. Only the latter will work for SBXs. DIMX arrays declared within functions and procedures are normally only visible within that routine; the PRIVATE or PUBLIC qualifiers may be used to extend visibility to the ++include file containing the routine or to the entire program, respectively.

· Like MAP statements, DIMX statements must occur physically prior to any statements referencing the array, so that the compiler can define the variable. Also, as with MAP statements, the array gets initialized (or in this case, allocated) when it is encountered at run time. This generally requires some care in properly positioning the statement to suit the requirements of both the compiler and the run time system; often coupled with some conditional logic to prevent it from being executed more than one time by the run time interpreter.

See Also

• Passing DIMX Arrays

• REDIMX

• DIMX vs DIM

• Dynamic Array of Structures

• MAP Statement Extensions

• Referencing DIMX Variables

• EXTENT

History

2013 January, A-Shell 6.0.1264: Refinement of DIMX / SBX refinement: Use of DIMX within a function or procedure, within an SBX, no longer clears the SBX cache flag. Previously, the cache flag was being cleared so as to force a reload from disk on the next XCALL to the SBX, because DIMX modifies the memory map of the RUN module, thus making it non-reusable.

There are two significant consequences to this rather obscure refinement. The first is that re-executing an SBX that is already cached in memory is much faster than loading it from disk. So for SBXs that are called frequently, and which contain DIMX statements within functions, this can be a significant speed-up.

The second is that it permits the SBX to XCALL itself, either directly or indirectly. Previously, clearing the cache flag caused the SBX to be flushed from memory on the next XCALL. But if the SBX was still executing (in a higher stack frame), clearing it from memory would have rather disastrous ramifications (although typically resulting in an illegal syntax error when returning to the higher level instance of the SBX).

Warning: using DIMX inside an SBX but outside a function/procedure remains incompatible with SBX recursion, although there is currently no way for the runtime system to detect and warn you about it.

2012 March, A-Shell 6.0.1245: DIMX refinement: On the initial allocation for a DIMX statement, the array extent is now adjusted upward to take advantage of the memory chunk actually allocated. In some cases, A-Shell will reuse a convenient chunk of memory that is somewhat larger than the amount requested.

AUTO_EXTEND refinement: when reallocating memory for a larger array, the minimum new size is 105% of the old. Previously there was a limit of 128K of expansion, which may have resulted in increments of as small as a single unit when the base element size was very large.

2011 September, A-Shell 5.1.1235: Add direct support for structures. See Dynamic Array of Structures.

2011 March, A-Shell 5.1.1209: The value of the first subscript in the DIMX statement can now be zero; previously the minimum was one and zero caused a subscript out of range error.

2010 November, A-Shell 5.1.1193: Local non-static DIMX statements are now fully cleaned up on exit from the function or procedure. Previously, the variable descriptor was removed (along with all of the other local stack variables), but the memory handle and allocation remained in effect. With this enhancement, it is no longer necessary to use REDIMX(0...) to "undimx" any DIMX'd arrays at the end of the function. (But it doesn't hurt to perform that step redundantly.) Note that this is purely a compiler adjustment (compiler edit 469, which was included in A-Shell edit 1193), and not a runtime fix.

2010 September, A-Shell 5.1.1192: Added EXTENT dot function and Referencing DIMX Variables capabilities.

2010 August, A-Shell 5.1.1191: Minor refinement in the expansion heuristics used by DIMX with AUTO_EXTEND. When the array needs to be expanded, it is now expanded by a minimum of 150% of the previous array size, or 110% of the size required for the assignment triggering the expansion. But, this is then limited to no more than 128K beyond what would be required for the current assignment. Also, a 128K grace or overage is now added to the MALLOCLIMIT value, to prevent the possibility of the expansion failing because of these heuristics.

2010 August, A-Shell 5.1.1190: Improvements were added in 1190 and 1191 to support its use within recursive SBXs, to add the AUTO_EXTEND feature, and to support removal via REDIMX.

2005 May, A-Shell 4.9.931: DIMX added to A-Shell.

Subtopics

Referencing DIMX Variables

Dynamic Array of Structures

DIMX vs DIM


Referencing DIMX Variables

Added September 2010

Compiler enhancement (edit 463): Functions and procedures may now use ++EXTERN to reference DIMX variables, including those with AUTO_EXTEND. For example:

DIMX A(10),S,20

DIMX B(10),S,0,AUTO_EXTEND

CALL TEST()

PRINT A(10)

PRINT B(50)

END

PROCEDURE TEST()

++EXTERN A()

++EXTERN B()

A(10) = "This is A(10)"

B(50) = "This is B(50)" ! should cause auto-expansion

ENDPROCEDURE

In the above example, the two arrays get initially allocated to 10 elements each before the call to the TEST() procedure. Within the procedure, we assign values to A(10) and B(50). In the latter case, the assignment causes both the B() array to be auto-extended (from 10 to 50+ elements), but also, since the elements of B() are themselves dynamic strings, memory for the B(50) element is created. On return, both values are printed, demonstrating that the manipulations and assignments to the arrays within the procedure are actually operating on the global arrays. (This technique provides a workaround to the restriction of not being able to pass a DIMX array as a parameter to a procedure or function.)

Note that you still must make sure to actually execute the DIMX statement before referencing an element in the array. (Often DIMX statements are placed out of the initial flow of control, in order to allow the dimensions to be calculated before the array is initialized. The need for that is considerably reduced now by the AUTO_EXTEND (5.1.1190) feature, as well as ability to create an array of dynamically sized elements (5.1.1159). Any reference to an array whose DIMX has not yet been executed will result in an illegal subscript error.)


Dynamic Array of Structures

Revised December 2011

A dynamic array of Defined Structures may be defined and allocated as follows:

DEFSTRUCT ST_MOVIE_PROD

MAP2 TITLE$,S,30

MAP2 PRODUCERS(9),S,30

ENDSTRUCT

...

DIMX DMVPR(N),ST_MOVIE_PROD ! dynamic array of N structures

DIMX FX(N),X,300 ! dynamic array of N ordinary X,300 variables

MAP1 FMVPR(10),ST_MOVIE_PROD ! fixed array of 10 structures

...

DMVPR(1) = FX(1) ! assign one X,300 var to another

Note: initial values specified in the map statements within the structure definition are ignored by DIMX. All elements/fields are initialized to null. See this more detailed discussion on the A-Shell forum.

As shown above, the declaration of the dynamic array of structures is syntactically consistent with both static arrays of structures and dynamic arrays of ordinary types (with the structure name replacing the type,size pair). The assignment statement following the declarations also illustrates that the DMVPR() array of structures and the FX() array of simple X,300 variables are, at the top level, compatible, since at the top level, an instance of the ST_MOVIE_PROD structure is equivalent to an instance of an X,300 variable. The FX() array though, provides no direct means of referencing individual fields within each unformatted element, so we'll set that aside for a moment and concentrate on the differences between the fixed and dynamic arrays DMVPR() and FMVPR().

Although the fixed and dynamic arrays are logically similar, the normal organization of fixed arrays of structures, in which each member can be accessed as if it were an independent array, i.e. FMVPR.TITLE$(J), is not efficient for dynamic (moveable) arrays. Consequently, both the structure and the syntax of accessing the individual element members of dynamic arrays is reversed, so that you append the "dot member" name after the structure element subscript, e.g.:

PRINT DMVPR(J).TITLE$ ! member of dynamic array of structures

PRINT FMVPR.TITLE$(J) ! member of fixed array of structures

C programmers will recognize the correspondence to the way elements within arrays of structures are accessed in that language.

When the member is itself an array, as in the case of PRODUCERS(), you end up with two sets of parentheses:

PRINT DMVPR(J).PRODUCERS(K) ! dynamic array

PRINT FMVPR.PRODUCTS(J,K) ! fixed array

As with other DIMX arrays, the AUTO_EXTEND, PUBLIC, and PRIVATE modifiers are all available. See Dynamic Arrays (DIMX) and MAP Statement Extensions.

History

2011 October A-Shell 5.1.1235: DIMX structures implemented.


DIMX vs DIM

DIMX is an enhanced version of the venerable DIM statement used to allocate an array at runtime. The enhancements of DIMX over DIM are:

• It accepts optional type and size specifiers rather than being limited to F6 and string with size determined by STRSIZ.

• The element size is evaluated at runtime, whereas with DIM, it is evaluated at compile time.

• It allocates the memory needed out of the system memory pool, rather than from the user partition. Memory used by DIMX is automatically released when the program ends.

• If the AUTO_EXTEND option is specified, the first dimension (first subscript) of the array will be automatically extended as needed whenever an assignment is made to the array.

• The AUTO_EXTEND feature is only activated for explicit assignments like those shown above; it is not normally activated for ambiguous or implicit assignments, such as when array elements are passed as parameters.


Dynamically-Sized Variables

Added September 2009

As the title suggests, these variables automatically re-size themselves to accommodate the data you assign to them.

Dynamic variables are allocated and maintained outside your user partition, so the only limit on how big they can become would be determined by available memory on the system. If unable to expand as needed, the program will get an error 3 - out of memory. The are understandably not as efficient as fixed-length variables, but can be extremely useful in situations where you don't have a good way of knowing the appropriate maximum size required at the time the program is written. (Letting the computer work a little harder is nearly always a better option than making the programmer work harder or risking bugs caused by inadvertent truncation!) .

To declare a dynamic variable, assign it an explicit size of zero, e.g.:

MAP1 STRING,S,0 ! dynamically sized string

MAP1 UNF,X,0 ! dynamically sized unformatted

MAP1 DARY(75),S,0 ! fixed-length array of dynamic strings

MAP1 XARY(24,9),X,0 ! fixed-length array of dynamic unformatted

Comments

Dynamic variables are impossible to align in memory with respect to other variables, so should normally only be declared at the MAP1 level. However, see Dynamic Variables Below MAP1 for a relaxation of the rule.

An array may be made up of dynamic elements, but the range of index values for the array remains fixed. However, you may use DIMX and REDIMX to dynamically allocate and resize such as array, e.g.

DIMX ZARY(A,B,C),S,0

REDIMX ZARY(A*2,B,C)

Re-dimensioning an array doesn't preserve the original contents unless only the first dimension changes, as in the example above.

Dynamic variables may also be used in function and procedure parameter lists, as well as for the return value of a function, i.e.:

Function Fn'Test$(a$ as s0) as s0

Dynamic variables (and array elements) initially take up 8 bytes of storage memory (used as a descriptor), so it won't make much sense to use them if they aren't going to expand beyond 8 bytes.

When an assignment is made to the variable, either via an assignment (e.g. STRING = "abc"), INPUT statement, or via an XCALL, Function, or Procedure, the variable will be expanded as needed to contain the data. If referenced in an expression before any value is assigned, they act like null strings.

It is not wise to use INPUT RAW with dynamic X variables, since the amount of data input depends on the current size of the variable, which would be 0 initially, but could be anything later (after some other kind of assignment).

As currently implemented, the internal memory allocated to a variable does not shrink, so first assigning a large amount of data and later assigning a small amount does not free memory. (This may change as the implementation evolves.)

The run-time system maintains several pools of dynamic variable memory, including one for global or persistent variables (which lasts for the duration of a RUN program), and one each for the automatic (aka local or stack) variables at each level of function/procedure nesting. All are allowed to grow without any particular limit during the execution, but are cleared as soon as the variables contained within go out of scope—i.e. at the end of a procedure, function, or program.

To compile programs with dynamic variables, you must use compiler edit 439+, and the /X:2 switch. Any legally compiled program containing dynamic variables will receive a new RUN header value of 0xF167 or 0xF1E7 (if /av), and will generate a "?RUN file incompatible" error if executed under any A-Shell runtime prior to 5.1.1159. Programs which do not contain dynamic variables should continue to compile and run exactly as before.

Example

To load an entire binary file into a dynamic X variable:

map1 bytes,f

map1 rcv,f

map1 ch,b,2,1

map1 blob,x,0 ! dynamic var to hold file

xcall SIZE, fspec$, bytes ! get size of file

open #ch, fspec$, input

xcall GET, blob, ch, bytes, rcv ! blob now contains file

close #ch

! create an exact copy of the original file...

open #ch, "copy.dat", output

print #ch, blob;

close #ch

See the SOSFUNC library module FNFILESTR.BSI for a set of related routines for copy files to memory variables and vice versa.

History

2014 September, A-Shell 6.1.1391: Eliminate the extra trailing null byte when initializing/expanding dynamic X variables. The extra null byte was added to dynamic strings to improve compatibility with external library routines expecting "C-style" (null-terminated) strings, but this doesn't apply to X variables, where the extra byte was just a nuisance. When loading a binary file into an X variable for example, it was throwing off the size and hash.

2009 September, A-Shell 5.1.1159: Feature added to A-Shell

Subtopics

Dynamic Overlays

Dynamic Variables Below MAP1


Dynamic Overlays

Updated January 2011

A dynamic overlay is similar to a dynamic X variable, except that it is designed specifically for overlaying DIMX arrays. Such an overlay permits you to pass a DIMX array as a parameter to a subroutine or procedure / function.

There are two steps involved in creating a dynamic overlay:

Step 1: Declare the Overlay

Declare the overlay variable using the special ,@0 overlay syntax, e.g.:

MAP1 OVERLAY,X,@0

Note that the size field is optional but ignored, and only S and X variables are allowed. (In most cases, only X makes sense; use S-type overlays only when you are sure that the target variable contains no embedded null bytes.)

Step 2: Assign the Overlay

Assign the overlay at runtime using the "=@" operator, e.g.:

OVERLAY =@ VAR ! or, OVERLAY = @VAR (spaces are not significant)

This effectively gives the OVERLAY variable the same data storage location and size as the VAR variable. As mentioned above, the main motivation is to do this with dynamic arrays, e.g.:

DIMX DYNARY(x,y,z),S,n

...

OVERLAY =@ DYNARY()

Note that you may NOT specify any array subscripts for the array on the right side of the @= operator, since this technique is currently only supported to overlay the ENTIRE array.

Comments

The overlay does not automatically get updated if the target array changes in size—i.e. due to either REDIMX or AUTO_EXTEND (see Dynamic Arrays (DIMX)). However, you can reassign the overlay as needed. For example:

MAP1 AOVL,X,@0 ! declare the dynamic overlay

DIMX A(5,10),S,7 ! dimension an array

AOVL =@A() ! assign the overlay to the array

PRINT LEN(AOVL) ! prints 350 (5 x 10 x 7)

REDIMX A(10,10) ! redimension the array

PRINT LEN(AOVL) ! still prints 350 (still tracking the old allocation)

AOFL =@A() ! reassign the overlay

PRINT LEN(AOVL) ! now prints 700 (10 x 10 x 7)

So the best practice would be to (re)assign the overlay immediately before you need to use it.

Example

There is currently no corresponding operation to overlay a dynamic array on top of an X variable, which admittedly might be handy when passing such an array between routines via parameter lists. But you can get around that limitation using the technique in the following example, which passes a dynamic array to a procedure for processing:

DIMX ARY(X),S,Y

MAP1 OVL,X,@0

...

<load the array with some data>

...

OVL = @ARY() ! overlay the array with the XARY variable

CALL MYPROC(OVL,X,Y) ! pass array plus its dimensions to a function

...

! (our ARY() may have been updated by the MYPROC() procedure)

END

!-----------------

PROCEDURE MYPROC(XXARY AS X0, ELEMENTS AS F, WIDTH AS F)

DIMX LOCARY(ELEMENTS),S,WIDTH ! allocate local array to match array passed in

MAP1 LOCOVL,X,@0

MAP1 I,F

LOCOVL =@ LOCARY() ! overlay the local (currently empty) array

LOCOVL = XXARY ! now copy the data on top of that

FOR I = 1 TO ELEMENTS

<perform operations on LOCARY(I)>

NEXT I

XPUTARG 1,LOCOVL ! update caller's overlay (which is the same as

! caller's actual array) with the local array data

ENDPROCEDURE

History

2010 September, A-Shell 5.1.1192: Added to A-Shell in compiler edit 465.


Dynamic Variables Below MAP1

Added February 2015

Note: This function was added to A-Shell in an experimental context. Please use with caution, test thoroughly, and report your experiences back to the A-Shell developers.

It is possible to allow dynamic variables (s,0 and x,0) below the MAP1 level. For example:

DEFSTRUCT ST_REC

MAP2 SKU,S,10

MAP2 DESCR,S,0 ! variable length!!

MAP2 PRICE,F

ENDSTRUCT

This can be a useful technique for encapsulating data with variable-length components, but it creates an implicit linkage between the structure and the variable length elements that opens the door to various kinds of risks if not handled carefully. The size of the structure is fixed—the variable length field appears to have a fixed length of 16 bytes—but the contents of the variable length member are stored outside the structure, in the dynamic variable pool. The structure can be passed as a parameter to a function, and the variable length elements will remain intact, but at that point they should be treated as read-only. Both copies of the structure would link to the same variable-length text, but if that text is changed, only the current structure would remain properly linked to the updated text.

Writing the structure to a file would also make no sense; in that case, what would actually be written for the dynamic members would be their 16 byte descriptors, which would be useless outside the immediate context of the program.

History

2014 October, A-Shell 6.1.1391, compiler edit 712: Added to A-Shell


Implicit Variable Declarations

In addition to explicit declaration of variables via MAP or DIMX statements, provided you do not use the /M COMPIL switch, you may implicitly declare variables simply by using them. In the absence of the /M switch, when the compiler sees a variable that has not previously been declared, it creates an implicit MAP statement for it, based on the following rules:

• If the variable name ends in $, it will be auto-mapped as a string according to the default string size specified by a prior STRSIZ # statement (with a default size of 10 bytes).

• Otherwise it will be auto-mapped as F,6

Note: it is strongly recommended that you do not take advantage of this dubious feature, since it makes it all too easy to introduce bugs into programs via typos and misspellings of variable names. Furthermore, it is recommended that you use COMPIL /M to force all variables to be explicitly declared. If you are working with a large set of code which uses a lot of implicit variable declarations, an easy way to locate and create explicit MAP statements for all of the undeclared variables is to use the COMPIL /L switch, which creates a .LSX listing, at the end of which will appear the auto-mapped variables. You can review the list—perhaps sort it first to help spot similar names possibly referring to the same thing—and then just yank the set of MAP statements into the source code to make those variable declarations explicit, after which you can take advantage of the /M switch.


CMDLIN

This system variable is automatically set to contain the remainder of the command line used to start the current program. For example, if the program was started with:

RUN FALALA do re mi

Then A$ = CMDLIN would set A$ to "DO RE MI" (always folded to upper case).

xcall LSTLIN, A$ on the other hand, would return "RUN FALALA do re mi" (the complete command line with no folding).


Dot Variables

Dot variables, so named because they begin with a period (dot), are read-only system variables useful for retrieving certain kinds of information like the date, program name, etc. In many cases, the same information is available via other methods, such as XCALLs, but the dot variable approach is generally the most elegant, efficient, and transparent. They were originally considered part of the d/Basic extensions (COMPIL /D), because most of them originated with d/Basic. But over time, A-Shell has added its own dot variables and they are now available as part of the A-Shell extensions (COMPIL/X:2).

Extension | Notes
.ACCOUNT | Evaluates to the user’s current ppn (e.g. "100,22").
.ARGCNT | Number of parameters passed in the last function, procedure call, or SBX.
.DATE | Returns the date as a decimal number which displays as MMDDYY. So March 16, 2009 should return the numeric value 31609.
.DEVICE | Evaluates to the user’s current device (e.g. "DSK0:")
.EXPERIENCE | Evaluates to the numeric value 100 (since "experience" level is not one of the AMOS job attributes that is emulated under A-Shell).
.FALSE | .TRUE and .FALSE may be used as self-documenting replacements for -1 and 0.
.JOBNAME | Evaluates to the jobname.
.LAST_LABEL | Name of last label passed. Requires ++PRAGMA TRACK_LAST_LABEL.
.LAST_ROUTINE | Name of last called function or procedure. Requires ++PRAGMA TRACK_LAST_ROUTINE.
.LINENO | Returns the last line number, similar to err(1) except without requiring an error. Not to be confused with the dot function .LINENO(ch) (which returns the physical line # since the last page break in the output file open on the specified channel).
.LOCATION | Returns the current program location counter, i.e. the offset in bytes from the start of the current program (RUN, LIT or SBX) to the current statement position. Note that the location counter is generally represented in hex (as it appears in the LSX files created by the compiler /LF switch), so you would probably want to print it using the SOSLIB function Fn'Dec2Hex(.LOCATION).
.MONTH | Evaluates to the 3 character abbreviation for the current month.
.NEST_LEVEL | Number of levels deep with nested function/procedure calls.
.NULL | May be used with sequential files to open a file which is not connected to anything.
.PGMNAME | Evaluates to the current program name.
.PGMVERSION | Evaluates to the current program version (e.g. "1.2A(100)").
.TERMINAL | Evaluates to the current TRMDEF name.
.TIME | Evaluates to the current time, in HHMMSS format.
.TRUE | .TRUE and .FALSE may be used as self-documenting replacements for -1 and 0.
.USERNAME | Evaluates to the user name.
.YYMMDD | Evaluates to the current date in YYMMDD (string) format.

History

2016 December, A-Shell 6.3.1538, compiler edit 792: Add .LINENO and .LOCATION

2016 September, A-Shell 6.3.1524: Add special file name .NULL

2014 October, A-Shell 6.1.1391, compiler edit 710: Add .TRUE and .FALSE

2006 October, A-Shell 4.9.969: Add .LAST_LABEL, .LAST_ROUTINE, .ARGCNT, .NEST_LEVEL

1997 August, A-Shell 4.2.555: Add .TERMINAL, .JOBNAME, .USERNAME, .ACCOUNT, .DATE, .TIME, .PGMNAME, .PGMVERSION, .MONTH


ARGCNT

Updated November 2016; see History

.ARGCNT holds the number of arguments for the last SBX or function or procedure. It also:

• retrieves the number of arguments passed to an SBX, without any need to ++INCLUDE ASHINC:XCALL.BSI previously.

• returns -1 if the current program was not called as an SBX.

• gets replaced by the next Function, Procedure or SBX call, so it should be tested immediately at the start of a routine, and the results saved if needed later in the routine.

History

2016 November, A-Shell 6.3.1534, compiler edit 790: use of .ARGCNT within a PRIVATE_BEGIN / PRIVATE_END block now generates a compile error. Although the expression wouldn't technically be illegal, because the PRIVATE block is essentially called for initialization by whatever function or procedure in the module gets called first, there's really no good way to predict in advance what the .ARGCNT value will represent, and thus it is almost certain to create a discrepancy between the expected and actual behavior.

2012 November, A-Shell 6.0.1262: The current .ARGCNT value (# of arguments passed to the current subroutine, function or procedure) is no longer wiped out by calls to functions or procedures. This eliminates the need to copy it to a local variable immediately upon entrance into a routine.


NULL

Added October 2015

The special file name .NULL may be used with sequential files to open a file which is not connected to anything. For example:

OPEN #1, .NULL, OUTPUT

OPEN #2, .NULL, INPUT

For output, .NULL is equivalent to the device /dev/null under UNIX and NUL under Windows, i.e.any data output to the file is just discarded. For input, .NULL acts like an empty input file (returns EOF on the first input attempt).

The ability to associate an output file channel with a null device adds to the flexiblity of the PRINT #CH statement, since depending on the value of CH and what file it is associated with, the statement can output to the screen (if CH=0), a disk file, or nothing at all. But the feature is even more useful in conjunction with the new MX_FILESOCK mechanism (see next).

History

2016 September, A-Shell 6.3.1524: Function added to A-Shell.


Expressions

ASB expressions are combinations of variables, literal values, operators, functions and parentheses that can be reduced to a single value. Generally speaking, wherever you can use a single value or variable in a source rather than destination context, you can use an expression of arbitrary complexity. Although there are several types of variables, there are only two fundamental types of expressions: numeric—that evaluate to a floating point value—and string—that evaluate to a string. Mostly this is all quite familiar and intuitive, although there are few quirks—"mode independence", the overloaded + operator, and Boolean bit-wise arithmetic—which merit some discussion. First, though, let's review the complete list of operators:

Operator | Precedence 1=highest | Description
^ | 1 | Raise to power, e.g. 5^3 is 5 to the 3rd power or 125
** | 1 | Equivalent to ^
+ | 2 | Unary plus
- | 2 | Unary minus
* | 3 | Multiplication
/ | 3 | Division
+ | 4 | Addition or string concatenation
- | 4 | Subtraction
= | 5 | Relational equals, e.g. IF A = B OR C = D THEN ...
< | 5 | Relational less than; string or numeric
<= | 5 | Relational less than or equals; string or numeric
> | 5 | Relational greater than; string or numeric
>= | 5 | Relational greater than or equals; string or numeric
<> | 5 | Relational not equal; string or numeric
# | 5 | Relational not equal; same as <>
NOT | 6 | Logical NOT, e.g. IF NOT (A OR B) THEN ...
AND | 7 | Logical AND
OR | 7 | Logical OR
XOR | 7 | Logical XOR; exclusive OR
EQV | 7 | Logical equivalence; exclusive NOR
MIN | 7 | Minimum (of two operands), e.g. A = B MIN C + D
MAX | 7 | Maximum (of two operands), e.g. A = B + C MAX D + E
USING | 8 | Formatting, e.g. A USING "###.##"

Mode Independence

This mysterious term, brought over from the original AlphaBASIC, refers to the ability to use and intermix string and numeric expressions, with the compiler and runtime interpreter performing conversions as necessary for the operations to make sense. For example, since multiplication only makes sense with numeric operands, if you supply string operands, they will be converted to numeric expressions automatically before the multiplication is performed. If a string starts with non-numeric characters, the corresponding value is simply zero. This is all fairly straightforward for operators and statements that expect a certain type of operand; the confusion comes with the + operator, which works with both strings and numbers.

Subtopics

Constants


Constants

Constants are either numeric values, string values, or in some cases compiler functions, which are evaluated and fixed at compile time rather than at run time.

String Constants

These are enclosed in double quotes, e.g.

NAME$ = "Smiley O'Reilly"

To include a double quote character (ASCII value 34) within a constant string, use two of them together, e.g.

TOOL$ = "6"" Wrench" ! evaluates/displays as 6" Wrench

There is no syntax for embedding control characters or escape sequences directly within literal constant strings. Instead, such strings must be built using a combination of concatenation and the CHR(x) function, e.g.

ONE'TWO$ = "Buckle" + chr(13) + chr(10) + "my shoe." ! (CRLF embedded in middle of string)

Numeric Constants

These come in the following flavors:

• Decimal values (integer or floating point), with optional leading minus sign. Note that the decimal point character is the (American-style) period; commas are not allowed, nor is scientific/exponential notation. Examples:

A = 25 ! Good: decimal integer

B = -2.3 ! Good: negative decimal floating point

C = 2.3- ! Illegal: trailing unary minus sign not allowed

D = 12345.67 ! Good: positive decimal floating point

E = 12,345.67 ! Illegal: commas not allowed

• Hexadecimal and octal values are denoted with a leading "&h" or "&o" (case sensitive), respectively; e.g.

F = &h100 ! Good: hex 100 (256 decimal)

G = &o100 ! Good: octal 100 (64 decimal)

H = &H100 ! Bad: &H not recognized (must be lower case)

I = &O100 ! Bad: &O not recognized (must be lower case)

• Single-byte ASCII values are denoted by enclosing the ASCII character in single-quotes, e.g.

A = 'A' ! Good: ASCII A (65 decimal); same as A = 65

Note that the hex and octal notation described above is also recognized by the various forms of INPUT statements, DATA, and GDI print directives. The ASCII byte notation, however, is not.

Symbols

These are created with the DEFINE statement are treated by the compiler equivalently to literal string or numeric constants, depending on whether the symbol name ends in a dollar sign, e.g.

DEFINE FREEDOM_FRIES$ = "French Fries" ! define string constant

DEFINE FF_COUNT = 25 ! define numeric constant

? FF_COUNT;FREEDOM_FRIES$;" per serving" ! this statement compiles to same RUN code

? 25;"French Fries";" per serving" ! RUN code as this statement

Compiler Functions

These are functions that are evaluated by the compiler at compile-time rather than by the interpreter at run-time, and thus are equivalent to constants. See the "Related Topics" below.

Subtopics

OFFSIZ$

OFFSET

SIZEOF


OFFSIZ$

Added April 2013

.OFFSIZ$(struct.member)

This is a variation of the .OFFSET() function (see 6.1.1350.0) which returns the combination of the specified structure member's offset and size, as a string formatted as "offset~size". While the combination of the two values in a string may seem unusual, since the offset and size are often used together, the combined format eliminates the need to specify the struct.member name twice, which invites discrepancy, and lends itself to use in runtime functions that may parse out the two values and combine them with other information.

Here are some examples using the structure given in the description of .OFFSET() in 6.1.1350.0 below:

? "Offset~size of FLD1 in ST_1: "; .OFFSIZ$(ST_1.FLD1) ! "1~10"

? "Offset~size of FLD2 in VAR : "; .OFFSIZ$(VAR.FLD2) ! "11~13"

? "Offset~size of FLD3 in VX(): "; .OFFSIZ$(VX().FLD3()) ! "24~6"

.OFFSIZ$() is particularly handy in building XTREE coldefs, e.g.:

coldef$ += .OFFSIZ$(ST_1.FLD1) + "~Field~S~~" ! 1~10~Field 1~S~~

or, using a hypothetical function to build the entire definition for an XTREE column:

coldef$ += Fn'Coldef$(.OFFSIZ$(ST_1.FLD1), title$, cformat$, option$)

History

2013 April, A-Shell 6.1.1350: Function added to A-Shell


OFFSET

Added April 2013

.OFFSET(struct.member)

Similar to .SIZEOF(var) except that it returns the offset to the specified member variable within the specified structure, starting from 1, rather than the size of the variable, and it only works on fields within structures. Also, in the case of arrays, .OFFSET only returns the offset to the base of the array, and doesn't actually allow the use of subscripts. The specified structure name can either be a defined structure name, or a MAP'd or DIMX'd instance of it. For example:

DEFSTRUCT ST_1

MAP2 FLD1,S,10

MAP2 FLD2,S,13

MAP3 FLD3(4),F

ENDSTRUCT

MAP1 VAR,ST_1

DIMX VX(10),ST_1

For example:

? "Offset of FLD1 in ST_1: "; .OFFSET(ST_1.FLD1) ! 1

? "Offset of FLD2 in VAR : "; .OFFSET(VAR.FLD2) ! 11

? "Offset of FLD3 in VX(): "; .OFFSET(VX().FLD3()) ! 24

Note the empty parentheses () in the third example.

History

2013 April, A-Shell 6.1.1350: Function added to A-Shell


SIZEOF

.SIZEOF(variable)

.SIZEOF evaluates at compile-time to the size in bytes of the specified variable or defined structure, which must have been previously defined with a MAP or DEFSTRUCT statement. For example:

defstruct ST_REC

map2 field1,s,10

map2 field2,f

endstruct

map1 price,f,8

map1 vs$,s,0

map1 rec, ST_REC

map1 rec'copy, x, sizeof(ST_REC) ! rec'copy, x, 16

dimx xary(5), x, .sizeof(rec) ! xary(5), x, 16

map1 fbytes(.sizeof(price)),b,1 ! fbytes(8),b,1

map1 ary(10)

map2 foo,f

map2 bar,i,2

print .sizeof(ST_REC) ! 16

print .sizeof(rec) ! 16

print .sizeof(rec'copy) ! 16

print .sizeof(ST_REC.field2) ! 6

print .sizeof(rec.field1) ! 10

print .sizeof(vs$) ! 16 (see comments)

print .sizeof(ary(1)) ! 8

print .sizeof(foo(1)) ! 6

Comments

Although most of the examples above show use of the .sizeof() compiler function in a PRINT statement, where it might be confused with a run-time function, in all cases, the function is evaluated by the compiler. It is converted to a fixed integer at the point it is first encountered, and thus may be used anywhere a literal integer is otherwise required, such as when declaring the size of a variable or the number of elements in an array.

The .sizeof function may take as an argument the name of a defined structure (ST_REC), the name of a field within the defined structure (ST_REC.field2), the name of an ordinary mapped variable (price), an instance of a structure (rec), a field within an instance of a structure (rec.field1), or an array element (ary(1) or foo(1)).

Variable length S and X variables, such as vs$ in the example above, always return a size of 16; this is the internal size of the descriptor for the variable, not the size of the data held by the variable, which changes at runtime and which can be accessed via the run-time len(vs$) function.

Use of .sizeof when defining related variables is a good technique for avoiding inadvertent errors that arise when you later change the size of one of the variables and forget to change the other. Another way to reduce that risk is to use the DEFINE statement to define a constant symbol which is then used to define the size of related variables. But .sizeof is even more powerful since it works on compound structures like ST_REC and ary(1) in the example above.


Assignment Statements

This documentation has not yet been written, we're working on it. Needed to put the topic here for linking purposes.


I/O Statements

Input/Output statements divide into two general categories: sequential access and random access. On the AMOS platform, this distinction exists even at the file level: random files, also known as contiguous files, are actually allocated as single contiguous sets of blocks on the disk, unlike sequential files which are allocated as linked lists of blocks. On the Windows and UNIX platforms, the operating system makes no distinction between the two types of files—all files are allocated as a linked list of blocks—and all files may be accessed using either sequential or random-access methods, determined by the way the file is opened. In practice, any given file is typically accessed by one method or the other, not both, based on the type of data and general purpose of the file.

Sequential Access

• text-oriented, typically

• byte, field, or line-oriented

• variable length fields and lines

• files are opened for input or output, but not both

• no record locking

• the screen is a special sequential file; open for output on channel 0

• the keyboard is a special sequential file; open for input

• serial ports may be accessed as sequential files

• output files may be created by the OPEN statement and grow automatically via PRINT

• the DATA statement pool acts like a sequential input file, internal to the program

• access is by default sequential but can be overridden using MX_FILEPOS.

Random Access

• fixed length records containing a mixture of field types

• ISAM and ISAM-A files are special variants of random access files

• files must be pre-allocated; see ALLOCATE, CREATE

• file expansion typically not automatic, except for ISAM, ISAM-A; see MX_EXPFIL

• file and record locking is available; see LOKSER

• records may be "blocked" into 512 byte blocks; see OPEN for random access statement

Subtopics

Generic File Statements

Sequential File Statements

Random File Statements

TRACE and DEBUG Statements

ISAM Statements

ISAM-A Statements


Generic File Statements

These file statements work on all types of files.

Subtopics

CLOSE

KILL

LOOKUP


CLOSE

CLOSE #ch

Parameters

ch is the file channel associated with the file when it was opened.

Comments

Closing a file releases any internal locks on it. It has no effect on external locking mechanisms such as XLOCK and FLOCK.

All open files are automatically closed at the end of a program.

Attempting to explicitly close a file channel which is not open generates BASIC error #14 (I/O to unopened file). You can determine if a file channel is open by using the ERF(ch) function.


KILL

Updated July 2015; Comment added

KILL fspec

KILL erases/deletes a file.

Parameters

fspec is filespec in native or AMOS format. If no extension is specified, .DAT is assumed. Terminate the filespec with a dot to erase a file with no extension.

Comments

If the file does not exist, the statement behaves like a null operation—i.e., no error is triggered. So there is no particular need to do a LOOKUP prior to a KILL.


LOOKUP

LOOKUP fspec, blks

LOOKUP checks for size and existence of a file.

Parameters

fspec is a filespec in native or AMOS format. Default extension is .DAT.

blks is a floating point variable which returns the size of the file in "blocks" (512 bytes). Adding further to the confusion of the archaic units, if the file is an exact multiple of 512 bytes, the number of blocks will be reported as a negative value, indicating a "random" file; otherwise it will be a positive number. See the system option ABSLOOKUP to override that behavior. If the file does not exist, the return value is 0. If the file exists but has zero bytes, the return value is 0.5.

See Also

LOOKUP function.


OPEN for sequential access

OPEN #ch, fspec, INPUT {,WAIT'FILE}

OPEN #ch, fspec, OUTPUT {,WAIT'FILE}

OPEN #ch, fspec, APPEND (,WAIT'FILE}

Parameters

ch is an integer expression specifying the file channel which will be needed for subsequent I/O operations on the file. File channel 0 refers to the terminal, in which case the OPEN statement will have no effect.

fspec is a string expression specifying the file to open, using native or AMOS syntax.

WAIT'FILE only applies when the LOKSER system option is active and causes the program to wait for exclusive access to the file.

Comments

Opening a file for OUTPUT creates an empty file. If the file already existed, it is first deleted.

APPEND is equivalent to OUTPUT except that if the file does exist, it is not first deleted.


INPUT

INPUT {#ch | prompt,} var {,var2 ... varn}

expects commas to delimit the input data into fields. If the data stream does not appear to satisfy the number of destination variables specified, it will prompt for more. The input stops when all the variables have been satisfied, which may be mid-line.

INPUT LINE {#ch | prompt,} var

inputs up to a line terminator, assigning the entire result to the one var.

INPUT RAW #ch, var

inputs a number of bytes of raw data equal to the physical size of the specified destination var.

INPUT CSV #ch, var {,var2 ... varn}

similar to the standard INPUT but is better at tokenizing the input according to the common industry standards for comma separated values.

Parameters

ch is an integer expression specifying the file channel on which the file was opened.

prompt is a string expression specifying the prompt to display on the screen for the case of keyboard input.

var, var2, ... varn are numeric or string variables to receive the input. Except for INPUT RAW, you may use dynamic strings (s,0) which will be expanded as needed to contain the input data.

Comments

If the file channel is not specified, or evaluates to zero, the operation inputs from the keyboard, in which case the optional prompt may be specified to instruct the operator what to input, e.g.:

INPUT "Enter your name: ", NAME$

INPUT "", NAME$

If no prompt is specified, a "?" will appear to prompt the user. You can specify a null prompt as in the second example above to eliminate the "?".

Subtopics

INPUT CSV

INPUT RAW


INPUT CSV

Rewritten October 2011

INPUT CSV #CH, var1 {,var2 {,…varn}}}

INPUT CSV #CH acts much line INPUT #CH (input from a file), except that it contains additional parsing logic designed to deal with various forms of CSV (Comma Separated Values) format, which can sometimes be troublesome for the standard INPUT #CH statement. (Despite the name, CSV files sometimes use delimiters other than commas, such as tab, colon, or semi-colon. The INPUT CSV operation scans the first line of the file to identify the delimiter character, based on the most commonly appearing character not within pairs of quotes, from the set of: comma, tab, colon, and semi-colon. The standard INPUT #CH statement only supports comma delimiters.)

Another important difference between the two input statements is that INPUT CSV is line oriented rather the field oriented. Each INPUT CSV statement will process a single line of the input file, regardless of how many variables are listed in the INPUT CSV statement or how many fields appear in the actual data. If there are more variables than data fields, the extra variables are set to null. If there are more data fields than variables, the extra data fields are ignored. (Note that line breaks which occur within quoted fields are treated as mere data characters and do not terminate the INPUT CSV operation.)

Unfortunately, there seems to be no universal standard for CSV files, particularly as it relates to the handling of quotes within fields. INPUT CSV uses various heuristics to attempt to determine whether each double-quote character is a merely a field delimiter or part of the data. For example, the quotes surrounding a field such as { "Smith, John" } would be treated as delimiters and removed from the data returned in the associated field. Without those quotes, the comma would probably be treated as a delimiter, such that the data would be considered as two fields. When a quote appears mid-field, such as { "6" bolt" }, with or without the quotes around the outside of the field, it will be treated as a raw data character; the associated return variable would receive { 6" bolt }. Double double-quotes are generally treated as single double-quotes, as in BASIC strings, so { "7' 5"" center" } would be interpreted as { 7' 5" center }.

Comments

You can disable all of the special quote handling logic by using the AS_CSVNOQUOTE flag in the ASFLAG.SBR subroutine.

The maximum logical line length is 4K.

Warning: the variables receiving the fields must each be long enough to hold the entire field as it appears in the data file, including outer quotes. Otherwise, fields which are quoted in the data may end up being returned with the leading quote character included in the returned variable, with a corresponding character truncated from the end. Dynamic string variables (s,0) are supported.

History

2011 May, A-Shell 5.1.1215: The auto-detection of the delimiter character has been expanded to support comma, tab, colon and semi-colon. The decision is based which of the four characters is the most common (outside of quoted fields) on the first line of the file. Previously, only comma and tab were supported, and the decision was based on which character appeared first in the file.

2009 October, A-Shell 5.1.1163: AF_CSVNOQUOTE flag now stifles the automatic removal of the outer quotes surrounding a field.

2008 August, A-Shell 5.1.1122: Fields enclosed in quotes are now automatically de-quoted, even when AF_CSVNOQUOTE is set. AF_CSVNOQUOTE is still useful for eliminating all other quote-matching logic in files that have non-standard quoting. Also, AF_CSVSMARTQUOTE no longer does anything. Its logic is now automatic. Previously, it only served to prevent the improper concatenation of additional input lines in order to try to match up quotes that occur in the middle of a field (i.e. don't require matches). There doesn't seem to be any value in not doing that all the time.

2008 February, A-Shell 995.0.7: Fields with embedded line breaks are now supported. The total extended input line length is still limited to 4K.


INPUT RAW

INPUT RAW #ch, var

where ch is the channel of a sequential file open for input, and var is a variable of type X. The operation proceeds until var is filled (with no filtering of binary characters, line terminators, etc.), or until EOF.

Comments

Requires compilation with the /X:1 switch

See also

• GET.SBR

• GETBYT.SBR


PRINT Statement

PRINT {#ch} {USING mask}{delimiter} expr{delimiter expr delimiter...}

PRINT outputs the specified material to file or screen.

ch is an integer expression specifying the file channel on which the file was opened. If not specified, or zero, output is to the terminal.

USING mask may specify a format mask for the entire print operation, which must include format specifiers for each expression listed in the statement.

Each expression is a numerical or string expression, which may include a USING mask clause for formatting that one expression.

Each delimiter may be either a space, comma or semicolon. A space simply outputs a space. A semicolon outputs nothing beyond the preceding expression—i.e. stops the cursor just past the output of the expression. A comma adds several spaces following the preceding expression, unless a format mask was specified prior to the first expression, in which case commas are used simply to delineate the expressions so they can be matched up with the corresponding format specifiers in the mask. The last delimiter is optional. If omitted, a line terminator (CRLF or LF) is output.

Comments

The statement token "PRINT" may be replaced by the equivalent "?" for brevity.

Print Tab() Functions are often used as expressions within PRINT statements, particularly for screen output. For file output, only one dimensional tabs are meaningful.

PRINT statements are somewhat unusual in that they take a variable number of expressions as arguments. A PRINT statement with multiple arguments can be broken up into multiple PRINT statements with the same overall result. Alternatively, instead of using the delimiters to separate multiple expression arguments, you can use string concatenation to combine them all into a single string expression.

Three variations of PRINT are DPRINT, EPRINT and TPRINT, all of which has the identical syntax but are only applicable for screen printing in a GUI environment. All three use the current default proportional font instead of the standard fixed-pitch text mode font. DPRINT adds a sunken panel effect and is typically used for displaying static data fields. EPRINT embeds the output fields in edit boxes, typically used for displaying editable data fields. For outputting to GUI screens you can also use AUI_CONTROL .

Examples

PRINT "Hello world"

? #7, CITY$;", ";STATE$;" ";ZIP$

? #7, CITY$ + ", " + STATE$ + " " + ZIP$ ! same result as preceding statement

? #CHREP USING "###. /---description ---/ $###,###.##", QTY, DESCR$, QTY*PRICE

print tab(r,c);"Enter name: "'; tab(r,c+30);"Age: ";

Print (A using MASK1$) (B using MASK2$)

See Also

• TRACE.PRINT: output to debug window

• DEBUG.PRINT: output to debug window if DEBUG mode

• WRITECD (following topic): comma delimited file output

• USING Mask


WRITECD

Updated May 2011

Note: Beginning in A-Shell 5.1.1216 of May 2011, it became possible to specify which delimiter characters would be used for WRITECD and WRITETD operations; see Get/Set CSV Delimited for more information. We have left the original documentation in place because in the absence of a defined delimiter, both WRITECD and WRITETD will work as they previously have. If you define your own delimiter, however, all references below to "comma" should be replaced with "defined delimiter character."

The ability to define a delimiter also means that WRITETD is now deprecated, and should not be used. It remains a valid operator only to preserve operations by older code.

WRITECD (Write Comma Delimited) is a variation of the PRINT statement which is useful for creating industry-standard* comma-delimited files. Syntax and operation is identical to the PRINT statement, except that it performs three additional functions which are useful when more than one variable is being output on a line:

• it automatically inserts a comma between each variable being output

• it automatically quotes any string variable which itself contains any of the "likely" delimiter characters (comma, tab, semicolon, colon), the custom delimiter character (if applicable), or any of the "problem" characters (quote and apostrophe).

• it strips leading and trailing blanks from any string variable (unless accompanied by a formatting mask).

The maximum size of an individual field needing to be enclosed in quotes is 1021 bytes.

Example

WRITECD #1,5.2,"Nov 1, 1998"," abc "

Outputs:

5.2,"Nov 1,1998",abc

Comments

WRITECD/WRITETD will convert any embedded quotes (") within a field into apostrophes ('), to try to be more compatible with other CSV readers. It will also put double quotes around any field containing quotes or apostrophes, in addition to commas and tabs, as before.

Also note the procedure for breaking up a single line of CSV output into multiple WRITECD statements:

WRITECD #CH, A, B, C,;

WRITECD #CH, D, E, F

This will output the six variables on one line. Note that that the comma after the C and before the semicolon is required. If you omit it, the D output will immediately follow C with no delimiter. If you omit the semicolon from the first line, then you'll get two lines of output.

* Note that the term "industry standard" is used with a good deal of sarcasm and distaste in this context, since the notion of any such standard is farcical. Which is why typical spreadsheet programs now employ elaborate 'wizards' to aid in the importing of CSV data, and which despite all kinds of fancy heuristics still have to rely on a complicated user interface for specifying all kinds of options, which if not specified properly, may reduce the results to mush. Readers are hereby advised that if they encounter a CSV file which doesn't read in properly using INPUT CSV, they might need to avail themselves of such a wizard to load the file into a spreadsheet and then re-save it, possibly with a different delimiter. This will hopefully result in a CSV file which has the same ideas about "standard" as does INPUT CSV.

History

2011 May, A-Shell 5.1.1216: Support new custom CSV delimiter; see Get/Set CSV Delimited|topic=MIAMEX 181\: Get/Set CSV Delimiter. Also, expand the list of quoted characters—real and potential delimiters—to: comma, tab, semicolon, colon, quote, apostrophe, plus the custom delimiter character if applicable.


ALLOCATE

ALLOCATE fspec, blks

ALLOCATE creates a random file.

Parameters

fspec is file specification in native or AMOS format. If no extension is given, the default is .DAT. To create a file with no extension, terminate the filespec with a single period (".").

blks specifies the size of the file in 512 byte "blocks". Modern disks typically have much larger physical blocks sizes, so the 512 byte unit used here is just a historical hold-over from AMOS.

Comments

Random files must be created before they can be opened. In contrast, a sequential file is created automatically when it is opened for output.


FILEBASE

FILEBASE sets the record numbering basis.

FILEBASE fbase

Parameters

fbase is a literal value, typically 0 or 1, establishing the starting point for record numbering in all files opened subsequently. 0 is the default.


OPEN for random access

There are two variations of the OPEN statement for random-access files. This one is used for standard RANDOM and ISAM files:

OPEN #ch, fspec, mode, recsiz, recnovar {,WAIT'FILE}{,WAIT'RECORD}{,READ'ONLY}{,SPAN'BLOCKS}

And this one is used only for ISAM-A files.

OPEN #ch, fspec, mode, recsiz, recnovar, fstatvar {,END'FILE}{,WAIT'RECORD}{,WAIT'FILE}{,READ'ONLY}

Parameters

ch is an integer expression (>0) specifying the file channel which will be needed for subsequent I/O operations on the file.

fspec is a string expression specifying the file to open, using native or AMOS syntax.

mode may be one of the following:

RANDOM | when LOKSER enabled, requests exclusive access
RANDOM'FORCED | shared access
INDEXED or ISAM'INDEXED | ISAM shared access
INDEXED'EXCLUSIVE or ISAM'INDEXED'EXCLUSIVE | ISAM exclusive access
ISAMP'INDEXED | ISAM-A shared access; must use second form of OPEN statement above
ISAMP'INDEXED'EXCLUSIVE | ISAM-A exclusive access (" " " " )

recsiz is an integer expression specifying the record size—i.e. the number of bytes transferred in each subsequent READ and WRITE operations.

recnovar must be an F,6 variable which is used to specify the record number for READ and WRITE operations. For ISAM lookup operations, this variable will be automatically updated in preparation for the next READ. Also see MX_FLSET for details on handling this parameter within SBX routines, and XREAD, XWRITE for an alternative method of specifying the record number.

fstatvar must be an F,6 variable; it returns a status code after each ISAM-A operation.

WAIT'FILE, WAIT'RECORD and READ'ONLY have meaning only when LOKSER is enabled; otherwise they are ignored. WAIT'FILE causes the statement to wait until access can be granted. If requesting exclusive access, no other process may have the file open except for READ'ONLY. If requesting shared access, no other process can have the file open exclusively. Otherwise, if access cannot be granted, error 37 will be returned. WAIT'RECORD causes READ operations to wait if the requested record is locked, otherwise error 38 is returned. READ'ONLY disables LOKSER—and WRITE operations—for this file access session, and is useful when you're just going to be reading from the file and it isn't critical that the file isn't modified during the read operations. Also see ASFLAG.SBR for a way to achieve this effect without using the BASIC Plus compiler extensions.

SPAN'BLOCKS disables 512-byte blocking. This is a historical hold-over from AMOS, which performed random file access in 512 byte blocks and did not allow logical records to be split between two blocks. If the record size didn't divide evenly into 512, the remaining number of bytes would simply be unused at the end of each 512 byte block. In the worst case, a record size of 257 bytes would result in 255 out of every 512 bytes wasted. In SPAN'BLOCKS mode, records are adjacent with no wasted space between then and no consideration for how they map onto physical disk "blocks". 512-byte blocking remains the default, for compatibility with existing files, but serves no useful purpose in the modern world and is therefore deprecated. SPAN'BLOCKS is always recommended, except when compatibility with older file layouts is required. SPAN'BLOCKS is automatic when the record size is greater than 512.

END'FILE applies only to ISAM-A and causes the file "cursor" to start at the end of the index rather than at the start, so a subsequent GET'PREV operation will retrieve the last indexed record.


READ

READ #ch, recvar

reads a record from a random file without locking.

READL #ch, recvar

establishes an exclusive lock on the record before reading if LOKSER enabled. If the lock cannot be granted, the operation either waits or returns error 37, depending on whether the WAIT'RECORD clause was specified on the OPEN statement. To release the lock, you just either use a WRITE or UNLOKR statement.

READ'READ'ONLY #ch, recvar

an unlocked read, with no option to subsequently write.

READ var1{, var2...}

reads individual data fields from the DATA statement pool.

Comments

ch specifies the previously-opened file channel.

recvar is the variable to receive the entire record. Typically it is an unformatted MAP1 level variable or structure containing sub fields arranged to match the layout of the data record. See example below.

Comments

The record # for the read operation is established by setting the record number variable specified in the OPEN statement. Since the OPEN statement and subsequent READ statements may be widely separated, care must be taken that the record # variable remains in scope. See MX_FLSET for details related to reading from a file within an SBX. See XREAD and XWRITE for variations of READ and WRITE which specify an explicit record # for the operation, eliminating the interdependence on the external record # variable.

Record #'s start at 0 by default, but may be changed (typically to 1) using the FILEBASE statement.

Typically the size of the recvar should match the record size specified in the OPEN statement. However, if not, the READ operation works in the same was as an assignment statement, with the data read from the disk acting as the source expression. Thus if recvar is too small, the data is simply truncated to fit. If recvar is too large, the extra bytes are either left alone, assuming recvar is an unformatted type, i.e. X variable, or set to null, if recvar is a string.

Example

DEFSTRUCT ST_CUS ! 64 byte customer record definition

MAP2 ID,S,6

MAP2 NAME,S,30

MAP2 PHONES(2)

MAP3 OFFICE,S,10

MAP2 CELL,S,10

MAP2 ZONE,B,2

MAP2 BALANCE,F

ENDSTRUCT

MAP1 CUS,ST_CUS ! customer record instance

MAP1 CUSRECNO,F ! record #

OPEN #1, "CUST.DAT", RANDOM'FORCED, 64, CUSRECNO

CUSRECNO = 9 ! rec # 9

READL #1, CUS ! lock and read rec

CUS.BALANCE += 1 ! modify rec

WRITE #1, CUS ! write (and unlock) rec

See Also

• XWRITE and XREAD


UNLOKR

UNLOKR #ch

Parameters

ch is an integer identifying the file; established by the OPEN statement.

Comments

UNLOKR has no effect if LOKSER not enabled, or if the current record number is not locked. The record number to unlock is determined by the contents of the record-number variable specified in the OPEN statement. Records are locked by the READL statement, and if not unlocked by a subsequent WRITE, should be unlocked by UNLOKR. Closing the file also unlocks all locked records.


WRITE

WRITE #ch, recexpr

WRITEL #ch, recexpr

The difference between WRITE and WRITEL has to do with record locking and only applies when LOKSER is enabled. WRITE writes a record and unlocks it afterwards so that it can be modified by another process. It assumes that the record was previously read with READL. WRITEL establishes a lock first and then writes. It is used for writing records that were not previously locked.

Parameters

recexpr is an expression containing the data to write. Typically it is the same record variable or structure used in the READ statement, but could technically be any expression, provided its length does not exceed the record size specified in the OPEN statement. If the length of recexpr is less than the record size, the remaining bytes in the target record on disk will not be modified.

Comments

See the READstatement topic for comments regarding the record number which apply here as they do for READ.

Example

See READ.

See Also

• XREAD, XWRITE


XREAD, XWRITE

Revised and reviewed May 2012

In A-Shell build 1107 of April 2008, new "eXplicit" variations of READ and WRITE statements were added:

XREAD #CH, RECNO, VAR {,VAR2...,VARN}

XREADL #CH, RECNO, VAR {,VAR2...,VARN}

XREAD'READ'ONLY #CH, RECNO, VAR {,VAR2...,VARN}

XWRITE #CH, RECNO, VAR {,VAR2...,VARN}

XWRITEL #CH, RECNO, VAR {,VAR2...,VARN}

XWRITEN #CH, RECNO, VAR {,VAR2...,VARN}

XWRITELN #CH, RECNO, VAR {,VAR2...,VARN}

These are equivalent to the standard versions of these statements (without the "X" and without the RECNO variable), except that instead of getting the record number implicitly, from the variable specified in the OPEN statement, the record number is specified, eXplicitly, in the statement.

While the "X" versions of the READ and WRITE file operations can be used in any context without penalty, there are two specific situations where they are extremely advantageous:

• Within SBX routines, where they eliminate the need to use MX_FLSET to reset the address of the record number variable stored in the file's control structure. See Accessing Open Files for more information.

• In parameterized/generic file operations where you don't know the record size at the time of writing the code. The standard variations of the WRITE statements will abort with a "record size overflow" error if the record variable specified in the WRITE is larger than the record size specified in the OPEN. The XWRITE variants avoid this limitation by automatically truncating the specified record variable to match the record size specified in the OPEN statement.


TRACE and DEBUG Statements

Documentation (not function) added October 2011

This group of statements is useful for outputting tracing or debugging messages without interfering with the existing screen display or program logic. (The messages go to the Debug Message Window; see Opening the Message Window.

TRACE.OPEN <string expression>

TRACE.PRINT <string expression>

TRACE.PAUSE <string expression>

TRACE.CLOSE

DEBUG.OPEN

DEBUG.PRINT

DEBUG.PAUSE

DEBUG.CLOSE

TRACE.OPEN is optional, since the TRACE.PRINT and TRACE.PAUSE statements will open the window automatically if it is not already open. The only point of it would be the ability to set the window title (which otherwise defaults to "A-Shell Debug Messages").

TRACE.PRINT <text> outputs the specified text to the debug window. The text string may contain the following special macros:

$# (displays the running message count as a message id #)

$T (displays the time in HH:MM:SS format)

$P (displays the program name in brackets, e.g. <MYPROG>)

For example, the following statement

TRACE.PRINT "$# $T $P The value of X is: " + X

would appear something like:

27 11:25:01 <MYPROG> The value of X is: 25

TRACE.PAUSE is identical to TRACE.PRINT except that it causes the application to pause, with a message in the debug message window prompting the operator:

<Application paused - Double-click here to resume>

As suggested by the message, the application is then suspended while waiting for the user to double-click the message window. This is intended as alternative to the usual practice of display message boxes which require a click on the OK button to proceed (or the venerable and primitive STOP statement). Note: Ctrl+C will abort the pause and pass the Ctrl+C to the program.

The actual wording of that message and the acknowledgement message when the double-click is received may be customized via the strings 005,002 and 005,003 in SYS:SYSMSG.xxx.

The DEBUG.xxx statements are equivalent to the TRACE.xxx statements, except that they are ignored if the DEBUG flag is not set. The DEBUG flag may be set via the SET.LIT command, the MX_DEBUG call, or by clicking on the Set Debug Mode option in the Debug Message Window context menu:

this is a linked image

See also

The description of the DEBUG system variable in the A-Shell Extensions table.

EVTWIN.SBR


ISAM Statements

ISAM statements have the form:

ISAM #ch, code, key

Parameters

ch (Num) [in]

Channel number specified in the OPEN statement for the file. Note that a single channel is used for the combination of the IDA and the primary IDX. Secondary IDX files have their own channels.

key (String) [in/out]

A symbolic key

code (Num) [in]

A numeric code 1-8 indicating the operation to perform.

Code | Operation | Description
1 | Lookup | Searches the IDX file associated with CH for the specified KEY. If not found, returns ERF(ch) = 33. Else returns ERF(ch) = 0 and sets the relative record number variable (from the OPEN statement) to match the found record.
2 | Get Next | Performs a get-next operation based on index position left by the previous 1, 2, or 7 statement. Sets the relative record number variable to match the fund record. Sets ERF(ch) to 38 if no more keys in sequence. KEY is not used. Generally superseded by code 7.
3 | Add Key | Adds the specified key to the index, associating it with the record number currently stored in the record number variable.
4 | Delete Key | Deletes the specified key from the index.
5 | Add Record | Allocates/assigns a new record in the IDA file, returning its relative record number in the record number variable. Must be followed by a WRITE{L} #ch, rec statement to actually write the record data to the file.
6 | Delete Record | Deletes the record specified by the relative record number variable from the IDA file (adding it back to the deleted record chain so that it may be reused).
7 | Get Next | Same as code 2 except returns the found next key in the KEY variable.
8 | Get Previous | A-Shell extension, added in 6.1.1344.0. Reverse of code 7. Returns ERF(ch) = 38 if no more keys (i.e. when you hit the start of the index).

Error processing

Each of the ISAM statements returns a status which you should check using the ERF(ch) function. The range of values is given in the table below:

ERF(ch) value | Meaning
32 | Illegal ISAM statement code
33 | Key not found during key lookup
34 | Duplicate key during attempt to add key. Note that duplicate keys not supported by ISAM 1.x.
35 | IDX is corrupted and must be recreated.
36 | IDX file full. You've disabled the auto-expand feature (see NOAUTOX option), the disk is full, or you've reached the maximum limit of 4 billion IDX blocks.
37 | IDA file full. You've disabled the auto-expand feature (see NOAUTOX), the disk is full, or you've reached the maximum limit of 4 billion records.)
38 | End of file reached during get-next key operation, or start of file reached during get-previous key operation
39 | Illegal ISAM sequence. See File Locking below.

File Locking

You must employ some kind of file locking system when allowing multi-user access to ISAM files (i.e. when the files are opened in INDEXED rather than INDEXED'EXCLUSIVE mode). Unlike ISAM-A, ISAM 1.x provides you the latitude (and responsibility) to implement the locking system. However, when LOKSER is enabled, it will be used and certain rules will be enforced (with violations resulting in ERF(ch) returning error 39). The following table summarizes the ISAM /LOKSER behavior and rules:

Stmt Code | Operation | Primary IDX | Secondary IDX
1, 2, 7, 8 | Locate record by key | Locked automatically and remains locked on return | Locked automatically during operation but unlocked on return
3 | Add key | Must be locked initially (typically from a previous locate record operation). Unlocked on return | Locked automatically during operation; unlocked on return
4 | Delete Key | Must be locked initially and remains locked on return | Locked automatically during operation; unlocked on return
5 | Add Data Rec | Must be locked initially; remains locked on return | N/A
6 | Delete Data Rec | Must be locked initially; remains locked on return | N/A
READ | read data | Must be locked initially; unlocked on return | N/A
READL | read/lock (for update) | Must be locked initially; remains locked on return | N/A
WRITE | write/update data | Must be locked initially; unlocked on return. | N/A
WRITEL | write new data | Must be locked initially; remains locked on return. (Normally followed by Add Key which unlocks) | N/A
LOCK | Lock primary index | Locked by operation | N/A
UNLOKR | Unlock record and/or index | Unlocked by operation (no harm if already unlocked) | N/A

Examples

The following samples illustrate some typical operations on an ISAM file with a single primary IDX. For simplicity, all the examples use a generic routine called ISAM'ERROR for any unexpected errors. The routine should always start with an UNLOKR #CH to make sure the file isn't left in a locked state.

Add Record:

ISAM #CH, 1, KEY ! lookup key

IF ERF(CH) = 0 THEN

? "Record already exists"

UNLOKR #CH

ELSEIF ERF(CH) # 33 THEN ! any state other than not-found

GOTO ISAM'ERROR

ELSE

ISAM #CH, 5, KEY ! add a data record

IF ERF(CH) # 0 THEN

GOTO ISAM'ERROR

ELSE

WRITEL #CH, REC ! write the data

ISAM #CH, 3, KEY ! add the key

IF ERF(CH) # 0 THEN

GOTO ISAM'ERROR

ENDIF

ENDIF

ENDIF

Delete Record:

ISAM #CH, 1, KEY ! lookup key

IF ERF(CH) = 33 THEN

? "Record doesn't exist"

UNLOKR #CH

ELSEIF ERF(CH) # 0 THEN

GOTO ISAM'ERROR

ELSE

READL #CH, REC ! read/lock the record

ISAM #CH, 4, KEY ! delete key

IF ERF(CH) # 0 THEN

GOTO ISAM'ERROR

ELSE

ISAM #CH, 6, KEY ! delete the data record

IF ERF(CH) # 0 THEN

GOTO ISAM'ERROR

ENDIF

ENDIF

ENDIF

History

2013 March, A-Shell 6.1.1344: Add new get'previous statement: ISAM #CH, 8, KEY.


OPEN

OPEN #channel, filespec, mode, recno, fstat {,end'file} {, wait'record} {,wait'file} {,read'only}

Opens the file. (Note that while internally there may be multiple physical files, from BASIC, the combination of the data file and index is treated as a single file. Unlike old ISAM, there is no need or possibility of opening up additional index files.)

channel

expression or variable evaluating to an integer, which will be used to identify all other operations on related to this open.

filespec

name of the file (without any extension).

mode

must be one of the following:

Open Mode | Meaning
INDEXED | Normal shared open. If file is already open by another user exclusively, job will wait (if the wait'record option specified) or receive BASIC error 37 (file in use).
INDEXED' EXCLUSIVE | Open for exclusive use. If file is already open by another user in any mode, job will wait (if the wait'record option specified) or receive BASIC error 37 (file in use).
ISAMP' INDEXED | Same as INDEXED but forces operation to be interpreted as an ISAM-A open rather than an ISAM open, regardless of the COMPIL mode. Otherwise the COMPIL mode will determine whether to assume old ISAM or ISAM-A.
ISAMP'INDEXED' EXCLUSIVE | Same as INDEXED'EXCLUSIVE but forces operation to be interpreted as an ISAM-A open rather than an ISAM open, regardless of the COMPIL mode.

recno (floating point)

holds the current record number. Normally, you never need to do anything explicitly with this variable since all operations are based on the index, but it will be set to the data record number after each successful index operation, and is used as input to the record deletion and update operations.

fstat (floating point)

set to indicate the status of most operations, from the following table:

Symbol | Value | Meaning
ISAM_NF | -3 | Not found
ISAM_NA | -2 | Not available (record locked)
ISAM_LT | -1 | Key found which is less than specified key
ISAM_EQ | 0 | Key found equal to specified key
ISAM_OK | 0 | OK
ISAM_GT | 1 | Key found greater than specified key
ISAM_DK | 2 | Duplicate key error in CREATE’RECORD (if AF_ISAMNODUPERRS set)

The remaining parameters are all optional modifiers and may be specified in any order:

Open Modifier | Meaning
end'file | Positions the internal index pointer at the end of the primary index, rather than at the beginning (so that a GET'PREV or FIND'PREV will return the last record in the index).
wait'record | If an attempt is made to read a locked record, the program will wait until the record is freed.
wait'file | Causes the OPEN operation to wait until the file is available (instead of returning error 37 if it is not).
read'only | Indicates that the file will only be accessed for read operations. Attempts to perform updates will fail with an error.


CLOSE

CLOSE #channel

channel

an expression or variable matching that used to open the file. Files should be closed explicitly, although BASIC will perform a forced closed on any file left open when the program ends.


GET, GET'LOCKED, GET'READ'ONLY

A-Shell BASIC > Statements > I/O Statements > ISAM-A Statements
GET, GET’LOCKED, GET’READ’ONLY

GET #channel, {wait’record,} isam’key(knum) rel kval, varlist

The various forms of the GET statement are used to directly locate and read a record based on a key value. Logically this may be considered a combination of two operations: one to lookup the key and the other to read the record.

channel

the integer expression whose value matches that specified in the OPEN statement.

The optional wait’record clause causes the operation to wait until the record is available (just as if wait'record was specified in the OPEN statement.)

knum

integer expression indicating which logical index to search in. The primary index is 0, the first secondary index is 1, etc.

rel

is one of the following logical comparison operators, relating the key to be found with the key specified:

Relation | Meaning
< | less than
<= | less than or equal
= | equal
> | greater than
>= | greater than or equal

kval

an expression indicating the key to start for in the specified index.

varlist

a list of variables to receive the data. (Although it is technically legal to list several variables, the recommended approach is to specify a single unformatted record variable which is broken into fields by means of lower level MAP statements.)

The fstat variable (from the OPEN statement) will be set according to the key found (or not found). If the key is found, the recno variable will also be set to the record number (although as mentioned before, you don't need to do anything with this information).

For example:

GET'LOCKED #CUS'CHANNEL, WAIT’RECORD, KEY(0) >= "BIG", CUS'REC

The above statement will search the primary index for the record whose key is greater than or equal to "BIG", and if successful, will lock and return the record in the CUS'REC variable and set the Fstat variable (from the OPEN statement) accordingly. To remove the lock, you will need to perform a RELEASE'RECORD or DELETE'RECORD. If the record is found, but is currently locked, then the program will wait.


GET'NEXT Statements

GET'NEXT #channel, {wait’record,} varlist

GET'NEXT'LOCKED #channel, {wait’record,} varlist

GET'NEXT'READ'ONLY #channel, {wait’record,} varlist

These statements are similar to the corresponding GET, GET'LOCKED, and GET'READ'ONLY statements, except that instead of locating the record directly, by means of a specified key value, they simply get the next record based on the order of the index last specified in a GET or FIND statement.

The fstat status variable (from the OPEN statement) will be set to ISAM_NF if there are no more records in index order, or ISAM_NA if the found record is locked, or ISAM_EQ for success.


GET'PREV Statements

GET'PREV #channel, {wait’record,} varlist

GET'PREV'LOCKED #channel, {wait’record,} varlist

GET'PREV'READ'ONLY #channel, {wait’record,} varlist

These statements are identical to the corresponding GET'NEXT statements except instead of getting the next (i.e. higher) record in the index, they get the previous (i.e. lower) record in the index.

The fstat status variable (from the OPEN statement) will be set to ISAM_NF if there are no more records in index order, or ISAM_NA if the found record is locked, or ISAM_EQ for success.


FIND Statements

These statements are similar to GET and GET’NEXT statements except that they only operate on the index. They do not transfer any data. They are used to traverse or position the internal pointer into a specific index, after which you can use GET'NEXT or GET'PREV statements to access the data sequentially from that point.

FIND #channel, isam’key(knum) rel kval, retkey

FIND’NEXT #channel, retkey

FIND’PREV #channel, retkey

Retkey is a variable which will receive the located key (if the operation is successful). The variable should be of the correct size and type to match the specified index.

For the FIND statement, the fstat status variable (from the OPEN statement) can be set to any of the values listed in the table of status values with the OPEN statement, except for ISAM_NA. (Since it doesn't try to read the data record, it cannot get a record-locked status).

For the FIND'NEXT and FIND'PREV statements, the only possible values to be returned for fstat are ISAM'NF (meaning you hit the end of the index) or ISAM'EQ (found).

Examples:

FIND #CUS'CH, ISAM’KEY(1) >= "BIG", RET’KEY

FIND’NEXT #CUS'CH, RET'KEY

FIND’PREV #CUS'CH, RET'KEY


UPDATE'RECORD

A-Shell BASIC > Statements > I/O Statements > ISAM-A Statements
UPDATE’RECORD

UPDATE’RECORD #channel, varlist

This statement rewrites a previously locked record and updates all indexes accordingly.

The recno variable (from the OPEN statement) determines which record will be updated. Normally it is set automatically by a GET operation with the LOCKED option. However, it could also be set manually, or via an ISAM'POP statement.

Because failed GET and NEXT operations do not update the recno variable, you should always check the value of the status variable after these operations to avoid inadvertently updating the wrong record.

If the record specified by the recno value is not currently locked, the attempted UPDATE'RECORD will generate BASIC error 42 (record not locked).

UPDATE'RECORD does not release the lock on the record. So normally you would follow it with a RELEASE'RECORD operation.

The UPDATE'RECORD operation performs all necessary index operations so that the indexes match the updated data.

All errors trap (as BASIC errors).

Update Note: Build 899.1.4 of 09 Sept 04

The UPDATE'RECORD statement now generates a Basic error #231 instead of merely returning status -3 when there is an error in updating one of the index files. This could potentially interrupt programs which were already checking for this condition, but given that a similar error in the GET statement generates the same error, and that it is highly unlikely that there is any appropriate response to such a condition other than rebuilding/verifying the index(es), it seems appropriate to generate a Basic error here (that can't be ignored).


DELETE'RECORD

A-Shell BASIC > Statements > I/O Statements > ISAM-A Statements
DELETE’RECORD

DELETE’RECORD #file-channel

DELETE'RECORD is similar to UPDATE'RECORD except that it deletes the record (and all associated keys) rather than updating it. Like UPDATE'RECORD, it relies on the record being locked and the recno variable being set (normally by a previous GET operation with the LOCKED option).

Unlike UPDATE'RECORD, it is not necessary to manually delete the lock.

All errors trap (as BASIC errors).


CREATE'RECORD

A-Shell BASIC > Statements > I/O Statements > ISAM-A Statements
CREATE’RECORD

Updated July 2014; added Comments and History

CREATE’RECORD #channel, varlist

CREATE'RECORD adds a new record to the file and updates the indexes accordingly. All errors are trapped as BASIC errors.

Comments

The most likely error during CREATE'RECORD would be an attempt to add a record with a duplicate key, assuming duplicates not allowed. Normally this will trigger BASIC error 208, but you can stifle the BASIC error and instead get back the status value 2 (in the fstat parameter specified in the OPEN statement) by setting the AF_ISAMNODUPERRS flag in ASFLAG.SBR.

History

2012 October, A-Shell 6.1.1313: Add support for AF_ISAMNODUPERRS


RELEASE Statements

RELEASE’RECORD #channel {,recordnumber}

RELEASE’ALL #channel

RELEASE'RECORD releases the lock on the previously accessed record, or the record number specified.

Note that you need to use RELEASE'RECORD after an UPDATE'RECORD, since the latter does not release the lock itself.


ALLOCATE'INDEXED

ALLOCATE'INDEXED fspec, allocate'map

ALLOCATE'INDEXED creates a new ISAM-A file (as an alternate to using ISMUTL.LIT). The allocate'map structure contains the configuration details needed to create the file, and must be customized, based on the following:

MAP1 ALLOCATE'MAP

MAP2 ERROR'OFFSET,B,2,-1 ! Offset if error

MAP2 MAX'RECS,B,4 ! (ignored)

MAP2 REC'SIZE,B,2 ! total record size

MAP2 EXTRA'PCT,B,2 ! extra IDX blocks (ignored)

MAP2 LOADING'FACTOR,B,1,100 ! loading factor (ignored)

MAP2 RESERVED0,X,11 ! reserved for future

MAP2 VARIABLE'REC'SIZE,B,2 ! size of variable portion of rec

MAP2 PRIMARY'KEY ! primary key definition

<see key definition structures below>

MAP2 SECONDARY'KEY ! zero or more secondary key definitions

<see key definition structures below>

MAP2 ALLOCATE'END,B,2,0 ! marks end of key definitions

The layout of the PRIMARY'KEY and SECONDARY'KEY sub-structures should be mapped according to one of the following models, based on the key type:

Alphanumeric Key Definition

MAP2 KEY'ALPHANUMERIC

MAP3 KEY'TYPE,B,1,1 ! 1=alphanumeric

MAP3 KEY'RESV(3),B,1 ! reserved for expansion

MAP3 KEY'NAME,S,20 ! name of key (ignored)

MAP3 KEY'NULL1,B,2,0 ! null terminator for name

MAP3 KEY'DUP,B,1 ! sum of 1=duplicates allowed,

! 2=compress dupes, 4=leading, 8=trailing

MAP3 KEY'CHG,B,1 ! key change permitted (ignored)

MAP3 KEY'SIZE,B,2 ! size of key in chars

MAP3 KEY'POS,B,2 ! key pos (1=first byte)

Signed Integer Key Definition

MAP2 KEY'INTEGER

MAP3 KEY'TYPE,B,1,2 ! 2=integer

MAP3 KEY'RESV(3),B,1 ! reserved for expansion

MAP3 KEY'NAME,S,20 ! name of key (ignored)

MAP3 KEY'NULL1,B,2,0 ! null terminator for name

MAP3 KEY'DUP,B,1 ! 1=duplicates allowed

MAP3 KEY'CHG,B,1 ! key change permitted (ignored)

MAP3 KEY'SIZE,B,2 ! size of key in bytes (2 or 4)

MAP3 KEY'POS,B,2 ! key pos (1=first byte)

Unsigned Binary Key Definition

MAP2 KEY'BINARY

MAP3 KEY'TYPE,B,1,4 ! 4=binary

MAP3 KEY'RESV(3),B,1 ! reserved for expansion

MAP3 KEY'NAME,S,20 ! name of key (ignored)

MAP3 KEY'NULL1,B,2,0 ! null terminator for name

MAP3 KEY'DUP,B,1 ! 1=duplicates allowed

MAP3 KEY'CHG,B,1 ! key change permitted (ignored)

MAP3 KEY'SIZE,B,2 ! size of key in bytes (1-5)

MAP3 KEY'POS,B,2 ! key pos (1=first byte)

Concatenated Key Definition

MAP2 KEY'CONCAT

MAP3 KEY'TYPE,B,1,3 ! 3=concatenated

MAP3 KEY'RESV(3),B,1 ! reserved for expansion

MAP3 KEY'NAME,S,20 ! name of key (ignored)

MAP3 KEY'NULL1,B,2,0 ! null terminator for name

MAP3 KEY'DUP,B,1 ! 1=duplicates allowed

MAP3 KEY'CHG,B,1 ! key change permitted (ignored)

MAP3 SUBKEY(?) ! 1 or more subkeys

MAP4 SUBKEY'SIZE,B,2 ! size of subkey in chars

MAP4 SUBKEY'POS,B,2 ! subkey pos (1=first byte)

MAP3 KEY'END,B,2 ! terminate list of subkeys


INDEXED'STATS

Updated May 2008

INDEXED'STATS #channel, stats'map

INDEXED'STATS fspec, stats'map

INDEXED'STATS retrieves information about an existing file, either based on its open channel number or its filespec. The layout of the stats'map variable depends on the number of type of indexes, which you must therefore know in advance. (If you don't know, you can always use ISMUTL.LIT to retrieve statistical information.)

The stats'map layout is as follows:

MAP1 ISAM'STATS'MAP

MAP2 IS'DATA'DEVICE,B,2,0 ! RAD50 device name of DAT

MAP2 IS'DATA'UNIT,B,2,0 ! Device unit number of DAT

MAP2 IS'REC'SIZE,B,2 ! total record size

MAP2 IS'FREE'RECS,I,4 ! free rec count (100 million)

MAP2 IS'FREE'IDX,I,4 ! free IDX flock count

MAP2 IS'TOT'RECS,I,4 ! total allocated records (100 million)

MAP2 IS'TOT'IDX,I,4 ! total allocated idx blocks

MAP2 IS'TOT'LOADED,I,4 ! # records loaded

MAP2 IS'MIN'FREE'IDX,B,2 ! minimum free idx blocks

MAP2 IS'EXTRA'PCT,B,2 ! extra % idx blocks to allocate

MAP2 IS'CREATE'DATA ! creation date

MAP3 IS'CREATE'MONTH,B,1

MAP3 IS'CREATE'DAY,B,1

MAP3 IS'CREATE'YEAR,B,1

MAP3 IS'CREATE'DOW,B,1

MAP2 IS'SECOND'IDX,B,1 ! number of secondary indices

MAP2 IS'REBUILD'DATA ! rebuild date (not used)

MAP3 IS'REBUILD'MONTH,B,1

MAP3 IS'REBUILD'DAY,B,1

MAP3 IS'REBUILD'YEAR,B,1

MAP3 IS'REBUILD'DOW,B,1

MAP2 IS'RESERVED(8),B,1 ! reserved for expansion

MAP2 IS'PRIMARY'KEY'STATS ! primary key stats

<use same key structures as for ALLOCATE'INDEXED above>

MAP2 IS'SECONDARY'KEY'STATS ! 0 or more secondary keys

<use same key structures as for ALLOCATE'INDEXED above>

MAP2 IS'END,B,2,0 ! marks end of key definitions

Note: When compiling without the /X:# switch, the I,4 variables shown above will have to be changed to B,4. This is an unfortunate side effect of retaining compatibility with the AlphaBASIC and AlphaBASICPlus variations of indexed'status under AMOS. Under AlphaBASIC (OCMPIL and COMPIL), the four-byte fields in the above structure were type B, while under BASICPlus (COMPLP), they were type I. This remains true under A-Shell, but seems even more confusing because A-Shell makes less of a distinction between the two variations of BASIC. (They use the same RUN.LIT and COMPIL.LIT, with the only difference being whether the COMPIL switch /X:# was specified.) Unfortunately, the format of B and I variables is not the same (the low and high words are swapped), so a common bug when migrating older code to use BASIC Extensions is to forget to remap these B,4 variables to I,4, leading to wildly incorrect values. Programmer beware!


ISAM'PUSH and ISAM'POP

ISAM'PUSH #channel

ISAM'POP #channel

ISAM'PUSH and ISAM'POP are extensions only available in A-Shell (and which require the COMPIL /X:2 switch). They allow you to save, and later restore, the current index cursor context. This is particularly handy when, while traversing an index which includes duplicate keys, you need to make a detour involving some other index operations on the same file, before continuing from where you were. Without these operations, you would instead have to manually reposition yourself within the index, which, if duplicates are involved, would require scanning through the duplicates until you hit the record where you were, based on the record number. (There is no other way to go directly to a particular key among a group of duplicate keys.)

Specifically, the context attributes that are saved and restored are:

• The index number (if there are multiple indexes for the file)

• The cursor position within the index

• The value of the recno variable.

Note that ISAM'PUSH and ISAM'POP do not affect record locks. Thus, if you lock a record before using ISAM'PUSH, it remains locked, and will still be locked when you use ISAM'POP. However, the contents of the record data variable (aka varlist) is not saved or restored, so you must take care to either save your own copy, or to make sure that your record data variable contains the desired contents before you update the record.

Note also that ISAM'PUSH uses the current record number according to the record number variable in the open statement, as opposed to the one last saved inside the ISAM library. The problem with the superceded method was if the ISAM'PUSH did not immediately follow another operation on the same file, some intervening ISAM operations to other files could disrupt the state information within the ISAM library, causing the ISAM'PUSH to not push the proper location.

Example:

GET'NEXT'LOCKED #AROPEN'CH, WAIT'RECORD, AROPEN'REC

SAVE'AROPEN'REC = AROPEN'REC ! save copy of locked rec

ISAM'PUSH #AROPEN'CH

CALL SCAN'FOR'OTHER'AROPEN'RECS ! (unknown processing)

ISAM'POP #AROPEN'CH ! restore our index context

AROPEN'REC = SAVE'AROPEN'REC ! restore our saved data rec

AROPEN'UPDATED = 1 ! change some data

UPDATE'RECORD #AROPEN'CH, AROPEN'REC ! update the rec

RELEASE'RECORD #AROPEN'CH ! and release the lock


TRANSACTION'LOG Statements

TRANSACTION'LOG'OPEN logspec

TRANSACTION'LOG'CLOSE

These are extensions only available in A-Shell (and which require the COMPIL /X:2 switch). TRANSACTION'LOG'OPEN opens a log file of the specified name (native or AMOS syntax, default extension is ITL for ISAM Transaction Log). Any file opened after the log file is opened in the current program will automatically have all its update operations logged to the file. This is a prerequisite for the TRANSACTION'BEGIN, TRANSACTION'COMMIT, and TRANSACTION'ROLLBACK operations.

TRANSACTION'LOG'CLOSE closes the current log file. If not done explicitly, it will be done implicitly at the end of the program.

See the discussion on Transactions and Logging for more details.


TRANSACTION Statements

TRANSACTION'BEGIN

TRANSACTION'COMMIT

TRANSACTION'ROLLBACK

These are extensions only available in A-Shell (and which require the COMPIL /X:2 switch). Together they allow you to implement "transactions" (which are logical operations involving multiple physical operations on one or more files which should be done as a logical unit, i.e. either all or nothing).

TRANSACTION'BEGIN marks the beginning of the transaction.

TRANSACTION'COMMIT marks the successful end of the transaction.

TRANSACTION'ROLLBACK aborts the transaction, discarding all changes since the TRANSACTION'BEGIN operation.

Note that while you may operate on any number of files between the TRANSACTION'BEGIN and either the TRANSACTION'COMMIT or TRANSACTION'ROLLBACK, only those ISAM-A files which were opened after the TRANSACTION'LOG'OPEN will be affected by the transaction statements. Any operations to other files will take place normally and immediately, just as they would in the absence of the transaction statements.

See the discussion on Transactions and Logging for more details.


AMOS

AMOS {/switch} <command>

Invokes an "AMOS" command from within BASIC. Similar to AMOS.SBR. The optional /switch may be /T or /S to either force tracing or silencing of all output (same idea as :T and :S in CMD/DO files). If omitted, the default is to display the output of commands but not the commands themselves (like :R).


CALL

CALL <label> ! traditional routine (GOSUB)

CALL <procedure>(<param list>)

CALL <function>(<param list>)

The CALL statement may be used to call traditional BASIC subroutines, in which case it is equivalent to GOSUB, as well as to call structured Procedures and User-Defined Functions.

Examples:

CALL HELP ! equivalent to GOSUB HELP

call Print'Cus'Addr'Label(CUSTNO, CH) ! procedure

Call Fn'Status'Message$(code) ! function


EXIT

The EXIT statement may be used within a control structure (For ... Next, Do/While/Until, Switch) to exit the structure, proceeding to the next statement following the end of the structure. For example:

DO WHILE A < B

...

IF TIME > 82800 EXIT ! exit loop after 11 PM

...

LOOP


GOSUB

The GOSUB statement is used to call a "traditional BASIC subroutine". It is essentially equivalent to a GOTO (to the label at the start of the subroutine), with an internal stack marker used so that the next occurrence of a RETURN statement causes execution to proceed with the statement following the GOSUB. For example:

SECS = 4

GOSUB TARRY ! same as CALL TARRY

PRINT "LET'S GO!"

...

TARRY:

SLEEP SECS

RETURN

Note that in "modern BASIC", structured procedures are generally preferable to GOSUB routines, since they allow parameter passing and local variables, eliminating the need for global variables such as the SECS variable in the example above.

Also note that the keyword CALL, while used to call Functions and Procedures, may be used in place of GOSUB to call traditional subroutines like the one above.


REPEAT

REPEAT is similar to EXIT in that it can occur inside a DO LOOP or FOR/NEXT loop; it causes the control to transfer to the next iteration of the current loop without executing any remaining statements in the body of the current loop. For example:

TOT = 0

FOR I = 1 TO 10

IF I = 5 REPEAT

TOT = TOT + I

NEXT I

The above loop would set TOT to the sum of all the numbers 1 through 10, except 5.

As of A-Shell build 958 of 15 June 2006, the compiler supports REPEAT statement when compiling in X:1 or X:2 (BasicPLUS) or /RC mode.


RETURN

RETURN | ! from traditional subroutine
RETURN (<expression>) | ! from SBX, setting return function value

In the first case—when used without any arguments—RETURN transfers control back to the statement following the last GOSUB, i.e. returns from a traditional BASIC subroutine.

The second case—when followed by an expression—can be used optionally prior the end of an SBX routine to push a value on to the expression stack, allowing the SBX routine to be called as a function using XFUNC (which see, along with Call SBX as a Function, for details). Note that if the SBX routine is called by the XCALL or VXCALL statements, the RETURN <expression> statement will be treated as the equivalent of END, which returns to the caller without any value pushed on the expression stack.


Control Structures

ASB supports the typical range of control structures (aka loops, conditionals, code blocks) for controlling and organizing your logic, described in the following sections.

Subtopics

IF

IF … ENDIF

IFELSE

SWITCH

FOR … NEXT

FOREACH

DO / WHILE / UNTIL


IF

IF <condition> {THEN} <statements> {ELSE <statements>}

This is the original if statement supported by the first version of AlphaBASIC. Multiple statements were possible in both the then and else clauses, but all had to be combined into a single logical line using colons to separate the statements and ampersands to continue on to subsequent physical lines. Although inelegant, the this form of if statement was often combined with the goto statement in early AlphaBASIC to create primitive loops. Now deprecated, this primitive form of the if statement has been superseded by the more powerful and elegant if...endif construction.

Compatibility: Supported in all versions of the compiler. A-Shell implementation matches the AMOS implementation at both the source and RUN level.

Example

if TOTAL > CREDIT'LIMIT goto LIMIT'EXCEEDED

if CHROMO = XY then &

SEX = “M” : ? “It's a boy” &

else SEX = “F” : ? “It's a girl”


IF … ENDIF

IF <condition> {THEN}

<statements>

{ELSEIF <condition>

<statements>

{ELSE

<statements>

ENDIF

This newer form of block-structured if statement was originally introduced in AlphaBASIC Plus, and later extended by A-Shell build 1125 to support the elseif clause. Advantages over the original if statement include:

• No need to use colons to separate statements or ampersands to continue on to additional lines.

• For conditions that divide more than two mutually exclusive ways, you can use as many optional elseif clauses as you need.

• Ability to nest statements (including other if..endif or other control structures within the clauses.)

Compatability: requires /X:2 or /RC. A-Shell implementation is compatible with the BASIC Plus version at the source code level, except for the elseif clause which is an A-Shell extension.

Example

if COST < 10 then

PAY'METHOD = PM_CASH

PETTY'CASH -= COST

elseif COST < 100 then

PAY'METHOD = PM_CHECK

CHECKING'ACCOUNT -= COST

elseif COST < 1000 then

PAY'METHOD = PM_CREDIT

else

CALL BUY'LOTTERY'TICKET

if TICKET = WINNER then

CALL GET'AN'ACCOUNTANT()

else

CALL ROB'BANK()

endif

endif

Comments

The compiler determines whether an if statement is of the original or new (block-structured form) by whether there is a statement following the condition prior to the end of the logical line. It is possible to insert old-style if statements into the body of new-style if..endif statements, but this goes against most tenets of style.

Once you get more than a couple of elseif clauses, you may find the conceptually-equivalent switch statement to be a better match.

Beware: elseif (one word) and else if (two words) are not equivalent! The former marks the beginning of a/another mutually exclusive conditional clause that ends with either the next elseif, else, or endif. The latter marks the beginning of an else clause, and within that clause, starts a new if statement.

Subtopics

ELSEIF Clauses


ELSEIF Clauses

Beginning with A-Shell build 1125 of September 2008, one or more ELSEIF clauses may be inserted into an extended IF/ELSEIF/ELSE/ENDIF statement (in /RC or /X:2 modes), e.g.:

IF <expr1> THEN

<statements>

ELSEIF <expr2> THEN

<statements>

ELSEIF <expr3> THEN

<statements>

ELSE

<statements>

ENDIF

Previously, to accomplish the same thing you would have had to use nested IF/ELSE/ENDIF clauses, e.g.:

IF <expr1> THEN

<statements>

ELSE

IF <expr2> THEN

<statements>

ELSE

IF <expr3> then

<statements>

ELSE

<statements>

ENDIF

ENDIF

ENDIF

The ELSEIF version is mainly just cleaner and easier to follow.


IFELSE

Added October 2016

IFELSE(cond, expr1, expr2)

IFELSE$(cond, expr1, expr2)

These functions are conveniences which can often eliminate the need for a temporary variable or duplication of statements that differ only by a single either/or choice.

Each takes a conditional expression (cond) and two value expressions (expr1 and expr2). If the conditional expression evaluates to TRUE, then the function returns the value of expr1, else it returns the value of expr2. IFELSE returns a numeric value and IFELSE$ returns a string value.

Examples

Consider the case where you want to print a value with one of two masks depending on whether the value is less than 1. You might code it like this:

if VALUE >= 1 then

PRINT VALUE USING "#####"

else

PRINT VALUE USING "#.###"

endif

With the IFELSE$() function, you can eliminate the IF statement and reduce the two PRINT statements to one:

PRINT VALUE USING IFELSE$(VALUE>=1,"#####","#.###")

Or, in the case of larger statements where you are more likely to introduce temporary variables than to repeat variations of the statement, IFELSE() can eliminate the need for a temporary variable, e.g.

if flag'disable then

CSTATE = MBST_DISABLE

else

CSTATE = MBST_ENABLE

endif

xcall AUI, AUI_CONTROL, CTLOP_ADD, CTLID$, CTEXT$, CSTATE, CTYPE$, CMD$, FUNC$, ...

The above can be reduced to a single statement using IFELSE():

xcall AUI, AUI_CONTROL, CTLOP_ADD, CTLID$, CTEXT$, ifelse(flag'disable,MBST_DISABLE,MBST_ENABLE), CTYPE$, CMD$, FUNC$, ...

History

2016 September, A-Shell 6.3.1526 and compiler edit 773: Function added to A-Shell.


SWITCH

SWITCH <expr>

CASE <constant>{...{<constant>}}

{ CASE <constant>{...{<constant>}} }

<statements>

EXIT

! (any number of case-statement blocks and each statement

! block can have multiple case statement headers)

{ { CASE <constant>{...{<constant>}} }

{ CASE <constant>{...{<constant>}} }

<statements>

EXIT }

{ default

<statements>

EXIT }

ENDSWITCH

Compatibility: requires /X:2 or /RC. Implementation is believed to be compatible with BASIC Plus at the source level, but that implementation was never popular, and the details of its implementation were a bit vague; consequently there has been little effort to determine whether the A-Shell and AMOS implementations are identical or not.

The compiler supports the SWITCH / ENDSWITCH / CASE / DEFAULT statements in /RC and /X:# modes. In either case the generated RUN file is compatible with existing A-Shell runtime versions; in the case of /RC mode, it is also compatible with the AMOS runtime.

The implementation of SWITCH and related statements is roughly compatible with the AMOS BASICPlus version. Since the details of the AMOS version are a bit vague, however, an alternate explanation is provided below.

The general form of the SWITCH construct is as follows:

SWITCH <expr>

CASE <constant>

<statements>

EXIT

CASE <constant>

<statements>

EXIT

DEFAULT

<statements>

EXIT

ENDSWITCH

The <expr> is first evaluated, and then the list of CASE statements is scanned from top to bottom until a match is found between the <expr> and the <constant>. At that point, the <statements> below the matching CASE are executed. If there is no EXIT, the flow of control will continue on through the <statements> following the subsequent CASE statements. (In other words, once a match is found with a CASE, then all subsequent CASE and DEFAULT statements will match, which is why you almost always want to terminate the <statements> associated with a particular CASE with an EXIT.)

The optional DEFAULT statement is like a CASE that always matches, so its sub-statements will be executed if none of the above CASE statements match, or if a previous CASE statement matches but had no EXIT statement, so that control continued to flow.

Multiple CASE statements can share the same set of <statements>, and a single CASE statement can contain a range of values. A range consists of two constants separated by three dots (although one of the two ends of the range can be omitted to indicate an open-ended range). For example:

SWITCH DUES

CASE 101...

FREE'MASSAGES = -1

EXIT

CASE 100

CASE 75

FREE'MASSAGES = 3

EXIT

CASE 50...74

FREE'MASSAGES = 1

EXIT

CASE ...49

FREE'MASSAGES = 0

EXIT

ENDSWITCH

In the above SWITCH, if DUES>=101, FREE'MASSAGES is set to -1. If DUES=100 or DUES=75 then FREE'MASSAGES = 3. If DUES>=50 and DUES<=74, the FREE'MASSAGES = 1, and if DUES<=49 then FREE'MASSAGES = 0. If DUES>75 and DUES<100, then none of the CASE statements match, and since no DEFAULT was specified, the SWITCH ends up having no effect.

Note that as is typical with numeric expressions in Basic, they can evaluate to integers or floating point values. Although it is somewhat unorthodox to use a SWITCH with non-integers, there is no law against it.

The <expr> given in the SWITCH statement can be any type, but the <constants> in the CASE statements must match that type. In other words, if the <expr> is a string, then the CASE <constants> must be literal (quoted) strings, as shown here:

SWITCH MEMBER'TYPE$

CASE "Platinum"

FREE'UPGRADES = 5

FREE'MASSAGES = 3

DUES = 100

EXIT

CASE "G"..."Gold"

FREE'UPGRADES = 3

FREE'MASSAGES = 3

DUES = 75

EXIT

DEFAULT

FREE'UPGRADES = 0

FREE'MASSAGES = 1

DUES = 50

EXIT

ENDSWITCH

In the above example, the second CASE statement would match when MEMBER'TYPE$>="G" and MEMBER'TYPE$<="Gold" (using normal Basic string comparison logic). As a reminder, AlphaBASIC treats trailing blanks the same as nulls in string comparisons, so the second CASE would match even if MEMBER'TYPE$="Gold ".

Note that the maximum length of the literal strings in the CASE statements must not exceed the current default string size as set by the STRSIZ statement. Also note that this form of SWITCH (i.e. with string expressions) does not appear to be supported by AMOS.

For the more common type of SWITCH (numeric), the CASE constants can also be ASCII constants, or hex/octal constants), for example:

SWITCH ASC(A$[B;1])

CASE 'A'...'Z'

CASE 'a'...'z'

TYP$ = "Alpha"

EXIT

CASE '0'...'9'

TYP$ = "Number"

EXIT

CASE &h80...

TYP$ = "8 bit"

EXIT

CASE ...&o37

TYP$ = "Control"

EXIT

DEFAULT

TYP$ = "Punc"

EXIT

ENDSWITCH

Note that any statements between the SWITCH statement and the first CASE are actually executed in all cases under A-Shell, whereas they may not be in other implementations of SWITCH statements (such as AMOS). Consequently you should avoid putting any statements there, except perhaps for debugging purposes.

History

2006 June, A-Shell 4.8.958: Function added to A-Shell


FOR … NEXT

FOR <loopvar> = <startval> to <endval> {step <stepval>}

<statements>

{IF <condition> repeat}

{IF <condition> exit}

{<statements>}

NEXT <loopvar>

The for...next loop executes a set of statements repeatedly until the loop counter hits (or surpasses) the ending condition or the exit statement is encountered. For positive stepval values, this will occur when the loopvar >= endval, whereas when the stepval is negative, it will occur when the loopvar <= endval. The statements in the body of the loop may optionally include repeat statements (which effectively jump to the next statement in order to execute next iteration of the loop, skipping the remaining statements in the body for this iteration), and exit statements (which terminate the loop, as if the loopvar had hit the endval).

The loopvar must be either a floating point or integer (I) variable. The startval and endval can be any numeric expressions that are compatible with the loopvar type. (Don't, for example, try to use fractional starting or ending values with an integer loop variable.) Also, considering that the endval expression will be evaluated for each iteration of the loop, unless the expression's value changes during execution of the loop, for efficiency reasons it is best to pre-evaluate and assign it to a variable, rather than redundantly evaluating it each time.

The optional step clause determines the amount by which the loopvar will be incremented at the end of each loop (default 1). As with the startval and endval, the type should be compatible with the loopvar.

Compatibility: Supported since the original AlphaBASIC, but the semantics were changed in BASIC Plus—i.e. /X:1 and above, and also /RC. In the old compile mode, without /X:1 or /RC, A-Shell implementation matches the AMOS version at both the source and RUN level. In the BASIC Plus mode and above, the A-Shell implementation matches BASIC Plus as the source level only. The repeat and exit statements require /X:1 or /RC.

Example

for x = y*2 to z step -1

if x = w exit ! terminate on this condition

if x mod 2 then repeat ! skip to next iteration

z = fn'mystery(x)

next x

The above example is not one to emulate, since it is completely mysterious what the loop does or when or even if it will ever terminate. But it does illustrate that it is possible (however ill-advised) to modify the end condition within the loop body.

Comments

In the original implementation (without /X:1 or /RC), the condition increment operation and test for termination occurs at the end of the loop, so the loop always executes at least once, regardless of the startval and endval. Furthermore, the loop was not block-structured; the next statement could have been placed anywhere relative to the loop (and you could even have multiple next statements). Not that any of that flexibility encouraged good code.). The repeat and exit statement were not supported.

In the BASIC Plus implementation (/X:1 or /RC), the loop is block-structured, meaning that the loop body must be physically between the for and next statements. Furthermore, the termination condition is checked at the top of the loop, so it is possible for the loop to execute zero times.


FOREACH

FOREACH $$<itervar> in $<aryvar>({<startkey>})

<statements>

NEXT $$<itervar>

FOREACH'REVERSE $$<itervar> in $<aryvar>()

<statements>

NEXT $$<itervar>

The foreach and foreach'reverse loops are used to iterate through Ordered Maps, which see for details.


DO / WHILE / UNTIL

DO {WHILE or UNTIL condition}

<statements>

{IF <condition> repeat}

{IF <condition> exit}

{<statements>}

LOOP {WHILE or UNTIL condition}

For example:

DO WHILE A > B

A = A + 1

B = B * 2

LOOP

Another example:

DO

A = A + 1

LOOP UNTIL A = 10

Compatibility: BASIC Plus at the source level; requires /X:1 or higher.


REDIMX

Updated and Reviewed August 2010

This statement will re-dimension (or remove) an array originally created with DIMX.

DIMX varnam(sub1,...,subn),<type>,<size>

...

REDIMX varname(sub1,...subn)

To remove an array created with DIMX (i.e. free up its memory) use REDIMX as shown above but set the subscripts all to zero. For example:

DIMX ARY(50,100),X,25 ! allocate the array

...

REDIMX ARY(0,0) ! de-allocate it

Notes

· The REDIMX statement must occur after the corresponding DIMX (both during compilation and at runtime). If the compiler sees the REDIMX first, it will report an unmapped variable. If the runtime sees the REDIMX first (except for the exception noted below), it will report error 30 (re-dimensioned array - same error as you get when attempting to use DIMX a second time).

· The one exception to this rule is that a runtime attempt to REDIMX an array to a size of 0 will not complain if the array has not yet been allocated. (This allows you to add a REDIMX VARNAME(0,…,0) to free up an array in an error recovery routine, without having to check whether the array had actually been allocated yet.

· You cannot change the number of subscripts; you can only change the maximum value(s) of the subscript(s).

· The REDIMX statement can not specify a variable type or size; thus you cannot change the original type or size.

· The original contents of the array will be preserved ONLY if all dimensions beyond the first (for multi-dimensional arrays) are preserved. For example, if you start with DIMX A(P,Q,R), and then re-dimension using REDIMX A(X,Y,Z), the contents will be preserved only if Y=Q and Z=R (i.e., only the first dimension was changed).

· The MALLOC trace option will trace DIMX and REDIMX memory allocations (along with most other memory allocations/de-allocations), making it a useful debugging tool.

History

2009 April, A-Shell 5.1.1145: REDIMX added to a-Shell

2010 August, A-Shell 5.1.1189: Enhanced support removing an array by setting its subscripts to zero.


MAP Statements

Modified August 2015 (see History)

{qualifier} MAP<level> <varname>{,<type {,size}} {,@origin}

The MAP statement both defines variables in terms of size and data type but also in terms of the position relative to other variables. The latter capability is particularly useful for defining compound structures such as file records so as to match precisely with a physical byte layout on an external medium.

See MAP Statement Extensions for information on the qualifier option.

MAP1 (level 1, i.e. top-level) variables are positioned on even byte boundaries, subject to override by the ALIGN# PRAGMAs. Lower-level MAP statements (MAP2 thru MAP9) are aligned on byte boundaries (no inter-variable spacing), and may be addressed individually or as a group via the higher level variable(s).

See History, below, for a discussion on unfinalized MAP statements.

Examples

MAP1 CALORIES'CONSUMED,B,3

MAP1 CALORIES'BURNED,B,3

The above example defines two top-level 3-byte binary variables which are logically independent but in fact will be adjacent in memory (subject to alignment fill characters).

MAP1 TIME'REC

MAP2 ID,S,4

MAP2 WORKDAYS(7)

MAP3 DTX

MAP4 MON,B,1

MAP4 DAY,B,1

MAP4 YR,B,1

MAP3 INOUTS(2)

MAP4 IN,B,3

MAP4 OUT,B,3

MAP2 RATE,F,6

MAP1 TIME'REC$,S,115,@TIME'REC

The second example above illustrates a more complex MAP structure which includes multi-level arrays and an overlay. The actual layout in memory and the syntax for accessing the individual variables is as follows:

Memory Offsets | Variable | Aliases | Memory Offsets | Variable | Aliases
0 | ID | TIME'REC, TIME'REC$ | 12 |  |
1 |  |  | 13 |  |
2 |  |  | 14 | IN(1,2) | INOUTS(1,2)
3 |  |  | 15 |  |
4 |  |  | 16 |  |
5 | MON(1) | WORKDAYS(1), DTX(1) | 17 | OUT(1,2) |
6 | DAY(1) |  | 18 |  |
7 | YR(1) |  | 19 |  |
8 | IN(1,1) | INOUTS(1,1) | 20 | MON(2) | WORKDAYS(2), DTX(2)
9 |  |  | 21..34 | ... |
10 |  |  | 35 | MON(3) | WORKDAYS(3), DTX(3)
11 | OUT(1,1) |  | 36..109 | ... |

Note the way the array addressing syntax percolates down through the levels. For example, the variable OUT appears in the map as a scalar, but it is a child of the array INOUTS(2), which is itself a child of the array WORKDAYS(7), which makes OUT an array with two subscripts, as if it were mapped as OUT(7,2), except that the individual elements, are not contiguous with each other. (Only the elements corresponding to the top level first subscript are contiguous.)

The example also illustrates overlaying an entire map structure, TIME'REC, with another variable, TIME'REC$, can be a different type and size. The variable TIME'REC, like all top-level compound variables, is itself an unformatted (data type X) variable whose length is determined by the sum of all its lower-level dependent variables (115 bytes in this case). So the entire structure can be accessed via the single unformatted variable TIME'REC (useful for manipulating the structure as a whole, such as performing record-level file operations). By means of the @ overlay mechanism, we can define additional variables that occupy the same space and thus provide alternate views (or aliases) of the same data. In this case, the variable TIME' REC$,S,115 is overlaid on top of TIME'REC. (TIME'REC and TIME'REC$ are different variables, although in this case they happen to occupy the same space.) Overlaying a string on an unformatted/structured variable can be useful for some advanced techniques. You might also use the same technique in cases where a file contains multiple record layouts, or where you want to manipulate the data at a higher or lower level. For example, we could also overlay TIME'REC with an array of 1 byte elements to simplify operating on it at the byte level.

Note that when overlaying, the variables do not have to be the same overall size. The next position in memory (i.e. the location for the next MAP1 variable) will be determined by the larger of the variables overlaid on each other.

History

2015 August, A-Shell 6.1.1416, compiler edit 748: MAP2+ statements are now flagged as illegal if not preceded by a finalized MAP1 statement. Unfortunately, AlphaBASIC does not make it clear when a MAP1 statement is finalized, other than by the next MAP1 statement. But it is never quite clear if there will be another MAP statement since they are technically legal anywhere in a program. In retrospect, the language could have used an "ENDMAP" statement, although you could effectively create your own just by defining a dummy MAP1 statement at the end of your last multi-level MAP structure.

The ambiguity didn't really have much significance in earlier versions of A-ShellBASIC, except perhaps in certain kinds of nested overlays, where one variable was overlaying another whose position was still in flux because it was part of a higher level array whose element members hadn't been finalized. But it became more of a problem with the introduction of the language features such as DEFSTRUCT, SIZEOF(VAR), .OFFSIZ(VAR), etc.

As of now, the rule is that any reference to a previous variable, except in a MAP statement initializer—and when the referenced variable has been finalized, causes the current MAP1 level to be finalized. If you attempt to follow that with a MAP2 or higher, it will be triggered as an illegal MAP level.

This may cause compile errors in programs that previously compiled, but it will prevent the kind of problem fixed in compiler edit 747 from escalating into a runtime problem. If you're not sure whether you've used the technique described, recompilation with this version or higher is highly recommended.

Subtopics

MAP Statement Extensions


MAP Statement Extensions

ASB supports a series of extensions related to variable declarations, providing programmers more control over the scope and persistence of variables. This topic presents an overview of the general subject, followed by a detailed look at the related keywords.

Scope, the context within which a vairable can be referenced:

Global: Potentially visible from everywhere in the program. (Global/External Variables are not visible within functions and procedures unless ++pragma auto_extern declared within the routine.) This is the default for MAP variables except when declared inside a function or proc.

Local: Visible only within the function or procedure in which the variable was declared. This is the default for variables mapped within a function or procedure.

Module: Visible only within the current ++INCLUDE module (aka file), including within any functions or procedures contained therein. Declaration requires the PRIVATE keyword or ++PRAGMA PRIVATE_BEGIN and must appear outside of any functions or procedures.

Persistence, the duration of a variable's validity:

Static: Variable persists for duration of program. This is the default except for variables mapped within functions/procedures. Prefixing such MAP statements with STATIC will give them static duration. Unlike automatic variables (see below), there is only one copy of each static variable in memory, even in the case of recursion.

Automatic: Variable is automatically created and destroyed at runtime for each instance of a function or procedure. This is the default for variables mapped inside of a function or procedure. These are also called "stack" variables, because they are allocated on the stack. When the function or procedure returns, they get popped off the stack. Note that in the case of recursion, you can have multiple instances of a stack variable, one for each nesting level of the function call. Like all variables, they are always pre-initialized to zero or null unless the MAP statement contains an explicit initialization value.

Use of the keywords STATIC, PRIVATE, and PUBLIC in conjunction with MAP and DIMX statements to control the scope and persistence of variables:

MAP... Defines a global, static variable, unless it occurs within a function or procedure, in which case it defines a local automatic variable. Local variables, whether static or automatic, are invisible outside that routine. Note that if a MAP statement contains an explicit initialization value, then it has the effect of an assignment statement that gets executed at runtime. Thus, if MAP statement is in the flow of control in such a way that it can be executed multiple times, the definition of the variable only occurs once by the compiler but the optional initialization would occur each time the MAP statement was executed.

STATIC MAPn... Used only within functions and procedures to give the variable static persistence; the scope remains local. Note that if the MAP statement contains an initial value, it will only be assigned once. Warning: initialization of a static variable changes the actual RUN module in memory, which could create a logic problem if the module is inadvertently called (via indirect recursion) while it is still in use. For example, if ONE.SBX contains a static initialized variable, and ONE.SBX calls TWO.SBX, which in turn calls ONE.SBX again, that variable would not be re-initialized. Whether or not that is a problem may depend on whether TWO.SBX realizes that the call is recursive.

PRIVATE MAPn... Used only within a ++INCLUDE file, and outside of any function or procedure to define a variable with module scope and static persistence. This technique is useful to allow a group of related functions and procedures to share some common variables without having to expose them to the rest of the program. Note that like all MAP statements, they must be executed in order to achieve anything but null initialization. See ++PRAGMA PRIVATE_BEGIN for details on a technique to ensure proper initialization, and Global/External Variables for additional context regarding the visibility of variables within functions and procedures.

DIMX... Defines an array to be dynamically allocated at runtime. Note that the compiler defines the variable when the DIMX statement is encountered, as it would for a MAP statement, but the variable cannot be referenced at runtime until the DIMX statement is executed. The actual memory for the variable is allocated outside the user partition, and gets cleaned up when the program (or SBX) ends. If DIMX occurs within a function or procedure, by default the variable would be have local scope and persist only for the duration of the procedure or function. The memory allocation is freed automatically when the routine returns. You can add one of the keyword modifiers (STATIC, PRIVATE, PUBLIC) to change the scope and persistence. Note that DIMX is an extended implementation of the original DIM statement, which is now deprecated and not officially supported within functions.

STATIC DIMX... STATIC DIMX is to DIMX as STATIC MAPn is to MAPn. Used only within functions or procedures to cause the DIMX allocation to persist across calls to the routine, while retaining local scope. To achieve both persistence and module scope, use PRIVATE DIMX instead. As a practical matter, to avoid executing the STATIC DIMX statement multiple times if the function is called multiple times, you will probably have to associate it with another local STATIC MAP flag variable that you set when the DIMX is executed.

PRIVATE DIMX... PRIVATE DIMX is to DIMX as PRIVATE MAPn is to MAPn—i.e. declares the array to have module scope and static persistence, except that a PRIVATE DIMX statement may occur anywhere in the module, including within a function or procedure. Because DIMX statements must be executed to initialize them before they are referenced (unlike MAP statements, there is no default null initialization for DIMX), module-scope DIMX arrays are typically initialized inside a function or procedure. Making sure such initialization occurs once and only once, before any use of the array, requires additional control logic, the failure of which can be a common source of runtime bugs. The ++PRAGMA PRIVATE_BEGIN feature provides an elegant solution for the initialization problem.

PUBLIC DIMX... This is a special form of DIMX that can occur only inside a function or procedure. Unlike PRIVATE DIMX, it doesn't have to be within a ++INCLUDE file. It overrides the normal default of local scope and stack persistence for variables defined within a function of procedure, instead making the variable visible anywhere in the entire program. This is handy in a situation where you want to use a function or procedure to create a dynamic memory structure, perhaps by loading the data from or across the internet, that is then available in the main program.

History

2013 February, A-Shell 6.1.1339 (Compiler edit 624): ++PRAGMA PRIVATE_BEGIN/END introduced

2011 October, A-Shell 6.0.1235: Fixes/refinements to PUBLIC DIMX. PRIVATE DIMX structures supported.

2011 May, A-Shell 6.0.1217: Implement automatic cleanup of local DIMX at end of function/procedure

2010 August, A-Shell 5.1.1190-1193: DIMX arrays now support reentrancy. STATIC DIMX fixes.

2009 March A,-Shell 5.1.1157 (Compiler edit 437): Important bug fixes to PRIVATE

2006 October, A-Shell 4.9.970: PRIVATE and PUBLIC keywords introduced


XGETARG, XGETARGS, XPUTARG

Updated October 2011

See History at the bottom of this topic.

These statements may be used (in place of the MX_XCBDATA calls) to retrieve and return values within an SBX routine:

XGETARGS ARG1{,ARG2,...{ARGN}}

XGETARG ARGNO, ARG

XPUTARG ARGNO, ARG

XPUTARGSBX <argno>,<expr>

XGETARGSBX <argno>,<expr>

XPUTARGSBX <argno>,<expr>

XGETARGSBX <argno>,<expr>

XGETARGS retrieves the XCALL arguments into the corresponding variables. The first argument is returned in ARG1, the second in ARG2, etc. If more arguments were passed than you specify variables for, the extra arguments are ignored. Conversely, if you specify more ARG variables in the XGETARGS statement then were passed by the caller, the excess ARG variables are ignored. In either case, the operation is non-destructive to the original argument list, so you can later go back and retrieve (or re-retrieve) parameters using XGETARGS, XGETARG, or the original MX_XCBDATA statements.

XGETARG ARGNO,ARG performs the same function as XGETARGS except that it retrieves only the one argument (whose number is specified in ARGNO).

XPUTARG ARGNO,ARG is the reverse of XGETARG. It returns the value of the argument ARG into the caller's argument number ARGNO.

Note that in the case of XPUTARG, the ARG can be a variable or an expression, whereas in the case of XGETARGS or XGETARG, the arguments must be variables. (You can't retrieve an argument into an expression, but you can use an expression to return an argument.)

As with XGETARG, attempting to return an argument beyond the number of arguments passed is just ignored.

Type conversions will be made as appropriate if the variable types do not match the types passed to the routine (but it behooves you to use "appropriate" data types for the circumstances).

The following examples may clarify the equivalencies between the new statements and the old MX_XCBDATA calls:

XGETARGS P1,P2,P3,P4

is equivalent to:

xcall MIAMEX, MX_XCBDATA, XCBADR, XCBGET,1,P1

xcall MIAMEX, MX_XCBDATA, XCBADR, XCBGET,2,P2

xcall MIAMEX, MX_XCBDATA, XCBADR, XCBGET,3,P3

xcall MIAMEX, MX_XCBDATA, XCBADR, XCBGET,4,P4

and is also equivalent to:

XGETARG 1,P1

XGETARG 2,P2

XGETARG 3,P3

XGETARG 4,P4

For returning arguments,

xcall MIAMEX, MX_XCBDATA, XCBADR, XCBPUT,1,A+B/C

is equivalent to:

XPUTARG 1,A+B/C

The main advantage of the new statements is just efficiency, both for the programmer and for the computer. (This is especially true if you use XGETARGS to retrieve all arguments in one statement.)

Note that these new statements do not require XCBADR or any of the other variables set up by ASHINC:XCALL.BSI. However, you may still want to continue including XCALL.BSI at the start of your SBX modules since it does set the variable XCBCNT to the number of parameters passed, and the XCBSTRUCT() array to the types and sizes, and this information can be useful in determining how to interpret the passed parameters. (XGETARGS and XGETARG do not give you any obvious indication when fewer parameters were passed to the subroutine than the subroutine is expecting, so a well-written subroutine should, at a minimum, check XCBCNT to see how many parameters were passed.)

You do need to compile with the /X:2 (A-Shell extensions) switch (but this is true for all SBX modules anyway).

History

2011 October, A-Shell 5.1.1235: XGETARG now supports AUTO_EXTEND. Previously you needed to do a dummy assignment to the array variable prior to the XGETARG in order to trigger the auto extension.

2010 January, A-Shell 5.1.1173: Added the following new statements:

XPUTARGSBX <argno>,<expr>

XGETARGSBX <argno>,<expr>

XPUTARGSBX acts just like XPUTARG except that it references <argno> in the current SBX context, even if it occurs inside a function or procedure. PUTARG continues to act as before, referencing the function or procedure argument if inside a function or procedure, else the SBX argument if not.

Note that using XPUTARGSBX in a program will set the "5.1 extensions" flag in the header, which will can be seen by VERSYS, and which will cause a runtime error in versions of A-Shell prior to 1160, but it will not provide any warning in versions 1160-1172. In those versions, the runtime system will generate an illegal syntax code when hitting such a statement.


USING Mask

Updated May 2015

USING creates a formatted string expression based on a coded "picture" of how the value(s) should appear. The mask may be multi-field or single-field. The multi-field case is only used in the PRINT statement, prior to the list of values, e.g.:

num USING mask

PRINT USING mask, v1 {, ..., vn}

Where:

num is a numeric expression.

v1 thru vn are string or numeric expressions.

mask is a string describing how to format the value(s), according to the rules described below.

Note that while similar, the two cases shown above are distinct in important ways.

The first form, num USING mask, is a string expression, made up of a numeric value, the USING operator, and a string mask, which returns a string—i.e. the value formatted as a string. As a string expression, it can be used anywhere a string expression can be used. Note that the expression preceding the USING operator must be numeric, and that the mask should contain format instructions for only a single value, plus optional literal characters. Another name for this would be a Single Valued Numeric USING Expression. Examples:

PRINT #0, "Batting average: ";(HITS / AT'BATS) using "N.###"

TOTAL$ = (QTY * PRICE * (1 - DISCOUNT)) USING "Your total is: $#####.##"

In the second form, USING mask is an optional clause affecting the operation of the PRINT statement. Another name for it would be a PRINT USING Clause. In this case, the mask should contain formatting instructions for the same number of values as will be supplied as arguments to the PRINT statement. This kind of mask can deal with a mixture of numeric and string values, whereas the Single Valued Numeric USING Expression can only deal with numeric formatting. For example:

MASK$ = "Name: \-------------\ Age: ### Sex: ! Score: ###.#%"

PRINT #0 USING MASK$, name$,age,sex$,hits*100/tries

While the masks are intended to be somewhat self-explanatory, the interpretation of the various special characters is described in the following table. Note that for clarity, an underscore character is used to show a space in the Result column.

Specifier | Description | Example---> | Result
# | Marks a position to be filled by a numeric digit or leading minus sign. Masks allowing for more digits than necessary will result in right justification with leading spaces; see Z. Fractional values will be rounded to the nearest integer unless the mask contains a decimal point. | 123 using "####" 123.6 using "###" | _123 124
Z | To replace leading spaces with leading zeroes, replace all but the first # with Z. | 123 using "#ZZZ" | 0123
. | (period) Marks the position of the decimal point. Any # characters to the right of the of the decimal point will be zero-filled. | 123 using "###.##" | 123.00
, | (comma) Causes thousands separators to be output between each three digits. | 123456 using "###,###" | 123,456
$ | Outputs the currency symbol at the specified position; may be leading or trailing. | 123 using "$#####.##" | $ 123.00
$$ | Same as $ but when used in the leading position, shifts the currency symbol over to immediately before the first digit with the leading spaces in front of the currency symbol. | 123 using "$$#####.##" | _$123.00
* | A format mask starting with two asterisks followed by a dollar sign will act like the $$ case but will replace the leading spaces with asterisks. | 123 using "**$#####.##" | ****$123.00
^ | Outputs exponential format. | 12345 using ".####^^^^" | .1236E05
- | (minus sign) When put at the trailing end of a numeric mask, causes negative numbers to print with a trailing minus sign. Otherwise negative values will print with leading minus signs, and the minus sign takes up a position otherwise available to a digit. | -123 using "#####" -123 using "####-" 123 using "####-" | -123 123- 123_
\ | (String specifier, PRINT USING clause only) A pair of backslashes marks a string field in the multi-field version of the USING clause. If the string value is too long it will be truncated. Characters between the backslashes each define a position in the output but are not printed, allowing you to use self-documenting descriptions instead of dashes or blanks. | using "Name: \-----\ Age: ##", nam$, Fn'Age(dob) | Name: Jack Age: 99
! | (String specifier, PRINT USING clause only) Defines a single-character field. | using "Sex: ! Age: ##", gender$, age'nearest | Sex: M Age: 25
! | (Single Valued Numeric USING Expression only) Behaves like ".", except that if there are no non-zero digits to the right of the decimal point in the formatted output, it changes the decimal point in the formatted output to a space. Note that "!" is also used to denote a single character field in a PRINT USING MASK statement. The two different uses of the same mask character should be clear to the interpreter from the context. | See "Examples" below |
N | Behaves the same as "#", except that when placed after a decimal point, it causes any trailing zeros to be converted to blanks. If placed before the decimal point, and it is not followed by any "#" character prior to the decimal point, then it causes leading zeros to be convered to blanks. This is similar to the normal case with "#", except that for values less than 1, "#" will display a leading zero whereas "N" will not. See N Character Handling. | See "Examples" below |
n | Behaves just like "N", except that to the left of the decimal point it causes leading blanks to be stripped, and to the right of the decimal point, trailing blanks to be stripped. See N Character Handling. | See "Examples" below |
Any other character | Treated as a literal. | 123 using "[A-###]" | [A-123]

Examples (!, N, n)

1234.5 using "$$###,###.###" displays " $1,234.500"

1234.5 using "$$###,###.NNN" displays " $1,234.5 "

1234.5 using "$$###,###.nnn" displays " $1,234.5"

1234.5 using "$$###,###!nnn" displays " $1,234.5"

1234.5 using "$$nnn,nnn!nnn" displays "$1,234.5"

1234.5 using "nnn,nnn.nnn$" displays "1,234.5 $"

1234.0 using "$$###,###!NNN" displays " $1,234 "

1234.0 using "$$###,###!nnn" displays " $1,234"

1234.0 using "$$nnn,nnn!nnn" displays "$1,234"

1234.0 using "$nnnn,nnn!nnn" displays "$ 1,234"

0 using "###.#" displays " 0.0"

0 using "###.N" displays " 0. "

0 using "NNN.n" displays " ."

0 using "NNN!n" displays ""

0 using "nnn.N" displays ". "

0 using "nnn!N" displays ""

0 using "nnn.n" displays "."

0 using "nnn!n" displays ""

1.23 using "n.###" displays "1.230"

0.23 using "n.###" displays ".230"

Comments

For numeric specifiers, the maximum width of the formatted number will be equal to the total number of characters in the specifier, including the special characters. If the number doesn't fit in that space, the result will be a percent sign (%) followed by the number with default numeric formatting. In the case of string specifiers, the string will simply be truncated to fit the specifier.

String specifiers can only be used in the multi-field variation of the USING MASK clause, i.e. PRINT #CH USING MASK$, expr1, expr2,...

Although the decimal point, comma, and dollar sign characters in the mask are invariable, the actual decimal, thousands separator and currency symbols used in the formatted result will be based on the Language Definition.

Although the USING operator is primarily associated with PRINT statements, the single-field version may be used like any other string expression, such as in assignment statements, as parameters to functions, etc. They are often used as a convenient and elegant way to round results in arithmetic operations. For example, in the following statement the formatting mask is being used as a convenient way to round each item total to an even number of cents:

TOTAL = (QTY * PRICE) USING "#######.##"

Note that what really happens in the above assignment statement is that the floating point result (QTY * PRICE) is rounded to the nearest cent and then represented as a string, which is then converted back to a floating point value stored in TOTAL. This technique is a good solution to the problem of making sure the internal values exactly match the printed values so that, for example, column totals add up as expected. Traditional arithmetic approaches to rounding are more syntactically complex and run the risk of deviating from the way the printed results are rounded.) However, when using masks for rounding purposes, make sure there are no non-numeric characters in the mask (dollar signs and commas in particular), and that the mask is big enough to handle any possible value (since the leading % in an overflow will cause the result to evaluate to zero).

History

2015 Mayl, A-Shell 6.1.1410: Add additional N Character Handling.

2015 April, A-Shell 6.1.1407: Add specifiers !, N, n, re-write first section above.

Subtopics

N Character Handling


N Character Handling

In earlier versions of A-Shell, literal N and n characters in PRINT USING MASK expressions were being misinterpreted as numeric fields. To avoid this, N and n are now ignored as possible leading numeric field indicators unless immediately preceded by a non-alphabetic character, and there are no alphabetic characters other than N to the right, all the way to the end of the mask. For example:

PRINT USING "Neg. scans: NNN", X

PRINT USING "Neg. scans: NNN (total)", X

PRINT USING "Neg. scans: #nn (total)", X

In all three statements, the "N" in "Neg." and the "n" in "scans" are treated as literals, since they are adjacent to alphabetic characters.

In the first statement, the "NNN" acts as a mask, because there are no subsequent non-alpha chars. In the second, the "NNN" is treated as a literal, because of the trailing alphabetic chars in "total". In the third, the "#nn" is treated as a mask because "#" is an unambiguous leading mask character.

Note that this limitation effectively disables the use of the leading "N" and "n" mask characters in PRINT USING MASKs containing trailing text, but it doesn't affect the use of "N" or "n" as trailing mask characters (e.g. "##.nn"), and doesn't generally affect the common case of <VALUE> USING MASK expressions unless they contain trailing alphabetic characters, which is odd but legal.


Unary Operators

Function | Description
NOT | Bitwise inversion of operand. This is generally used as a logical operator, but care should be taken when dealing with any values other than 0 (FALSE) and -1 (TRUE). (NOT 0 is -1 and NOT -1 is 0, but applying NOT to any other non-zero (i.e. TRUE) values just returns another non-zero (also TRUE) value, which can easily lead to confused logic.
- | Unary minus, arithmetically negates the value of the operand.


The Overloaded Plus Operator

The overloaded plus operator ( + ) performs either addition or concatenation, depending on whether the arguments are strings or numbers. How does this work with Mode Independence, which automatically converts between numbers and strings according to the operator and statement context? It depends on the type of the operand to the left of the plus sign. If it is a string expression, then the operation is concatenation and the right-side expression will be converted to string if necessary. Otherwise, the operation is addition and the right-side expression will be converted to a number if necessary. Determining the type of the left operand isn't always so obvious though, since it may be affected by a prior implicit conversion. Assignment statements, for example, will expect the first operand after the equals sign to be of the type of the destination, and if not, will convert it accordingly, which could then affect how a subsequent + operation is interpreted. The following examples may help clarify this.

10 map1 num,f,6

20 map1 s$,s,10

30 print "1" + 2 ! "12" (concatenation)

40 print 1 + "2" ! "3" (addition)

50 num = "1" + 2 ! num = 3

60 s$ = "1" + 2 ! s$ = "12"

70 num = 1 + "2" ! num = 3

80 s$ = 1 + "2" ! s$ = "12"

The print statement (line 30 and 40) accepts either numeric or string argument expressions and does not coerce them either way, so the compiler decides between concatenation or addition purely on the type of the left operand with the results as shown in the comments above. Assignments, however, expect the first operand to the right of the equals sign to match the type of the destination variable, and will convert it if needed. So in the assignment on line 50, even though the left operand of the + is a string, it gets converted to a number to match the type of the destination variable (num), which in turn forces the + to be treated as addition. On line 60, since the destination s$ is a string, the left operand "1" also remains a string, which forces the + to be treated as concatenation, with the right operand 2 converted to the string "2". Line 80 shows the reverse effect, with the left operand 1 being converted to the string "1" because the destination is a string, and that causes the + to be treated as concatenation.

You can use the functions str$(n) and val(s), which convert numeric expressions to string and vice versa, to coerce this behavior, although that too can be confusing. For example:

100 num = str$(1) + 2 ! num = 3

110 s$ = val("1") + 2 ! s$ = "12"

You might have expected the str$(1) in line 100 to force that operand to be a string expression and thus force concatenation, but it gets overridden by the implicit conversion in the assignment statement, i.e. str$(1) effectively becomes val(str$(1)). Conversely, in line 110 val("1") converts the "1" to a numeric 1, but it is overridden by the implicit conversion back to string for the assignment to the string variable s$, which results in the + operator being treated as concatenation.

If you have to do arithmetic or concatenation with a mixture of string and numeric expressions and find yourself unsure, the best approach is to break up your logic into multiple statements—(possibly using temporary variables—to avoid these implicit conversions.


Binary Arithmetic and Logical Operators

These operators are placed between the two operands that they act on (e.g. A + B, Q MAX R, etc.).

Operator | Description
+ | addition
- | subtraction
* | multiplication
/ | division
^ | raise first operand to power of second operand
** | same as ^
AND | bitwise AND
OR |
XOR | bitwise XOR
MAX | X MAX Y returns the larger of X and Y, i.e. equivalent to MAX(X,Y) in some other languages.
MIN | X MIN Y returns the smaller of X and Y, i.e. equivalent to MIN(X,Y) in some other languages.
= | Returns TRUE (-1) if the two operands are equal, else FALSE (0); not to be confused with = assignment operator
<> | not equal (reverse of =)
# | not equal (same as <>)
> | returns TRUE (-1) if the first operand is greater than the second
>= | returns TRUE (-1) if the first operand is greater than or equal to the second
< | returns TRUE (-1) if the first operand is less than the second
<= | returns TRUE (-1) if the first operand is less than or equal to the second
MOD | X MOD Y returns the "modulo" of X relative to Y, i.e. the integer remainder after dividing Y into X. For example, a Julian date can be converted to the day of the week using JULDATE MOD 7 (returning a value in the range of 0-6, which you may then want to adjust according to what value you want to assign to what you consider the first day of the week).


Boolean Bit-wise Arithmetic

The Boolean operators labeled "Logical" in the Operator Table above (AND, OR, NOT, etc.) can give rise to two kinds of confusion. The first results from general confusion about the rules of Boolean logic when multiple operators are combined. For example, forgetting that [ NOT X AND NOT Y ] is equivalent to [ NOT (X OR Y) ] rather than [ NOT (X AND Y) ]. This isn't the place to resolve that kind of confusion; instead consult a textbook on Boolean logic. The second kind, which hopefully we can resolve here, has to do with the fact that, at least in ASB, these so-called "logical" operators are actually arithmetic operators, similar to other arithmetic operators except that they work at the bit-by-bit level with no borrowing or carrying between bits. So while you may be tempted to view the expression [ X AND Y ] as having a purely logical value, i.e. TRUE or FALSE, in fact it has a purely numeric value resulting from the bit-wise ANDing operation, which can then be used like any other numeric expression, e.g. P = (X AND Y) * Z.

The following example should make this more clear:

MAP1 X,B,1

MAP1 Y,B,1

X = 1

Y = 4

? (X OR Y) ! 00000001 OR 00000100 = 00000101 (5)

? (X AND Y) ! 00000001 AND 00000100 = 00000000 (0)

? NOT X ! NOT 00000001 = 11111110 (-2)

? NOT (X AND Y) ! NOT 00000000 = 11111111 (-1)

? (X + Y) ! 00000001 + 00000100 = 00000101 (5)

This is pure bit-wise Boolean arithmetic. Note that negative values are represented using 2's complement notation; -1 is represented by all 1 bits. Also note that in the above example, (X OR Y) is equivalent to (X + Y), because when viewed one bit at a time, the OR and + operations are equivalent. The difference between the two only shows up when there is a carry operation, e.g.

X = 1

Y = 5

? (X OR Y) ! 00000001 OR 00000101 = 00000101 (5)

? (X + Y) ! 00000001 + 00000101 = 00000110 (6)

So the Boolean operators are for all practical purposes like other arithmetic operators, except that the Boolean operations never result in borrowing or carrying from one bit position to the next.

The question of truth value, i.e. is the expression TRUE or FALSE, only arises in conjunction with relational operators (=, >, <, etc.) or conditional statements (IF, WHILE, UNTIL, etc.), which convert the numeric value of an expression to TRUE or FALSE according to the simple rule:

Zero is FALSE

Non-Zero is TRUE

If we revisit our first example above, this time using IF statements to test the logical truth value of the expressions instead of directly printing the numerical value, we get the following:

10 X = 1 : Y = 4

20 IF (X OR Y) ? "TRUE" ELSE ? "FALSE" ! TRUE (5)

30 IF (X AND Y) ? "TRUE" ELSE ? "FALSE" ! FALSE (0)

40 IF NOT X ? "TRUE" ELSE ? "FALSE" ! TRUE (-2)

50 IF NOT (X AND Y) ? "TRUE" ELSE ? "FALSE" ! TRUE (-1)

60 IF (X + Y) ? "TRUE" ELSE ? "FALSE" ! TRUE (5)

These results follow directly from the rule just stated, that 0 is FALSE and any other value is TRUE. Yet line 30 often confuses programmers, considering that since both X and Y are non-zero—i.e. both are TRUE when considered individually—the expression (X AND Y) should be equivalent to (TRUE AND TRUE), i.e. should be TRUE. Similarly, in line 40, since X is non-zero, it must be TRUE, and therefore NOT X must be FALSE. Right? Wrong. The discrepancy is caused by the fact that the Boolean operators act arithmetically at the bit-wise level resulting in a numeric value which is only converted to logical TRUE or FALSE when needed for the conditional IF statement.

A-Shell, like most other languages, does not have a specific built-in Boolean data type and relies instead on the above rule for converting numeric expressions to logical TRUE/FALSE as required by relational operators and statements. If you want to define variables to represent TRUE and FALSE, you can either MAP them, i.e.:

MAP1 LOGICAL'CONSTANTS

MAP2 TRUE,B,1,-1

MAP2 FALSE,B,1,0

or defined constants, e.g.:

define TRUE = -1

define FALSE = 0

Although you might be tempted to use 1 for your TRUE value, and that might work in some cases, but -1 is a far better choice, since its binary representation is all 1's, and thus any bit-wise operation will always be dealing with a 1 on the TRUE side. If you used 1 (i.e. 00000001), then only the first bit would get the benefit of the non-zero value and all the other bit-wise operations would be dealing with zeroes (i.e. FALSE bits).

Note that when a logical expression is converted back to a numeric expression, as in the statement PRINT (X = Y), FALSE becomes 0 and TRUE becomes -1. So there is an asymmetry in the conversion back and forth between numeric and logical truth. When converting from numeric to logical, any non-zero value becomes TRUE; but when converting logical to numeric, TRUE always becomes -1. This is another reason why if you're going to define a constant TRUE, it should be set to -1.

Also note that while defining constants TRUE and FALSE may be convenient for the readability of code similar to the following:

IF (X AND Y) THEN

AUTHORIZED = TRUE

ELSE

AUTHORIZED = FALSE

ENDIF

... be careful not to casually use a relational operator to compare a numeric expression directly with your constant TRUE, e.g.

IF AUTHORIZED = TRUE THEN ... ! bad!!!

Instead, use the logical equivalence operator EQV:

IF AUTHORIZED EQV TRUE THEN ... ! good

Or better yet, just test the variable directly and let the IF operator convert it from a number to a truth value:

IF AUTHORIZED THEN ... ! best

The problem with using the relational equals operator (=) is that the result of the expression is TRUE only if both operands are numerically equal (i.e. AUTHORIZED = -1). Almost surely what you mean to be testing is if they are logically equivalent to TRUE (i.e. both are non-zero). And since TRUE is obviously equivalent to itself, X EQV TRUE is the same as X, so just testing the target variable directly as in the last example is the simplest.

To take another example:

10 define F_DOG = &h0001

20 define F_CAT = &h0002

30 define F_TAME = &h0010

30 IS'PET = (ANIMAL'TYPE AND (F_DOG OR F_CAT or F_TAME))

40 IF IS'PET = TRUE THEN CALL FEED'IT ! bad idea, pet will starve

50 IF IS'PET THEN CALL FEED'IT ! good, pet gets fed

Line 30 sets IS'PET to a non-zero value if the ANIMAL'TYPE bit representation contains either of the dog or cat or tame bits. Line 40 would virtually always fail, since the result of the assignment at line 30 will almost surely not be -1 (i.e. all bits set). Line 50 shows the correct approach, since the numeric expression IS'PET will be converted to logical TRUE if any of the bits are set.

Beware of Boolean combinations

When dealing with bit flags, we are often interested in testing whether if one among several bits is set, or if two or more bits are together set. We can use the AND operator to test if bits are set, and the OR operator to create an expression containing multiple bits that can then be tested as a group. Continuing with the pet example above, to test if our animal represented by ANIMAL'TYPE is either a dog or is tame, we can do either of the following:

IF (ANIMAL'TYPE AND F_DOG) OR (ANIMAL'TYPE AND F_TAME) THEN ... ! if dog or tame

IF (ANIMAL'TYPE AND (F_DOG OR F_TAME)) THEN ... ! " " " "

So far so good. But to test if it is a tame dog (i.e. is both a dog and tame), don't make the mistake of just flipping the central Boolean from OR to AND:

IF (ANIMAL'TYPE AND F_DOG) AND (ANIMAL'TYPE AND F_TAME) THEN ... ! bad

IF (ANIMAL'TYPE AND (F_DOG AND F_TAME)) THEN ... ! bad

The problem with both of the above statements is that F_DOG and F_TAME are non-overlapping bit patterns (&h0001 and &h0010). Thus the numeric expressions (ANIMAL'TYPE AND F_DOG) and (ANIMAL'TYPE AND F_TAME) are also going to be non-overlapping bit patterns, so ANDing them together will always result in zero (FALSE). Even worse, the expression (F_DOG AND F_TAME) is always zero (both are constants), and anything ANDed with zero is zero, so the second conditional will might as well be a null statement . The way to test if both bits are set is to introduce relational operators to strategically convert the numeric sub-expressions to logical ones, e.g.

IF ((ANIMAL'TYPE AND F_DOG) # 0) AND ((ANIMAL'TYPE AND F_TAME) # 0) THEN ... ! good

IF (ANIMAL'TYPE AND (F_DOG OR F_TAME)) = (F_DOG OR F_TAME) THEN ... ! good

Here, in the first statement we used the relational operator # (not equal) to convert the numerical expressions (ANIMAL'TYPE AND F_xxx) to logical expressions (i.e. to -1 for TRUE or 0 for FALSE). That allows the central AND operator to give us a numerical result which is non-zero if both of the sub-expressions were non-zero (matching the expected logical behavior). In the second line, we mask out all of the other bits in ANIMAL'TYPE except for the F_DOG and F_TAME bits, and then use the relational operator = to numerically compare if that equals the combination of those two bits, i.e. if both bits are set.


Logical versus Arithmetic Operators

Although the operators AND, OR, and NOT are generally used as if they were purely logical, in fact, in A-Shell/Basic they are really arithmetic (bitwise). The apparent logical nature is a side effect of the fact that in an IF statement (which has the general form IF <expression>), after all of the operations which make up the <expression> have been evaluated, reducing the expression to a single value, the IF statement then treats the result as TRUE if non-zero or FALSE if zero.

So, for example, in evaluating the statement IF X AND Y THEN ..., the expression evaluator first performs an arithmetic bitwise AND of the two operands X and Y, and if the result is non-zero, the expression is considered TRUE and the THEN clause will be executed. This is not the same as a truly logical AND, which would return a TRUE value for the expression if either A was TRUE or B was TRUE. To illustrate, consider the case where X=6 and Y=1. In binary form, this is 110 and 001, and the bitwise AND operation returns 000 (FALSE), even though each operand was individually TRUE (non-zero). This is one reason why you should always use -1 rather than 1 to represent the logical value TRUE.

When used properly, the arithmetic bitwise nature of the operators AND, OR, and NOT may be used to advantage when dealing with bit patterns. For example, if X is a bit field (where each bit represents a flag), you can test if a one or more individual bits are set using AND. For example, the statement IF X AND &h0011 will test whether either of the two lowest bit flags are set in the variable X. Similarly, you can use the OR operator to set the bits, e.g.:

BIT1 = &h0001

BIT2 = &h0002

BIT3 = &h0004

FLAGS = FLAGS OR BIT1 OR BIT3 ! sets the first and third bit, leaving the others alone.

To reset (clear) a bit, you can use the combination AND NOT:

FLAGS = FLAGS AND NOT BIT2 ! clears the 2nd bit, leaving the other bits alone

When creating compound IF statements involving multiple operators, it is wise to use the equals (=) and not equals (#) operators, with parentheses, to force the individual sub-expressions to be converted from bit fields to logical results. For example, instead of:

IF (FLAGS AND BIT1) AND (FLAGS AND BIT3) THEN... ! this will never be TRUE unless BIT1 and BIT3 overlap

you should use:

IF ((FLAGS AND BIT1) # 0) AND ((FLAGS AND BIT3) # 0) THEN ! TRUE if both BIT1 and BIT3 are set in FLAGS

The parentheses in the first expression above don't really accomplish anything, and the result of the entire expression will only be non-zero (TRUE) if BIT1 and BIT3 overlap each other and one or more "1" bits in FLAGS, which is clearly not the intended meaning. The use of the # (not equal) operators in the second expression converts the arithmetic result of each subexpression into a truth value (i.e. either -1 for TRUE or 0 for FALSE), so that the central AND will actually operate in the expected (logical) fashion.

Subtopics

Shortcut Operators


Shortcut Operators

Added December 2010

A-Shell offers the following shortcut operators:

var += <expr> ! equivalent to var = var + (<expr>)

var -= <expr> ! equivalent to var = var - (<expr>)

var *= <expr> ! equivalent to var = var * (<expr>)

var /= <expr> ! equivalent to var = var / (<expr>)

These require /X:2 or /RC, but they do not have any compatibility effect on the resulting RUN module. Note that the += operator works equally well for numeric addition as well as string concatenation.

History

2010 December, A-Shell 5.1.1195: Feature added to A-Shell (compiler edit 471)


Compiler Directives

Compiler directives are another category of statements, except that they are consumed entirely by the compiler, with the result of affecting the compiler's behavior, rather than generating tokens in the RUN module to be processed at runtime. They include:

• ++PRAGMAs

• ++INCLUDE and its variants

• Conditional Compilation statements

• ++EXTERN

• MESSAGE

• ERROR

• DEFINE

• Defined Structures

• DEFTYPE

• COMPILER_VERSION Macro

Subtopics

DEFINE

DEFTYPE

DIVIDE'BY'0

++INCLUDE

PRAGMAs

Conditional Compilation

MESSAGE

ERROR

Defined Structures

Auto-Defined Macros


DEFINE

DEFINE symbol = value

This statement defines the constant <symbol> to be equal to <value>. It was added to A-Shell in Build 923 of 15 March 2005. Some examples:

DEFINE TCRT'REVON = 32

DEFINE XTF'CTRLC = &h01000000

DEFINE MY'NAME$ = "JACK"

The names following the DEFINE must conform to the normal rules for variable names (start with an alphabetic character and contain alphabetic, numeric and apostrophe or underline characters plus an optional $ or % suffix).

The definition must either be a literal numeric value (as in the first two examples above), or a quoted string value.

These definitions act like macros, substituting the definition into the source code before each line of the program is compiled. Because of this, compiler error messages will usually display the line after macro expansions (which may look strange at first, but since the error messages also show the line number, it allows you to compare your source code to the result after the macro replacements.)

From a logic standpoint, the result is equivalent to using MAP statements, i.e.:

MAP1 TCRT'REVON,B,1,32

MAP1 XTF'CTRLC,B,4,&h01000000

MAP1 MY'NAME$,S,4,"JACK"

The main advantages of DEFINE over MAP statements are:

• You cannot assign a value to a DEFINEd symbol; thus, they act like true constants.

• DEFINEd constants take up no space in the RUN file unless they are used. Thus it now becomes practical to create ++INCLUDE files which define constants for virtually every situation, without worrying about the overhead. (They do create some compiler overhead, but is that really something we need to worry about?)

• Even for constants that are referenced in the program, constants generally save space in the RUN file. A non-subscripted MAP statement with an initial value takes 16 bytes, and then it takes another 2 or 3 bytes to reference it in the code. A constant takes zero bytes to define, and generally only 2 bytes to reference. (Depending on the number of significant binary digits in the constant, it may take 4 or 6 bytes to represent. But in the vast majority of cases, DEFINEd constants are small integers or powers of 2 and can be represented in only 2 bytes. Strings require 2 bytes plus their length to reference as constants, so in that case, the use of constants may actually increase the size of the RUN, assuming they are referenced multiple times.)

• Because of the above, converting MAP statements to DEFINEd constants (assuming they are never assigned more than one value) will result in smaller RUN files, with a very slight bonus in performance, at the cost of a slight increase in compile times. But the main advantage comes in programming clarity when you use meaningful symbolic names for constant values in place of literal number or mapped variables.

Including a file containing an unknown set of DEFINEs is generally safe and should have no side effect on an existing program (unless you deliberately use the defined constants). There are, however, some scenarios to be aware of:

• If a DEFINE precedes a MAP statement for the same identifier, the MAP statement will generate a syntax error, because the MAP statement identifier will be replaced by the value of the DEFINEd symbol before it gets compiled. For example:

DEFINE CTLOP'ADD = 1

MAP1 CTLOP'ADD,B,2,1

Since the CTLOP'ADD in the MAP statement will be replaced by 1, it will be compiled (and a syntax error generated) as if it were:

MAP1 1,B,2,1

• If a DEFINE conflicts with an unmapped variable, a similar thing will happen when you try to assign a value to the variable:

DEFINE CANADA'VAT = .15

CANADA'VAT = .16 ! assignment to unmapped variable

This will also cause a syntax error, because it will look to the compiler as if it were:

.15 = .16

(If the unmapped variable is never referenced, you won't get a syntax error, but then again it won't matter to your program operation either.)

• The one case where you might have a problem is if you reference an unmapped (and unassigned) variable in an IF statement, i.e.:

IF CANADA'VAT = .16 THEN ...

This will compile as if it were:

IF .15 = .16 THEN ...

That is a perfectly legal statement, and won't be what you expected (although your test of an unmapped/unassigned variable probably won't be what you wanted either, unless you were counting on it being zero). To eliminate this possibility, compile your programs with /M !!!

• If you attempt to DEFINE a symbol that has already been MAPPED, you will get a duplicate label error. So it doesn't really matter whether you DEFINE all your symbols first or do all your MAPs first, or mix them together; any conflict between the two will generate a compilation error.


DEFTYPE

Added November 2014

DEFTYPE may be used to define an alias for a data type, with optional size, that can then be used in MAP statements and in Function and Procedure declarations. This can be useful in assuring consistency of logical data types through an application. For example:

DEFTYPE Boolean = I,2

deftype PRICE = F,8

deftype phone = ST_PHONE

map1 ready,Boolean ! equivalent to map1 ready,I,2

dimx total(10),PRICE ! equivalent to dimx total(10),F,8

map1 cellnum,phone ! equivalent to m1p cellnum,ST_PHONE

Function Fn'PiePrice(ala'mode as Boolean) as PRICE

! equivalent to: Function Fn'PiePrice(ala'mode as I,2) as F,8

Note that while DEFTYPE itself is case INsensitive, following the normal rule for keywords, the defined macro symbols are case sensitive—i.e., are the same as those created by DEFINE or DEFSTRUCT . You can compile with the case-insensitive option (/CI or -ci) if you prefer case insensitivity throughout.

History

2014 October, A-Shell 6.1.1391: Function added to A-Shell


DIVIDE'BY'0

A-Shell BASIC > Compiler Directives

DIVIDE’BY’0

This statement, along with its converse, determines how an attempt to divide by zero is handled from that point forward in the program. In the default case (NO’DIVIDE’BY’0) such an attempt causes an error #10. After DIVIDE’BY’0 has been executed, such an attempt will return a quotient of 0.


++INCLUDE

Updated March 2017; see History

++INCLUDE <fspec>

The ++include compiler directive causes the file specified by fspec to be processed as if it were part of the file being compiled. The technique is useful for sharing common code, map statements, and definitions between programs. The fspec may be in either AMOS or native format. If no explicit location specified the file is expected to be in the current directory, or in the BAS: account. If not found in either location, the A-Shell compiler—unlike the AMOS counterpart—will also search in the same directory as the main source file being compiled, assuming that is different from the current directory.

While the ++include feature has been part of AlphaBASIC since the earliest days, A-Shell adds a number of enhancements. See the following topics, as well as the documentation on COMPIL/LI (Local Include).

History

2017 March, A-Shell 6.4.1546, compiler enhancement (797): maximum nesting levels for ++INCLUDE and ++IF conditions increased from 20 to 40. Improve messaging/recovery for the overflow condition.

2013 July, A-Shell 6.1.1358: Compiler enhancement (642): new variations of ++INCLUDE: ++INCLUDE'IF'EXISTS <filespec> and ++INCLUDE'ONCE'IF'EXISTS <filespec>. As the name implies, these operate just like ++INCLUDE and ++INCLUDE'ONCE except that if the file is not found in the normal search path, it is just skipped.

Subtopics

Nested ++Includes

One-Time ++Includes


Nested ++Includes

A-Shell supports thirteen levels of nested ++includes. This is primarily useful to allow modular include files to themselves include all of the necessary modules they require, thus relieving the programmer from having to include the entire network of dependent modules in the main source file. Nesting does introduce two complications worth further discussion: how to avoid including the same module twice (see One-Time ++Include), and how to keep track of the hierarchy of nested includes, particularly when it comes to locating the module containing an error flagged by the compiler.

To help you visualize the hierarchy of ++include processing, the compiler normally (absent the /S switch) lists the included file names as it processes them, indenting to indicate the level, e.g.:

.compil sqltest4/x:2

Phase 1 - Initial work memory is 16944 bytes

Copying from ASHELL.DEF[907,16]

Copying from FNSQLSTATE.BSI

Copying from FNEXTCH.BSI[907,10]

?Syntax error (++40) - this is an error

Copying from FNSQLATR.BSI

...

The above example illustrates two levels of ++include processing. The files ashell.def and FNSQLSTATE.BSI are included directly from the main program at the first level, and the file FNEXTCH.BSI is included from within FNSQLSTATE.BSI at the second level, which we can tell based on the fact that it is indented. The standard error message does not directly indicate which file the error occurred in, but it outputs a "+" in front of the line number for each level of ++include nesting. Thus, the "(++40)" tells us that the error was in a module nested two levels below the main program, which could only be FNEXTCH.BSI in this example.

Another option would be to use the COMPIL Background switch, which causes the compiler to output a <prog>.LST file containing details for each error, including the module file name.

Another useful function is offered by the COMPIL List File (LF) switch, which creates a consolidated List File containing all of the ++included modules. The file is designed mainly to use as a cross reference for linking runtime errors to the original source code, but could be used as an aid to studying all the parts of the program in one listing.

Yet another option would be to use The A-Shell Editor, a multi-file program editor capable of identifying all of the included modules associated with the main source and jumping between them as needed.

See Also

Discussion on A-Shell forum.


One-Time ++Includes

++INCLUDE'ONCE <fspec>

This directive acts just like the regular ++include, except that if the specified file has already been included in the current compilation, then it is skipped. This largely solves the problem—introduced by nesting—of accidentally including the same file twice. In fact, in most cases you may want to just use ++include'once all the time. It is somewhat unlikely that you would deliberately want to include the same file twice, but one possibility would be a set of map statements that you want to use locally within multiple functions.

To help you visually confirm the operation of skipping redundant ++includes, the compiler will indicate them as in this example:

Phase 1 - Initial work memory is 16944 bytes

Copying from ASHELL.DEF[907,16]

Copying from SQL.DEF

Copying from FNSQLCON.BSI

Copying from FNSQLSTATE.BSI

Skipping sql.def (already included)

Copying from FNEXTCH.BSI[907,10]

Copying from FNSQLATR.BSI

...

++INCLUDE'ONCE is useful for allowing individual modules to explicitly include their own dependent modules without having to know whether other modules in the program have already done so. But, it depends on using the option everywhere. An alternative or additional technique for avoiding including a module more than once, which does not rely on the consistent use of ++INCLUDE'ONCE, is to enclose each module inside a conditional compilation statement as follows:

! foo.bsi

++ifndef INC_FOO_BSI_

define INC_FOO_BSI_ = 1

<contents of the module>

++endif

In the above example, the module is only included if the specified symbol is not yet defined. Since it gets defined immediately after the test, we can be sure that the contents of the module will only be included once. Although there is no enforced standard for the symbol names, to be practical, they need to be unique. Thus it is wise to form the symbol by appending some prefix and/or suffix to the module name.

See Also

• Using Conditionals to Avoid Duplicate Includes


PRAGMAs

Updated February 2013 (see PRIVATE_...)

PRAGMAs are commands to the compiler to specify compilation options or otherwise modify its behavior. The general syntax is:

++PRAGMA <pragma> {options}

For example:

++PRAGMA FORCE_EXT "LIT"

where the available pragmas and associated options are listed in the tables below.

A-Shell PRAGMAs

The following PRAGMAs are supported only when A-Shell Extensions are enabled (X:2 compiler switch).

A-Shell PRAGMA | Description
ALIGN2 | Align MAP1 variables on 2 byte boundaries (default). See Alignment below.
ALIGN4 | Align MAP1 variables on 4 byte boundaries. See Alignment below.
ALIGN8 | Align MAP1 variables on 8 byte boundaries. See Alignment below.
EXTERN_BEGIN, EXTERN_END | Bracket MAP statements used to declare Global/External Variables.
SBX | Same as /X:3 (create an SBX instead of RUN).
TRACK_LAST_ROUTINE <boolean> | Updates .LAST_ROUTINE (see Dot Variables) each time a function or procedure is called.
TRACK_LAST_LABEL <boolean> | Updates .LAST_LABEL (see Dot Variables) each time execution passes a label in the program.
AUTO_EXTERN <boolean> | Used within User-Defined Functions or Procedures to allow the use of global variables within the local routine. Also see Global/External Variables.
PRIVATE_BEGIN and _END | Used within ++include files to ensure that the module's private variables (MAP and DIMX) are initialized once and only once before they are used.
GLOBAL_BEGIN and _END | Similar to PRIVATE_BEGIN and PRIVATE_END, except that they declare a block of variables intended to be visible to any other module in the program.
ASHELL_EXTENSIONS <boolean> | Enables/disables the switches /X:2, /P, and /PX respectively. The <boolean> argument is optional and defaults to "TRUE". Must be placed before any other code, except for comments, ++pragmas, ++IFxxx conditionals, and the PROGRAM statement.
PRE_PROCESS <boolean>
EXTENDED_PRE_PROCESS <boolean>
INCLUDE_GLOBAL_ONCE_ONLY <boolean> | When enabled, ++include is treated as ++include'once, except when it occurs inside a function or procedure. In such cases, it is likely that you are intentionally including an extra copy of some map statements.

BASIC Plus PRAGMAs

The following PRAGMAs are supported in BASIC Plus mode (X:1 compiler switch).

BASIC Plus PRAGMA | Description
NO_LINE_NUMBERS <boolean> | Same as /O
ERROR_IF_NOT_MAPPED <boolean> | Same as /M
FORCE_24_BIT <boolean> | Same as /A
FORCE_EXT "ext" | Force compiler output to use "ext" extension instead of .RUN.
FORCE_FSPEC | Allows you to change the name of the output file.
FORCE_IEEE <boolean> | Forces a floating point variable which does not have an explicit size to be treated as F,8 (rather than F,6). Also requires /X:1 or higher.
FORCE_OLD_ISAM <boolean>. | This is the equivalent of /I, causing the compiler to assume ISAM 1.x for OPEN statements that are otherwise ambiguous. Unlike /I, it can be turned on and off for different sections of the source code.

Valid replacements for the "boolean" argument are (not case sensitive): "YES", "TRUE", 1 or "NO", "FALSE", 0. Beginning with A-Shell 6.3.1528, the default for all pragmas accepting a <boolean> argument is "TRUE". Previously some of them required an explicit argument while others did not. For example, the following two are now equivalent, though previously , the first one would have triggered an invalid argument error:

++pragma ERROR_IF_NOT_MAPPED

++pragma ERROR_IF_NOT_MAPPED "TRUE"

AlphaBASIC PRAGMAs

The following PRAGMAs from Alpha BASIC Plus are recognized but ignored by A-Shell because the associated function is not important or relevant under A-Shell. The important point is that by being recognized, they do not generate compile errors, thereby keeping your code (more) source-compatible with AMOS.

• FORCE_SBR_EXT (see FORCE_EXT and SBX)

• LIFESIGNS (hardly needed when compilation time is measured in milliseconds)

• ADD_EXTRA_STRWRK (A-Shell's string work area can use the entire memory partition)

• EXTRA_STRWRK

• SET_SETWRK

Alignment

Align MAP1 variables on 8 byte boundaries. Aligning on 4 or 8 byte boundaries may be more efficient on modern processors, and can be useful for matching data layouts originating in other languages (such as C). But beware of the effect this can have when using map overlays. For example:

MAP1 A1,S,5

MAP1 A2,S,5

MAP1 AX,S,16,@A1

Under the normal 2-byte alignment, A2 will start in the 6th position of the AX overlay. But with 4 byte alignment, it would start in the 8 position.

See Also

MESSAGE

ERROR

History

2014 July, A-Shell 6.1.1387: Compiler refinement (edit 679) - ++PRAGMA ERROR_IF_NOT_MAPPED "FALSE" may now be used to override /M or a previous "TRUE". Previously it was only possible to enable the /M switch, not disable it. Note that you can now turn the option on and off multiple times within a program, allowing you to get the benefit of the for new sections of code without being forced to clean up the unmapped variables in all of your code—i.e. in all of your include modules.

Subtopics

FORCE_FSPEC

PRIVATE_BEGIN and _END

GLOBAL_BEGIN and _END


FORCE_FSPEC

Similar to FORCE_EXT <ext>, this pragma allows you to change the name of the output file generated by the compilation. The name you specify may optionally contain an extension (in which case it overrides the extension previously established by default or by prior pragmas), and it may be in native or AMOS format. It may also contain "%s" to indicate the simple name of the current source file. (This allows you to use a common pragma, perhaps via a ++INCLUDE, which specifies an alternate location for the run file.) Note that in all cases the filespec should be quoted. Examples:

++PRAGMA FORCE_FSPEC "fred"

++PRAGMA FORCE_FSPEC "BAS:MYNAME.RRR"

++PRAGMA FORCE_FSPEC "/vm/miame/run/abcdef"

++PRAGMA FORCE_FSPEC "NEWRUN:%s"


PRIVATE_BEGIN and _END

Update November 2016; see History

++PRAGMA PRIVATE_BEGIN

<map and dimx statements>

++PRAGMA PRIVATE_END

This set of pragmas may be used within ++include files to ensure that the module's private variables (MAP and DIMX) are initialized once and only once before they are used, regardless of the position of the ++include in the main program. Previously, without the benefit of the new pragmas, it was left to the programmer to make sure that any such MAP statements containing initializers, and any DIMX statements, got executed, just once, before being used. Typically that required that the ++include be at the top of the main program, so that execution fell through the MAP and DIMX statements before the main program started executing, or it required a static control variable and some conditional logic within the ++include module to keep track of whether the initializations had occurred.

Using these pragmas, the compiler takes care of the problem, making sure that the enclosed MAP and DIMX statements are initialized before any of the functions or procedures within the module are executed.

Secondarily, as a syntactic convenience, the keyword PRIVATE will be automatically added to any MAP or DIMX statement enclosed by the pragmas if not already explicitly specified. Thus, if you really do want to specify global variables within such a ++include module, you must keep then outside the set of pragmas lest they be turned into module private variables.

Notes

• Each ++include module can have only a single pair of these pragmas

• The feature is entirely implemented in the compiler, so there is no requirement for a corresponding update of the runtime system.

• Other kinds of statements may be included within the PRIVATE_BEGIN and _END pragmas, such as assignments or function calls related to initializing the private variables. As with the MAP and DIMX statements, they would be guaranteed to execute prior to any of the functions or procedures within the module, and only once.

Example

! (main program)

...

if Fn'GetTableItem$(X) = "" then

call SetTableItem(X, "Behold!")

endif

...

++include table.bsi

- - - - - - - - -

! (table.bsi)

++pragma private_begin

map1 table'max,f,6,5000

dimx table(table'max),s,100

++pragma private_end

...

Function Fn'GetTableItem$(idx as f) as s100

if (idx <= table'max) then Fn'GetTableItem$ = table(idx)

EndFunction

Procedure SetTableItem(idx as f, item$ as s100)

if (idx <= table'max) then table(idx) = item$

EndProcedure

In the above example, the module table.bsi contains a private DIMX array table() which is shared by the function and procedure in the module. Because the module is included at the bottom of the main program, without the ++pragma private_begin, the array would still be unitialized at the point it was referenced in the Fn'GetTableItem$() function, leading to an error. To correct for that, the ++include statement would have to be moved to the top of the main program, but that is an undesirable dependency which the programmer creating the table.bsi would rather not have to depend on. And it is otherwise not easy to code around the problem. But with the ++pragma private_begin, the problem disappears.

History

2016 November, A-Shell 6.3.1534, compiler edit 790: use of .ARGCNT within a PRIVATE_BEGIN / PRIVATE_END block now generates a compile error. Although the expression wouldn't technically be illegal, because the PRIVATE block is essentially called for initialization by whatever function or procedure in the module gets called first, there's really no good way to predict in advance what the .ARGCNT value will represent, and thus it is almost certain to create a discrepancy between the expected and actual behavior.

2013 February, A-Shell 6.1.1338: Pragmas added to A-Shell, compiler edit 624.


GLOBAL_BEGIN and _END

Added October 2014

These are similar in concept to the pragmas PRIVATE_BEGIN and PRIVATE_END, except that they declare a block of variables—and possibly some instructions related to initializing those variables—intended to be visible to any other module in the program.

Although non-PRIVATE variables defined outside of functions and procedures are already global, the difference here is that the section of variable and code gets effectively moved to the start of the program (see clarification below) so that the variables are all defined and initialized before any other code that may reference them. This feature is intended to help programmers modernize old-style ++include modules which suffer from the use of un-mapped variables, and/or which are sensitive to the order in which they are included in the main program.

Clarification: by default, the GLOBAL_BEGIN/END code is moved to the start of the program. But in some cases that may not be quite ideal, for example where the MAP statements or code require definitions from, say, ashell.def. To give you that flexibility, you can specify the location where you want the global code to be inserted via a special ++include statement:

++include $GLOBALS ! insert GLOBAL_BEGIN/END blocks here

This acts like a normal ++include except that instead of referencing a static file, it collects up all the code in the GLOBAL_BEGIN / END blocks and creates a virtual include file on the fly. Technical note: the global blocks will actually be copied to a temporary file cmpglobals.tmp, which you can examine for debugging purposes.

For include modules with unmapped variables, the recommendation would be to add a GLOBAL_BEGIN/END block to explicitly map the variables used in the module. For example, to take an extremely simple case, imagine an include module containing a routine to close a file:

CLOSE'FILE: ! caller sets CH

CLOSE #CH

RETURN

The problem with this module is that it references a variables, CH, which is not mapped or initialized here, thus requiring the calling programs to compile without the /M switch, or to figure out how and where to map/init it. It probably should be converted to a function, passing the channel explicitly, but that would definitely require changing all of the code that uses this function, which we're trying to avoid. Without the new pragmas, to fix the unmapped variable problem, could insert a map statement into the module, but unless the module was included at the top of the program, it is likely that code that calls the module would not yet have seen the MAP statement, and thus would still get an unmapped variable reference. And if you did include it at the top of the program, you would also have to insert a GOTO statement and label to jump over the CLOSE'FILE routine, lest it get executed during the program startup. And even then, if the routine was referenced by other included modules, you could easily get into "include sequence hell", where you endlessly shuffle the sequence of ++includes trying to come up with an order that manages to have all the variable definitions occur before they are referenced.

Another approach to solving that problem would be to split the module into two parts - a .MAP to be included at the top of the program, and a .BSI to be included at the bottom. That works, but introduces module clutter, which tends to encourage combining the .MAP modules, but that leads to variable definition bloat and general confusion.

With the new pragma, we can insert the following at the top of the module:

++PRAGMA GLOBAL_BEGIN

MAP1 CH,B,2

++PRAGMA GLOBAL_END

Now, when we compile it, the definition of CH will get moved to the top of the program (or to a specified location - see below) eliminating the forward-reference problem. Existing programs can just be recompiled without any other changes, unless they actually did map the CH variable, in which case that map would have to be removed. But it is likely that any such map statement would be in a common include, so you can probably just add a ++IFNMAP CH conditional to that to fix it in all cases.

Of course this is an extremely simplistic example. In a more realistic case, you may have many variables used within a BSI, some of which are truly local and should be declared PRIVATE, and others which may require some explicit initialization code. But the principle remains the same - whatever you put between the GLOBAL_BEGIN and GLOBAL_END pragmas will be made globally available to the rest of the program without you having to make any other adjustments to external code, other than recompiling the programs that use this module.

Note: the feature requires the /P (or -p) compile switch, but does not require any particular run-time version. The RUN files can even be AMOS compatible, if you stick with the /RC option.

History

2014 October, A-Shell 6.1.1392: Add to A-Shell


Conditional Compilation

The following directives may be used to mark sections of code to be conditionally compiled, based on whether a symbol, variable or label has been defined, or whether a constant expression is true or false. They are analogous to the IF/ELSEIF/ELSE/ENDIF statements except that they affect the operation of the compiler—determining which statements are compiled and which are ignored—rather than the runtime interpreter. The feature requires compiler switch /RC or /X:1 or higher.

Directive | Description
++IF, ++ELIF | Conditionals based on evaluating a constant expression; see below.
++IFDEF, ++IFNDEF, ++ELIFDEF | Conditional based on whether the specified symbol or structure has been previously defined.
++IFLBL, ++INFLBL, ++ELIFLBL | Conditionals based on whether specified label has been defined; see below.
++IFMAP, ++IFNMAP, ++ELIFMAP | Conditionals based on whether specified variable has been mapped; see below.
++ELSE | Used as an optional final clause preceded by any other type of ++IFxxx and ++ELIFxxx statements. The lines following the ++ELSE up to the ++ENDIF are compiled only if all of the preceding clauses were false.
++ENDIF | Marks the end of the conditional construct.
Using Conditionals to Avoid Duplicate Includes |
COMPILER_VERSION Macro |

Example1

++IFDEF GUI

PROGRAM MYPROG,1.0G(100)

<source code implementing GUI version here>

++ELSE

PROGRAM MYPROG,1.0(100)

<source code implementing text version here>

++ENDIF

The above illustrates one way to use conditional compilation to conditionally create either a GUI or text version of your RUN file, starting from the same source file. Previously you could only do the same thing with runtime conditions (which may still be a better option in most cases), but in some cases, you may prefer to have two separate versions of the RUN (perhaps to keep the size down, or to simplify runtime debugging.) Note that the symbol GUI would have had to have been defined somewhere prior to the compiler seeing these statements; see below for how to define symbols on the command line.

Also note that we used two different versions of the PROGRAM statement in the above example, so that you can easily tell which RUN version you have by displaying it with DIR/V.

Example2

++IF APPVER = 1

++MESSAGE Compiling Version 1

ver1.bsi

++ELIF APPVER = 2

++MESSAGE Compiling Version 2

ver2.bsi

++ELSE

++ERROR No APPVER defined!

++ENDIF

This illustrates the IF/ELIF/ELSE/ENDIF construct, used to select which ++INCLUDE file to use based on the defined APPVER. See the ++MESSAGE and ++ERROR statements.

Example3

++IFDEF SBX

++PRAGMA SBX

<retrieve parameters, SBX setup, etc.>

++ENDIF

This illustrates a simple way to allow a single source file to be compiled as either an SBX or a RUN file. (The SBX symbol would need to be defined on the compiler command line, e.g. COMPIL MYPROG/X:2/C:SBX=1)

++IFDEF MODE_SBX

++PRAGMA SBX

<retrieve parameters, SBX setup, etc.>

++ELIFDEF MODE_LIT

++PRAGMA FORCE_FSPEC SYS:MYPROG.LIT

<command line parsing>

++ELSE

<standard RUN setup>

++ENDIF

This illustrates an approach to generating either an SBX, LIT, or RUN from the same source file. (The MODE_SBX or MODE_LIT symbols would need to be defined on the compiler command line, e.g. COMPIL MYPROG/X:2/C:MODE_SBX=1)

History

2013 March, A-Shell 6.1.1346: Add ++ELIFDEF and ++ELIFMAP

2011 November, A-Shell 6.0.1240: Increase maximum nesting levels for conditional compilation statements from 5 to 13.

Subtopics

++IF, ++ELIF

++IFDEF, ++IFNDEF, ++ELIFDEF

++IFLBL, ++INFLBL, ++ELIFLBL

++IFMAP, ++IFNMAP, ++ELIFMAP

Using Conditionals to Avoid Duplicate Includes


++IF, ++ELIF

Updated March 2017; see History

The statement " ++IF <constant expression> " evaluates the specified expression and compiles the following statements if the expression is equivalent to TRUE. Constant expressions are a subset of regular BASIC expressions, made up only of defined symbols (constants) and literals (i.e. no variables), and a limited set of pre-defined functions and operators:

• All arithmetic operators (+,-,/,*,**,^,MOD)

• All logical operators (AND, OR, NOT)

• Comparison operators (<, >, <=, >=, ==, <>, #)

• All bitwise operators (AND, OR, NOT, NOR, XOR)

• Arithmetic functions: int(),fix(),abs(),min,max

• Scientific functions: exp(),sgn(),sqr(),sin(),cos(),tan(),atn(),fact()

• String functions: +,left(),mid(),right(),[a,b],len(),instr(),asc(),chr(), str(),val(),rtrim(),edit(),strip(),pad(0

• File functions: lookup()

++ELIF <constant expression> is equivalent to ++IF <constant expression> except is only evaluated if the preceding ++IF or ++ELIF expression(s) were false. See example below.

Examples

++IF APPVER > 3

<statements>

++ENDIF

++IF SITE_NAME$ = "MARS"

<statements>

++ELIF SITE_NAME$ = "JUPITER"

<statements>

++ELIF SITE_NAME$ # LOCAL_PLANET$

<statements>

++ENDIF

++IF (APPVER > 3) AND (LOOKUP("xyz.bsi") # 0)

<statements>

++ELSE

<statements>

++ENDIF

Note that the above examples are only valid if APPVER, SITE_NAME$, and LOCAL_PLANET$ are DEFINE'd symbols. Variables would not be acceptable because their values are not constant from the compiler's perspective. The LOOKUP expression is acceptable as long as the filename is constant, i.e. a literal string as in the example, or a DEFINEd symbol.

History

2017 March, A-Shell 6.4.1546, compiler enhancement (797): maximum nesting levels for ++INCLUDE and ++IF conditions increased from 20 to 40. Improve messaging/recovery for the overflow condition.


++IFDEF, ++IFNDEF, ++ELIFDEF

These directives may be used to conditionally compile sections of code based on whether a specified symbol or structure name has been defined, via DEFINE, Compiler Symbol Definitions, or DEFSTRUCT.

One typical use is to compile separate bits of code based on a prior symbol definition, for example:

++ifdef VER_WIN

MAP1 TEMPDIR,"c:\temp"

++elifdef VER_UNIX

MAP1 TEMPDIR,"/tmp"

++else

MAP TEMPDIR,"%TEMP%"

++endif

In the above example, the symbols VER_WIN or VER_UNIX might have been defined via a DEFINE statement or via the /C switch passed to the compiler.

Another typical use is to avoid redundantly processing a ++include module that may have already been compiled. See Using Conditionals to Avoid Duplicate Includes.


++IFLBL, ++INFLBL, ++ELIFLBL

Added April 2014

These are analogous to the existing ++IFDEF, ++IFNDEF, and ++ELIFDEF statements, as well as ++IFMAP, ++IFNMAP and ++ELIFMAP, except that instead of referring to defined symbols or mapped variables, they refer to labels—used by GOTO and GOSUB—as well as procedure and function names. Note however that when the specified label is meant to refer to a function or procedure name, it must be terminated by an empty pair of parentheses. For example:

++IFLBL MAIN

++MESSAGE The label MAIN is defined

++ELIFLBL MAIN()

++MESSAGE The procedure MAIN() is defined

++ELIF fn'main()

++MESSAGE The function fn'main() is defined

++ENDIF

Also note that labels, like variable names, are case sensitive, unless you compile with the /CI switch.

History

2014 April, A-Shell 6.1.1382, compiler edit 655: add all three statements to A-Shell


++IFMAP, ++IFNMAP, ++ELIFMAP

These conditionals may be used to conditionally compile sections of code based on whether a specified variable has been mapped. For example:

++IFMAP WORK'VARS

<work statements>

++ELIFMAP PLAY'VARS

<play statements>

++ELSE

MAP1 WORK'VARS

MAP2 JOB$,S,10

MAP1 PLAY'VARS

MAP2 GAME$,S,10

++ENDIF

Note that even when used within a ++include file, or a procedure/function, the variable name evaluated by the conditional is treated as global, and thus will not work as expected if the variable you are referring to was defined privately or locally. For example, both of the following conditions will act based on whether the specified variable has been previously mapped globally, even though you may be expecting otherwise:

++IFNMAP Module_Private_Var

PRIVATE MAP1 Module_Private_Var,B,1

++ENDIF

Procedure Test()

++IFNMAP FLAG

MAP1 FLAG,B,1

++ENDIF

...

EndProcedure

This is because private variables (and local variables) are defined in separate areas relative to their scope, but the conditional statements have no good way of knowing which context you are referring to, and checking multiple contexts would introduce another layer of confusion, so they always refer to the global context.


Using Conditionals to Avoid Duplicate Includes

One common use for conditional compilation statement is to prevent a common include file—which may be referenced by multiple modules—from being processed more than once. You can also use ++include'once (see One-Time ++Includes) but that depends on consistent use through all the code which may reference an include file. Adding conditionals within the include file itself can prevent the problem of duplicate includes without requiring any cooperation on the part of any external modules.

A common approach to protecting against duplicate include processing is to define a special symbol that indicates that the module has already been included, and then add a conditional which prevents processing of the module if the symbol has already been defined. For example:

! MYMODULE.BSI

++IFNDEF INC_MYMODULE_BSI_

DEFINE INC_MYMODULE_BSI_ 1

<contents of the module>

++ENDIF

In the above example, the first time the compiler sees the code, the symbol INC_MYMODULE_BSI_ will not have been defined, so it proceeds to process the module (including defining the symbol). On subsequent passes through this module, the symbol will have been defined, so the conditional will cause the module contents to be skipped.

For modules that define symbols or structures, you may avoid the need to define an artificial symbol just to track whether the module has been compiled, by referencing one of the DEFINE or DEFSTRUCT symbols in the file, i.e

++IFNDEF ST_CUSTOMER

...

DEFSTRUCT ST_CUSTOMER

MAP2 ...

...

ENDSTRUCT

...

++ENDIF

Similarly, if the module maps variables or defines any labels or functions/procedures, you can use ++IFNMAP <variable> or ++INFNLBL <label>, for example:

++IFNMAP MYMODULE'VARS

...

MAP1 MYMODULE'VARS

MAP2 ...

...

++ENDIF

Note that in the above case, the variable referenced in the ++IFNMAP must have global (not private or local) scope. See ++IFMAP, ++IFNMAP, ++ELIFMAP .

Or, to use the same idea but with a label or procedure name instead of a variable:

++IFNLBL MyProc()

...

Procedure MyProc()

...

EndProcedure

...

++ENDIF

Also See

COMPILER_VERSION Macro

History

2014 March, A-Shell 6.1.1382 (Compiler edit 655): Add ++IFLBL, ++ELIFLBL, ++IFNLBL


MESSAGE

The compiler directive ++MESSAGE message simply outputs a literal text message to the screen during compilation. This is generally useful in conjunction with Conditional Compilation (in which see Example 2) to give the programmer visual confirmation that the conditions are being interpreted as intended, or to warn of unusual or questionable environmental conditions. The remainder of the line following the keyword ++MESSAGE is output literally, as-is, to the screen, without any regard to punctuation or delimiters. Example:

++MESSAGE This is an example of a compiler message


ERROR

The compiler directive ++ERROR message outputs a message (as with ++MESSAGE) but also generates a compiler error. As with ++MESSAGE, it is mainly used in conjunction with Conditional Compilation (in which see Example 2) to make sure that the programmer doesn't overlook and important problem. Example:

++IF TARGET_PLATFORM = 1

++MESSAGE Compiling for platform Windows

++ELSE

++ERROR This program only supports Windows - must use /C:TARGET_PLATFORM=1

++ENDIF


Defined Structures

Updated July 2010

See History at bottom.

As of A-Shell 6.0.1123 of September 2008, it is possible to assign a type name to a set of MAP statements and then use that as if it was a data type. This comes in very handy for storing multiple copies of a particular data structure, as well as for passing structures as parameters (e.g. data encapsulation).

To define a structure, use the DEFSTRUCT and ENDSTRUCT keywords, to enclose a set of MAP statements (levels 2 thru 9). For example:

DEFSTRUCT ST'PHONE

MAP2 DESCR,S,20 ! e.g. Front Office, Accounts Payable, etc.

MAP2 TYPE,S,6 ! e.g. cell, bus, home, pager

MAP2 XNUM

MAP3 COUNTRYCODE,S,3

MAP3 AREA,S,3

MAP3 NUMBER,S,10

ENDSTRUCT

DEFSTRUCT ST_CUS

MAP2 ID,S,6

MAP2 NAME,S,30

MAP2 PHNUM(5), ST'PHONE ! array of ST'PHONE structures

MAP2 BALANCE,F

ENDSTRUCT

MAP1 SALE, ST_CUS ! SALE is an instance of structure ST_CUS

MAP1 PROSPECT(10), ST_CUS ! PROSPECT() is an array of struct ST_CUS

DIMX CLIENTS(N),ST_CUS ! Dynamic array of structures

MAP1 PH$, ST'PHONE ! PH$ is an instance of struct ST'PHONE

...

PH$ = FN'GETPHONENUM$(SALE,"cell") ! retrieve cell # from customer SALE

FUNCTION FN'GETPHONENUM$(cus as ST_CUS, type$ as S6) as ST'PHONE

map1 locals

map2 i,f

! locate phone number by matching type

for i = 1 to 5

if cus.PHNUM.TYPE(i) = type$ then

FN'GETPHONENUM$ = cus.PHNUM(i)

endif

next i

ENDIF

The above example illustrates defining two structures, ST_PHONE and ST_CUS. (Structures have the same naming flexibility as other variables, but it seems like a useful convention to prefix their formal names with ST_ to avoid confusion with variable names.) The ST_CUS structure contains an array of ST_PHONE structures, illustrating that they can be nested. The example then defines an instance of the ST_CUS structure called SALE, a fixed array of instances call PROSPECT(), a dynamic array called CLIENTS(), and an instance of the ST_PHONE structure called PH$.

The following shows the equivalent (fully expanded) form of MAP1 SALE, ST_CUS :

MAP1 SALE

MAP2 SALE.ID,S,6

MAP2 SALE.NAME,S,30

MAP2 SALE.PHNUM(5)

MAP3 SALE.PHNUM.DESCR,S,20

MAP3 SALE.PHNUM.TYPE,S,6

MAP3 SALE.PHNUM.XNUM

MAP4 SALE.PHNUM.COUNTRYCODE,S,3

MAP4 SALE.PHNUM.AREA,S,3

MAP4 SALE.PHNUM.NUMBER,S,10

Note the use of the period to separate the names of structure instances from the fields in the structure.

Also note that the syntax for accessing individual members of dynamic arrays of structures is different; see Dynamic Array of Structures for details.

Warning: initial values for individual mapped fields within a structure definition are allowed for mapped instances of the structure, but not for DIMX; see Dynamic Array of Structures. Prior to compiler edit 521, such initial values led to runtime errors; after that the compiler just ignored the initial values. See this more detailed discussion on the A-Shell forum.

So, for example, you might read the structure from a disk file and then print out the ID field as follows:

READ #CH, SALE

PRINT "Customer ID = ";SALE.ID

Defined structure names may be used similarly to the unformatted type X, and passed to functions and procedures. In the example above, the function FN'GETPHONENUM$() takes a ST_CUS structure as an argument, and returns a ST'PHONE structure.

Defined structure names may end in $, but the $ is dropped when referencing the individual fields. For example:

defstruct ST_CUS

map2 id,s,10

map2 name$,s,30

endstruct

map1 cus$,ST_CUS ! structure names may end in $

map1 tmpcus,ST_CUS ! (or not)

! use the $ when referring to the structure as a whole

tmpcus = cus$

! drop the $ from structure name when referring to individual fields

cus.id = "A12345"

! field names may end in $, just like any other variable

cus.name$ = "Agamemnon"

(Note that because function names must contain a $ suffix if the function returns an S or X value, and since structures are essentially a special variation of the X type, any function returning a structure must have a $ on the end of the name.)

The formal parameter "cus as ST_CUS" essentially creates a set of local map statements which are identical to the ones shown above for SALE, except with "SALE." replaced by "cus." Otherwise, in terms of parameter passing, the "cus as ST_CUS" parameter is equivalent to "cus as X246". (Previously, this is how you had to pass the structure, and then you had to repeat the MAP2-MAP9 levels of the structure map statements within the Function. So the new method doesn't exactly add any new capability, but it makes using structures and especially passing them between routines much cleaner and easier.

One way to help clarify the effect of structure definitions is to compile with the /L switch, in which case the expanded forms of the structures will display in the LSX file.

See Also

Dynamic Array of Structures

Forum discussion

History

2010 July, A-Shell 5.1.1187: Compiler edit 456: reserved words are now allowed for field names within a DEFSTRUCT. For example:

DEFSTRUCT ST_TIMEDATE

MAP2 TIME,B,4

MAP2 DATE,B,4

ENDSTRUCT

Normally TIME and DATE would be disallowed since they are reserved words, but since they get appended to the structure instance name before really being used, there is no conflict here.

2008 September, A-Shell 5.1.1124: Initial values and overlays are now supported within DEFSTRUCT / ENDSTRUCT.

2008 September, A-Shell 5.1.1123: DEFSTRUCT now allows upper and lower case (or mixed case) formal structure names, and STATIC and PRIVATE instances of structures now allowed. Note that DIMX does not support structures.


Auto-Defined Macros

Added November 2016

 | Description
COMPILER_VERSION | See link at left.
ABC_CURRENT_ROUTINE$ | These equate to the current function/procedure name (or "" if none), and the current module filename (file.ext). Both may be useful in standardized error reporting.
ABC_CURRENT_MODULE$
ABC_NAMED_PARAMS | Is defined (=1) automatically when the /P compiler switch is used, i.e. indicates that there is support for named parameters

History

2016 September, A-Shell 6.3.1528, compiler edit 778: Add ABC_CURRENT_ROUTINE$ and ABC_CURRENT_MODULE$.

2014 October, A-Shell 6.1.1392, compiler edit 711: Add COMPILER_VERSION.

2014 January, A-Shell 6.1.1373, , compiler edit 650: Add ABC_NAMED_PARAMS.

Subtopics

COMPILER_VERSION Macro


COMPILER_VERSION Macro

Added February 2015

The compiler internally defines a macro symbol COMPILER_VERSION to the compiler edit number, allowing you use it in a conditional compilation statement to avoid or warn about code that requires a minimum compiler version. For example:

++IFNDEF COMPILER_VERSION

++ERROR Compiler version too old (pre 711)

++ENDIF

++IF COMPILER_VERSION >= 710

DEFTYPE BOOLEAN I,2

++ENDIF

++IF COMPILER_VERSION < 728

++ERROR Program requires compiler version 728+ for .LINENO(ch) function

++ENDIF

Note: Unfortunately, since the COMPILER_VERSION macro was introduced in edit 711, an attempt to reference its value in a prior version will generate a "conditional expression not constant" error, so that will only be useful going forward. However, you can use ++IFDEF to test if it's defined—and if not, you will know that it is prior to version 711.

History

2014 October, A-Shell 6.1.1392, compiler edit 711: added to A-Shell


Numeric Functions

Updated July 2016; see History

These functions all return numeric values, although some may operate on string arguments.

Function | Description
ABS(x) | Returns absolute value of x.
EXP(x) | Returns the constant e (2.718218285) raised to the power x.
FACT(x) | Returns the factorial of x.
FIX(x) | Returns the integer part of the floating point value x.
INT(x) | Returns the largest integer less than or equal to x. (FIX(x) and INT(x) are same for positive numbers, but differ for negative numbers)
LEN(a$) | Returns length of string A$. Note that if a$ is actually a variable of type x, the returned length will always be the physical mapped size of the variable. Otherwise, for strings (type S), the returned length will be determined by the first null byte or the physical mapped length, whichever is smaller.
LOG(x) | Returns the natural (base e) log of x.
LOG10(x) | Returns the decimal logarithm of x.
RND(x) | Depending on x, either returns a pseudorandom value in the range of 0 to 1 based on a previously set seed, or establishes the seed. See RND2() for an enhanced implementation.
RND2() | Returns the next random number per the initialization/state set by SRND2(x,...). Enhanced version of RND(x).
SRND2(x...) | Initializes the RND2() generator.
SGN(x) | Returns the sign of x: -1 if x < 0, 0 if x = 0, 1 if x > 0.
SQR(x) | Returns the square root of x.

History

2016 July, A-Shell 6.3.1517: Add second random number generator, RND2 and SRND2.

Subtopics

Random Number Generators


Random Number Generators

A-Shell supports two pseudorandom number generation algorithms, exposed via the following three functions:

RND(seedop)

RND2()

SRND2(seed {,ubound, lbound {,stream}})

RND(seedop) has been included in A-Shell since version 1.0, and is semantically compatible with the AMOS function of the same name. That is to say, it is source and run time compatible, but doesn't generate the same sequence of output values as the AMOS version. Based on the standard C library functions rand() and srand(), which are in turn based on different underlying algorithms on different operating system platforms, its output varies across platforms and possibly even versions of the same platform. Depending on the seedop parameter, RND(seedop) either initializes the generator or returns the next value. The values returned are always in the range of 0 to 1.

RND2() was introduced in A-Shell version 6.3.1517, and is not in any way compatible with the AMOS version. However, because it is implemented directly within A-Shell, it is guaranteed to be stable and compatible across all A-Shell platforms and versions going forward, which is important for certain encryption and testing applications. It is also offers some other advantages, described below. RND2() takes no parameters; it only returns the next value, based on the initialization/state. The values returned may be fractional in the range of 0 to 1, or they may be integers in an arbitrarily specified range, depending on the initialization parameters.

SRND2(seed {,ubound, lbound {,stream}}) initializes the RND2() generator.

Parameters

seedop (32 bit integer)

If >= 0, causes the function to return the next value in the sequence. If < 0, acts as the seed to initialize the RND() generator. You can also establish a randomly selected seed by executing the RANDOMIZE statement.

seed (32 bit integer)

establishes the initial state of the RND2() generator. A seed value of 0 results in a randomly selected seed, equivalent to executing the RANDOMIZE statement.

ubound, lbound (32 bit signed integer)

optionally determine the range of returned values. If omitted or equal to each other, the range of returned values will be from 0 to 1 (fractional) as with the traditional RND(x). Otherwise, the returned values will be integers, uniformly distributed across the range specified by lbound and ubound, inclusive.

stream (32 bit integer)

optionally selects one of 2^32 “streams” or sequences within a given seed. Combining 2^32 streams with 2^32 seeds increases the universe of possible sets/sequences of random values dramatically. Note that for a given seed, different streams are guaranteed never to overlap each other. The default stream is 0, which, unlike the case with seed, does not result in a randomly selected stream.

Comments

If RND2() is called without first initializing the generator with SRND2(seed,...), it will be automatically initialized as if SRND2(0) had been called, i.e. a random seed will be selected and the range of returned values will be from 0 to 1 (fractional).

The RANDOMIZE statement initializes both generators to a non-deterministically selected psuedorandom seed and, in the case of RND2(), stream. It does not affect previously established lbound and ubound values.

Aside from stability and uniformity, the RND2() generator offers some additional benefits:

• The lbound,ubound feature makes it much easier and faster to generate integers in a particular range, which is probably the most common usage. It also eliminates the floating point rounding problem which might otherwise result in a fractional value very close to 1 acting as equivalent to 1 in an expression, which in turn could cause program logic intending to generate values in a range of 1 to N—e.g. INT(RND(1)*N)+1—to generate a value N+1, leading to application errors.

• RND2() is much less predictable than RND(), making it superior for cryptographic uses.

• RND2() has a wider, more granular range of output values, especially compared to the Windows implementation of RND(seedop) which is limited to 16 bits.

• Splitting it into two functions, one to initialize and one to generate, reduces the confusion inherent in the multiple operations of RND(seedop).

RND2() is based on the PCG family of random number generators; see www.pcg-random.org for more information.

Warning: attempting to run a program containing RND2() or SRND2() in a version of A-Shell prior to 6.3.1517 will generate an unsupported function error when it hits either function.

History

2016 July, A-Shell 6.3.1517: RND2() and SRND2(seed,…) functions added to A-Shell.


Trigonometric Functions

Function | Description
SIN(x) | Sine of x
COS(x) | Cosine of x
TAN(x) | Tangent of x
ATN(x) | Arctangent of x
ASN(x) | Arcsine of x
ACS(x) | Arccosine of x


String Functions

"True string functions" are those that return string values. Such functions can be specified with or without a trailing $ (i.e., CHR(X) or CHR$(X); we use the trailing $ below to emphasize that the function acts like a string expression.) Also included here are functions that that return numeric values (and thus are really numeric functions) but whose purpose is closely tied to string handling, such as LEN().

Function | Description
ASC(a$) | Returns ASCII value (in decimal) of first character of a$.
AUTOCAP(var) | "Intelligently" capitalizes the specified string. Note that the A-Shell implementation of this is rather minimal; users in need of more "intelligent" capitalization should refer to XFOLD.SBR.
CHR$(x) | Returns the ASCII character corresponding to the value x.
EDIT$ | Returns a modified version of the string a$, based on option bits set in flags.
FILL$ | Returns a string consisting of the string a$ repeated until it reaches n bytes long. Requires COMPIL switch /X:1 or higher.
INSTR() | Returns position of first occurrence of pattern$ in source.
LCS$(a$) | Returns string a$ folded to lower case.
LEFT$(a$,x) | Returns leftmost x characters of string a$. Equivalent to a$[1,x].
LEN | Returns length of string a$.
MID$(a$,start,length) | Returns substring of a$, starting in position start and extending length characters (or until end). Equivalent to substring syntax a$[start;length].
ODTIM | Outputs the specified date and/or time according to the formatting flags.
PAD | Returns string a$ truncated, or padded with trailing blanks as necessary to be exactly x characters long.
RIGHT$(a$,x) | Returns the rightmost x characters of string a$. Equivalent to a$[-x,-1].
RTRIM(a$) | Returns string a$ with trailing spaces removed.
SPACE$(x) | Returns a string of x spaces. Also see FILL(X,N).
STRIP(a$) | Same as RTRIM(a$). (Plus extension.)
STR$(x) | Returns the string decimal representation of the value x, with no leading or trailing blanks.
UCS$(a$) | Returns string a$ folded to upper case.
VAL(a$) | Returns numeric value of the decimal representation in the string a$. Supports "hexadecade" date notation if OPTIONS=HEXDEC (which see for more information). Also supports the decimal point and thousands separator character definitions in the Language Definition File. A-Shell extension

Subtopics

EDIT$

FILL$

ODTIM

PAD

INSTR()


EDIT$

Updated October 2016

EDIT$(expr, flags)

The EDIT$ function modifies the specified string expression expr according to one or more of the following flags as defined in ashell.def:

Symbol | Value | Description
EDITF_SPTB | &h0002 | remove spaces and tabs
EDITF_CTLS | &h0004 | remove chr(127) & chr(0)-chr(31) except TAB
EDITF_SPTBL | &h0008 | remove leading spaces and tabs
EDITF_SPTB1 | &h0010 | shrink spaces & tabs to one space
EDITF_SPTBR | &h0020 | remove trailing spaces and tabs
EDITF_UNQT | &h0040 | unquote (and reduce "" to "). EDITF_UNQT performs two operations: 1) if the first and last character, after any other processing (such as removal of leading/trailing spaces and tabs) are both double quotes ("), then are removed. 2) Any remaining double double-quotes ("") which are not preceded by a single double-quote are reduced to a single double-quote ("), unless the string has been reduced to a single pair of double double-quotes ("").
EDITF_EXQT | &h0080 | limits action to outside matched quotes. Exemption for quoted strings allows for multiple quoted subsections. This works well with JSON documents, which may contain many individually quoted strings, yet it may be convenient to remove all the whitespace not within those quoted strings.

Examples

S$ After EDIT$(S$,EDITF_SPTB+EDITF_EXQT)

--------------------- ------------------------------------------

"name" : "v1 v2" "name":"v1 v2"

"name" : v1 v2 "name":v1v2

"name : v1 v2" ] "name : v1 v2"]

"6"" ruler" "6"" ruler"

S$ After EDIT$(S$,EDITF_UNQT)

--------------------- ------------------------------------------

"6"" ruler" 6" ruler

"6"" ruler":$1.99 "6"" ruler":$1.99

In the last example above, the outer quotes were not removed because they didn't completely enclose the string, and the "" was not reduced to " because it followed a " character.

History

2016 October, A-Shell 6.3.1534: Add flags &h0040 and &h0080


FILL$

FILL$(expr,length)

The FILL$ function returns a string expression made by repeating the source expression until it reaches the specified overall length (in bytes).

For example:

PRINT FILL$("ab-",10) ! displays "ab-ab-ab-a"

Note that the source expression may contain nulls (which generally only makes sense if assigning the output of the function to an unformatted variable.)
For example, the statement REC = FILL$(chr(0),sizeof(REC)) would fill the REC variable or structure with nulls.


ODTIM

ODTIM (date, time {,flags})

This function outputs the specified date and/or time according to the formatting flags. If date and/or time is zero, the current date/time is used. The flags are the same as those used by ODTIM.SBR, which also see.


PAD

PAD (var, size) or PAD$ (var, size)

Returns a string equal to the input string var (which must be string format) padded with trailing spaces out to the length specified by size. In other words, this is the opposite of STRIP(var). If size is less than the current length of var then it functions just like the LEFT(var, size) function.

History

2013 May, A-Shell 6.1.1351: Removed limits on input and output size. Previously, the input expression was limited to 255 bytes, and the output expression to 4095. The new effective limit is the available space in the memory partition


INSTR()

Updated October 2016; see History

INSTR (spos, subject, pattern, {flags})

Returns position of first occurrence of pattern$ in source.

Searches the subject string for the specified pattern, starting at position spos. Returns the position (base 1) of the first match, or 0 if no match is found. Negative values indicate Regex errors; see comments.

The A-Shell version of INSTR() is equivalent to the standard AlphaBASIC version except for the optional flags argument, which, if specified, causes the pattern to be treated as a regular expression (see below).

Parameters

spos (Num) [in]

Position within the subject string to begin search. 1 is the first position. 0 and negative values are invalid and will return 0 as the result.

subject (String) [in]

String to be searched

pattern (String) [in]

Substring or pattern to search for. Treated as case-sensitive literal text unless flags specified.

flags (Num) [in]

If specified (even if 0), causes pattern to be treated as a Perl-compatible regular expression. The values for flags are the same as those for the REGEX.SBR option flags, plus these two additional flags:

Flag | Value | Description
INSTRF_ANY | &h01000000 | Treat pattern as set of characters; match first one that appears in subject.
INSTRF_ANYQT | &h02000000 | Same as INSTRF_ANY but ignores characters in subject between matching quotes.

These are based on the standard C function strpbrk(). For example:

PRINT INSTR(1, "DSK0:ABC.RUN /X", ";/ ", INSTRF_ANY)

Of the three characters in the pattern (";/ "), the first to occur in the subject is the space at position 13.

The above is equivalent to the REGEX character set pattern "[;/ ]"; it simply eliminates any doubts about REGEX syntax for special characters. But the INSTRF_ANYQT version is much harder to implement using REGEX.

Comments

Error Conditions: Any of the following conditions are considered invalid and will return 0 (no match):

• null pattern

• null subject

• spos < 0

• spos > length of string

Errors relating to regular expressions will be returned as negative values, matching those returned by REGEX.SBR. (See REGEX.SBR's Pattern Compilation Errors and Matching Errors.)

Case Sensitivity: For a case-insensitive search, you can either use the regular expression mode with PCRE_CASELESS (&h0001) flag, or you can just apply the String Functions LCS$() or UCS$() to the subject and pattern strings.

INSTR() versus REGEX.SBR: The function and XCALL version reference the same internal logic, and have the same parameter semantics. The INSTR() version has less overhead and is easier to use, while the REGEX.SBR version offers additional power (mainly in the advanced area of sub-expression matching, although it also returns the actual matched substring, which is often handy and not obvious).

Precompiling Patterns: Although the 20 numbered precompiled patterns (1-20) may be shared between REGEX.SBR and INSTR(), and thus you could use REGEX.SBR to pre-compile patterns later used with INSTR(), if you prefer to use INSTR() itself to pre-compile patterns, set the PCREX_PRECOMPILE (&h80000000) bit in the FLAGS parameter and set STPOS to the pattern number (like PATNO in REGEX). The SUBJECT string will be ignored (can be ""). On success, the return value of the function will equal STPOS; else refer to the STATUS codes listed under REGEX.

Using Precompiled Patterns: As with REGEX.SBR, you can specify a precompiled pattern by setting PATTERN = CHR$(n) where n is the pattern number (1-20). As with REGEX.SBR, whenever the same pattern is used in consecutive calls, the previously compiled version is automatically used (making pre-compilation unnecessary except when alternating between multiple patterns).

Backward Incompatibility: The new, 4-parameter version of INSTR() is NOT backwards compatible with runtime versions prior to 5.1.1109. However, the RUN file itself may still be used, as long as you never actually try to execute the statement. To prevent that, you would need to test for the A-Shell version (see MX_GETVER) and only execute the new INSTR() function if the A-Shell version is at least 5.1.1109.

See [908,46] in the the EXLIB for sample programs.

See the topic Substring search right-to-left on the A-Shell Forum for a discussion on how to implement a last-match (or right-to-left) version of INSTR(). As of 6.3.1527, the doc function .INSTRR() is available right-to-left searching. A general form search on the term "INSTR" will also turn up many threads which might be of related interest

See Also

• INSTRR

• NFIND.SBR

History

2016 October: A-Shell 6.3.1530: Add two non-REGEX flags as shown above.


System Functions

Function | Description
.ARGTYP | Returns the type of the specified argument passed to the current SBX, function, or procedure.
.ARGSIZ | Returns the size of the specified argument passed to the current SBX, function, or procedure.
DATE | Returns system date in separated format. See "Separated Date Format" below, also ODTIM.
ERR | ERR(X) is used within an error trap to return information relating to a BASIC error that has occurred, based on X. See ERR(#); note however that ERR(0), ERR(1) and ERR(2) are not extensions.
ERRMSG | ERRMSG(X) returns the message associated with BASIC error X, based on contents of SYS:ERRMSG.xxx). This is an A-Shell extension, requires COMPIL /X:2.
.EXTENT | .EXTENT(ARY(){,SUBNO}) returns the "extent" of the subscript number SUBNO (default 1) in the array ARY().
.INSTRR | Searches a string for a pattern, like INSTR(), but in reverse.
MEM | MEM(X) returns information about available memory and resources. See MEM(X) table below.
TIME | Returns system time in number of seconds since midnight. See ODTIM for formatting.

Separated Date Format

MAP1 SDATE

MAP2 MON,B,1 ! month 1-12

MAP2 DAY,B,1 ! day 1-31

MAP2 YR,B,1 ! yr-1900

MAP2 DOW,B,1 ! day of week (0=mon, 6=sun)

MAP1 BDATE,B,4,@SDATE

BDATE = DATE

MEM(X) Values

Function | Description
MEM(0) | returns the number of bytes of free space remaining in the "partition" (mostly used for variable storage, expression evaluation, stack, and possibly SBX loading.)
MEM(1) | returns total size of "partition." See MEMORY.LIT, MX_MEMORY, and the MEMORY system parameter for further discussion and methods of configuring partition size.
MEM(5) | size of compiled object code area
MEM(6) | size of DATA pool
MEM(7) | size of array storage area
MEM(8) | size of variable storage area (excluding arrays)

See Also

• Constants ... Compiler Functions

Subtopics

EXTENT

ARGTYP and ARGSIZ

INSTRR


EXTENT

Modified September 2014; see History

.EXTENT(ARY(){,SUBNO}) returns the "extent" of the subscript number SUBNO (default 1) in the array ARY(). This works for static arrays, but is mainly of interest with DIMX arrays, and especially those with the AUTO_EXTEND attribute. For example:

DIMX ARY(P,Q,R),S,25,AUTO_EXTEND

...

PRINT .EXTENT(ARY()) ! prints maximum current value of the first subscript, i.e. P in ARY(P,Q,R)

PRINT .EXTENT(ARY(),2) ! prints maximum current value of the second subscript, i.e. Q in ARY(P,Q,R)

Comments

.EXTENT(ARY()) will return -1 if the array ARY() has not yet been DIMX'd, or if it has been de-allocated, whether explicitly via a REDIMX ARY(0) or implicitly by returning from a procedure or function in which the DIMX was local. See notes in the Dynamic Arrays (DIMX) topic.

For fixed sized arrays, or arrays that have been DIMX'd but not yet auto-extended, .EXTENT() will return the fixed or initial allocated size, including if the initial DIMX size is zero. This may be considered the physical extent, as it has nothing to do with the contents of the array. For arrays that have been auto-extended, .EXTENT() will return the highest element number that has been written, i.e. the logical extent. Note that this behavior changed in A-Shell version 6.1.1389; see history note below for details.

Note that .EXTENT may also be used with Ordered Maps.

See Also

Sample programs in [908,61] of the EXLIB demonstrate .EXTENT().

History

2014 September, A-Shell 6.1: Significant behavior (semantic) change. Prior behavior and documentation was: .EXTENT(ARY()) will report the actual size of the array, which, depending on the availability and organization of the A-Shell heap when the array was last allocated or expanded, could be larger than what you explicitly asked for. This may be true even for arrays initially sized to 0 elements. This could lead to confusion in the case of AUTO_EXTEND arrays, leading you to falsely believe that all of the elements in the array, according to .EXTENT(ARY()), have actually been assigned values. If you need to keep track of how many elements have been assigned values, and can't tell by the fact that the un-assigned elements will be pre-initialized to nulls, then you'll need to use your own separate variable to keep track.

2010 September, A-Shell 6.0.1192: Function added to A-Shell.


ARGTYP and ARGSIZ

Added August 2016

.ARGTYP(argno)

.ARGSIZ(argno)

These two "dot functions" return the type and size of the specified argument passed to the current SBX, function, or procedure. If argno is invalid, the return value will be -1. The argument types are made up of the following bits:

Symbol | Value | Description
ARGTYP_MASK | &h000f | mask for types X,S,F,B,I
ARGTYP_X | &h0000 | X type (mutually exclusive)
ARGTYP_S | &h0002 | S type (" " ")
ARGTYP_F | &h0004 | F type (" " ")
ARGTYP_B | &h0006 | B type (" " ")
ARGTYP_I | &h0008 | I type (" " ")

Symbol | Value | Description
ARGTYP_ARRAY | &h0010 | ! array
ARGTYP_NOSURR | &h0020 | ! no surrogate
ARGTYP_DYN | &h0040 | ! dynamic variable
ARGTYP_LOCAL | &h0080 | ! local dynamic variable
ARGTYP_SBR | &h0100 | ! variable within SBX or xcall AMOS

Warning: These new functions are not recognized by runtime versions prior to 6.1.1373.0, and will simply return the value of the argno passed. You could use this fact to test if the feature is supported at runtime by passing an illegal argno, such as 999 or -2, to .ARGTYP(argno). If supported, the return value will be -1 (error); else if will match the argno passed.

History

2014 September, A-Shell 6.1.1373: Functions added to A-Shell.


INSTRR

.INSTRR (spos, string, pattern)

.INSTRR() is similar to INSTR() except it searches in reverse—e.g. it searches the string for the pattern, starting at the specified spos and working backwards towards the beginning of the string. The return value is the position of the last match—i.e. first match working backwards, with 1 indicating the first character of the string and 0 indicating no match.

Unlike INSTR(), .INSTRR() supports both positive and negative starting positions, with negative values counting from the end of the string—e.g. -1 starts the search at the end of the string. However the return value is always >= 0—i.e. position starting from the beginning of the string.

Also unlike INSTR(), .INSTRR() does not support the 4th argument used for regular expression searches.

See Also

• INSTR()

• NFIND.SBR

History

2016 September, A-Shell 6.3.1527: Function added to A-Shell.


File-Related Functions

Function | Description
EOF | EOF(X) returns end-of-file status for file channel X: -1 if no file is open on channel X; 0 if file is open but end-of-file has not been reached; 1 if end-of-file has been reached (after some form of INPUT statement on a sequential file).
ERF | ERF(X) returns error/status information about the last operation on an ISAM file (see table below for details). In the case of ISAM-A files, it simply returns the value of the fstat (status) variable associated with the file in the ISAM-A OPEN statement. As with the EOF(X) function, it returns -1 for channels that are not open. Note that -1 is also a valid ISAM-A status (ISAM_LT, key found less than specified key), but the usage context should usually make that distinction clear.
LOOKUP | LOOKUP (FSPEC$) Returns the size of the specified file in blocks (0 for non-existing, 0.5 for a file with zero bytes). Note that the returned block count for files which appear to be contiguous (are an even multiple of 512 bytes) will be negative, unless you set OPTIONS=ABSLOOKUP in the MIAME.INI. If you don't have control over that option, you may want to use the ABS(X) function on the result in order to confusion with files that happen to be a multiple of 512 bytes with, e.g. ABS(LOOKUP(FSPEC$)).
.LINENO, PAGENO | These return the current line number within the current page and the current page number#, respectively, for sequential output files.

ERF(X) Values for ISAM files

Function | Description
14 | Illegal record number
32 | Illegal ISAM statement code
33 | (after ISAM 1) indicates the key was not found
34 | (after ISAM 3) duplicate key found during add key
35 | link structure smashed
36 | (after ISAM 3) index file full (and auto-expansion disabled; see OPTIONS=NOAUTOX.
37 | (after ISAM 5) data file full (and auto-expansion disabled).
38 | (after ISAM 2 or 7) already at end of index
39 | Illegal ISAM sequence (violates LOKSER rules; if program was not designed to work with LOKSER, you can turn LOKSER off with SET NOLOKSER or LOKSER=OFF in the miame.ini)

Subtopics

LINENO, PAGENO


LINENO, PAGENO

Added November 2014

.LINENO(channel)

.PAGENO(channel)

These return the current line # within the current page and the current page #, respectively, for sequential output files. Both counters start at 1.

These are intended to simplify traditional report coding, particularly for those working with legacy or unfamiliar report programs, by eliminating the need to keep your own line and page counts synchronized with the file contents. Note however that the counting mechanism is based on a hook that covers only the most typical cases. In particular:

• For PRINT statements, the .LINENO(ch) value is only incremented by the absence of a trailing semicolon. Line feed characters which are output as data will not be counted.

PRINT #CH, PLINE ! counts as 1 line

PRINT #CH, PLINE; ! does not count (semicolon)

PRINT #CH, PLINE;chr(10); ! does not count

• Form feed characters, i.e. chr(12), will be detected anywhere, causing the .PAGENO(CH) value to be incremented, EXCEPT in the first position of the output file. The assumption there is that you are using the STRIPFF feature in the printer initialization file to ignore a leading form feed.

• XCALL PRINT is supported, although the feature is probably not useful there.

• XCALL PUTBYT is also supported; line and form feed will be detected anywhere.

• Any other method of outputting to a sequential file will probably bypass the counter hook.

History

2014 October, A-Shell 6.1.1396: Functions added to A-Shell


GETKEY

GETKEY(X {,xltname})

This function inputs and returns the ASCII decimal value of a single character. The parameter X must be one of the following:

Value | Description
0 | Don't wait for input. If no characters are available, returns -1. This is similar to XCALL TINKEY.
-1 | Wait until a character is entered. This is similar to XCALL ACCEPT.
-2 | Check if a character is available, but don't input it. Returns -1 if no character is available. (Some versions have returned 0 to indicate that a character is available, and others have returned the actual character value. For maximum compatibility, you should treat anything other than -1 as indicating that a character is available, but then input it using one of the other modes to determine its actual value.)

The optional xltname argument may be used to specify a function key translation table to process the character through if it is a function key.

Note that the return value of 999 indicates an invalid value of X. (A common mistake is to use 1 or 2 instead of -1 or -2.)


ERR

Updated December 2012; see History

The ERR(#) function was part of the original AlphaBASIC, but A-Shell adds the new sub-functions, ERR(7,8,9). For completeness, all the sub-functions are documented in the following table:

Sub-Function | Description
ERR(0) | Returns the last Basic error code. See SYS:ERRMSG.xxx for the description of all the Basic error codes. Also see ERRMSG.SBR for info on displaying and/or logging the error text under application control, as well as .LINENO in the Dot Variables table.
ERR(1) | Returns the last line number processed. Note that since A-Shell Basic doesn't require line numbers on every line, the last line number processed might be a long way from where the error occurred (or it may be 0 if the program has no line numbers). See ERR(8) to get the precise location of the error.
ERR(2) | Returns the last file channel processed. See FILNAM.SBR for info on retrieving the name of the file associated with the channel.
ERR(7) | (A-Shell Extension) Reports the location of the last error within the current stack frame/scope. This would differ from ERR(8) if the error occurred within a function or procedure and was allowed to percolate up to a higher level, where ERR(7) would indicate the line that called the function or procedure. Also see .LOCATION in the Dot Variables table to retrieve the current location counter outside the context of a BASIC error.
ERR(8) | (A-Shell Extension) Returns the internal location counter where the error occurred. Note that by convention, location counter values are usually displayed in hex, but the Basic PRINT statement has no way to know (or support) this. So if you are going to print the value of err(8), you may want to use MIAMEX, MX_OCVT, or the Fn'Dec2Hex$() function (in the SOSLIB). To match the location with a line of source code, you'll need to compile your program with the /L switch to create a LSX file, which lists the location counter (in hex) for each statement. Also see .LOCATION in the Dot Variables table to retrieve the current location counter outside the context of a BASIC error.
ERR(9) | (A-Shell Extension) Returns the function or procedure nesting level at the time of the error (equivalent to the dot variable .NEST_LEVEL). This might be helpful in debugging.

If you add TRACE=BASERR to the miame.ini (highly recommended), then all BASIC errors will be logged to the ashlog.log file, including most of the above information, and indicating whether the error was trapped. Also see Call Stack Tracing.

Errors occurring within User-defined Functions or Procedures will appear to the calling routine to have occurred on the line in which the Function or Procedure was invoked, unless the Function/Procedure performs its own local error trapping.

History

2012 December, A-Shell 6.1.1329: ERR(7) added, meaning of ERR(8) restored to original (as documented above)


XFUNC

XFUNC (Sbxname, arg1,...,argn)

XFUNC$ (Sbxname, arg1,...,argn)

XFUNC executes an external function, returning a value. It is similar to XCALL (in that it loads and calls an external function) except that it is an expression (which returns a value) rather than a statement (which does not). Sbxname is the name of an SBX subroutine which implements the function, and arg1 through argn are the arguments passed to the SBX routine. The only special requirement for the SBX routine is that it return a value (numeric for XFUNC and string for XFUNC$) via a special form of the RETURN statement (which see above).

See Also

• Call SBX as a Function


User-Defined Functions

Updated October 2016; see History

{PRIVATE} FUNCTION FN'name{$}(p1{=defval} {as typsiz{:mod}},...pN{=defval} {as typsiz{:mod}} ) {as typsiz}

<optional local MAP statements, with optional STATIC prefix>

<optional XGETARGs>

<nearly any kind of statements>

FN'name = <expression> ! set return value

ENDFUNCTION

The function definition, as shown above, starts with the optional keyword "PRIVATE" (see Private Functions and Procedures below for details), followed by the keyword "FUNCTION" followed by the function name, the list of formal parameters, and the function return type. The function name must start with FN', Fn', or fn' so that references embedded in expressions can easily be identified as function calls rather than arrays; see Function Name and Type for clarification. The function name must end with $ if the function returns a string or unformatted or defined structure type. If the final {as typsiz} clause (which defines the return type of the function) is omitted, the default type is F6.

The typsiz (data type and size) specification is similar to that used in MAP statements, except without a comma between the type code and the size. For example:

FUNCTION Fn'Test(p1 as S10, p2 as f6, p3 as B2, p4 As x256) AS i2

Function fn'display'name$(cus as ST_CUS_REC, bold as BOOLEAN) as s MAX_NAME

function fn'test(p1 as s20:inputonly, p2 as ST_PHONE:outputonly)

The first example above illustrates that, as with virtually all keywords, the FUNCTION keyword and AS typsiz clauses are not case sensitive. However, as with all other variables and labels, the function name and the formal parameter names are case sensitive, unless compiled with the /ci option.

The optional {=defval} clause assigns a default value to the parameter; see Named Parameters.

The optional :mod clause may be used to declare certain modifying attributes for the parameter, such as inputonly or outputonly; see Parameter Type and Size.

See Also

• XFUNC in System-Defined Functions

• Procedures

• SOSFUNC: in the SOSLIB, which is [907,10]

History

2016 August, A-Shell 6.3.1523, compiler edit 770: Add private attribute for functions and procedures.

2014 October, A-Shell 6.1.1391: Function name does not need to begin with FN'; see history note in Function Name and Type

2014 September, A-Shell 6.1.1389: A-Shell now supports Passing DIMX Arrays to functions/procedures by reference.

2014 January, A-Shell 6.1.1373: Named parameters implemented in A-Shell.

Subtopics

Function Name and Type

Parameter Type and Size

Named Parameters

Parameter Passing (In)

Parameter Passing (Out)

Passing DIMX Arrays

Return Expression

Local Variables

Global/External Variables

Exit Label $EXIT

Error Trapping in Functions

Invoking A Function

Private Functions and Procedures

Indirect Function Calls

User-Defined Function Examples


Function Name and Type

Updated October 2014

The function name must begin with FN' and is case insensitive. (Changed; see History, below). A side effect of this rule is that you may not define an array with a name starting with FN'.

Like other Basic expressions, functions fall into two fundamental types: numeric and string / unformatted. So that the compiler can immediately recognize the type of the function when it is referenced before being defined (without requiring forward declarations), the following naming convention is required:

• Functions that return string (or unformatted or structure) values must have names that end in $, such as Fn'Format$(...)

• Functions that return numeric values must have names that do not end in $, such as Fn'Average(...)

The return type can be further refined by appending the "as <typsiz>" clause to the end of the Function declaration (as in the Examples). Note, however, that you cannot override the rule just stated regarding the requirement that the names of functions returning string or unformatted values must end in $, while those returning numeric values must not end in $. If no "as <typsiz>" clause is specified, the standard defaults for implicit mapping of variables will determine the return type (i.e. F,6 for numeric functions, and S,# where # is 10 or the current STRSIZ for string functions.

History

2014 October, A-Shell 6.1.1391: Compiler enhancement (edit 708): when the /P (or -p) switch is used, it is no longer required that function names start with fn'. The main downside of taking advantage of this option is that it could make your source code harder to understand, since it wouldn't be immediately clear whether a subscripted identifier appearing in an expression, e.g.

something = WhatIsThis(idx)

is an array reference or a function reference. The compiler can tell the difference though. The upside is mainly aesthetic, allowing you to syntactically simplify your functions. This could be particularly helpful in cases where you have class-like collections of related functions and procedures. These can now all share a common prefix, allowing you to adopt a simpler but more object-oriented syntax scheme, i.e. object.verb(params).

Note: This feature is under review and should only be used with caution.


Parameter Type and Size

Revised November 2014

Parameters in function and procedure definitions have an optional "as <typsiz>{:<mod>)" clause to declare the type, size, and modifiers for the parameter. This also applies to the return type of the Function. If no clause is specified, the default type and size follows the normal rules for BASIC. The fact that you probably aren't 100% certain what those rules are should reinforce the importance of always defining the type and size explicitly. The following examples will help clarify the syntax:

Example 1

FUNCTION Fn'Test(p1 as S10, p2 as f6, p3 as B2, p4 As x256) AS i2

This illustrates the fact that although the <typsiz> clause uses the same fundamental data types as in MAP statements, here there is no comma between the type and size (e.g. "var2 as f6" instead of "map2 var2,f,6"). It also illustrates the the case insensitivity of the native type codes (F, S, B, X, I) and the "AS" keyword.

Example 2

Function fn'display'name$(cus as ST_CUS_REC, bold as BOOLEAN) as s MAX_NAME

This shows the possibility of using symbolic types and sizes rather than just the fundamental types and hard-coded sizes. One possibility is to use a defined structure (i.e. "as ST_CUS_REC"). See Defined Structures. Another is to use a symbol defined via a deftype statement (i.e. "bold as BOOLEAN"). Syntactically, it's impossible to tell the difference between a defined structure name and deftype name, but the assumption here is that BOOLEAN was defined via DEFTYPE BOOLEAN = I,2.

A third possibility is to replace just the size with a symbol, e.g. "as s MAX_NAME"). In this case, a single space is required between the native variable type ("s") and the symbol name ("MAX_NAME"). Using a symbol rather than a hard-coded number is useful for avoiding a common bug that may happen when passing string arguments to functions, where you decide to increase the size of the string field elsewhere in the application but forget about the function, resulting in the value being truncated within the function. But the technique has largely been superseded by the DEFTYPE method, which eliminates such discrepancies both in the parameter size and its type.

For string and X parameters, another way to avoid the truncation bug just described is to use Dynamically-Sized Variables within the function.

Example 3

function fn'test(p1 as s20:inputonly, p2 as ST_PHONE:outputonly)

This illustrates the use of the optional :<mod> clause to specify a modifier affecting the way the parameter is to be used. Currently the available modifiers are inputonly and outputonly.

The inputonly modifiier serves primarily as an aid to self-documenting code, but will also cause the compiler to generate an error if you explicitly reference the parameter in an XPUTARG statement using a literal parameter number. There is no run-time aspect of this feature, so you won't be stopped from outputting to the parameter using a variable to specify the parameter number in the XPUTARG statement.

The outputonly modifier also aids in self-documenting your code, but in addition it skips the input parameter binding operation (which, for very large parameters could save a lot of CPU cycles).

In the absence of an inputonly or outputonly modifier, the parameter is consider input/output. Note however, that since parameter passing is, in almost all cases, by value (as opposed to by reference), there is no automatic updating of the variables passed by the caller, unless you use explicit XPUTARG statements.

History

2009 April, A-Shell 5.1.1145: Feature added to A-Shell


Named Parameters

Added January 2014

Named parameters, also called "keyword arguments," may be used in place of, or in conjunction with, the traditional ordered parameters for all function and procedure calls. (For related information as it applies to subroutines, see Named Parameters in Subroutines.) Although this feature is really just a syntactic nicety rather than a fundamental capability, it nevertheless offers a variety of benefits:

• makes code more self-documenting

• reduces errors relating to omitting or mis-ordering parameters

• allows functions to specify default parameter values besides 0 or ""

• allows functions to specify mandatory parameters

• allows caller to specify just the parameters of interest, omitting the defaults

• allows the compiler to detect badly formed function calls

The A-Shell/BASIC implementation of named parameters is similar to that found in other modern languages such as Python, in which the parameter names are extracted from the existing function and procedure definitions without requiring any syntactic changes to existing definitions. In addition, function and procedure definitions may now specify default values for one or more parameters. Parameters with specified defaults are considered optional parameters, whereas those without defaults are considered mandatory.

However, there is one important exception to this rule, required for backward compatibility. Since A-Shell/BASIC has traditionally treated ALL function, procedure and subroutine parameters as optional, it will continue to do so unless a function/procedure definition is modified to specify at least one default value.

This will become clear with a few examples, but first let's note the following points:

• Named parameters are resolved entirely by the compiler. Thus programs using named parameters are backwards compatible back to the 5.0 runtime, and the runtime system has no way of detecting if a particular call used named or traditional ordered parameters.

• The semantics regarding optional and mandatory parameters are entirely determined by the function/procedure definitions, and not affected by whether the routine is called with named or ordered parameters.

• Since the compiler needs to see the function/procedure definition before any calls which use named parameters, it now makes a new preliminary pass of the entire source to build a table of the definitions. Although this pre-pass is very fast, to avoid inflicting any performance penalty or risk of side effects on programmers not using named parameters, the preliminary pass and thus the named parameter feature requires a new switch: /P. This in turn requires an update to COMPIL.LIT 1.1(126)

• In order to create common utility functions and procedures that might need to be compiled by older versions of the compiler, the /P switch will define a symbol ABC_NAMED_PARAMS=1 which you can use in conditional compilation statements to specify alternate versions of your function/procedure definitions. See example below.

• Ambiguity/Compatibility Warning: Expressions of the form A=B have always been legal where expressions are legal, and thus Fn'X(A=B) is legal with any version of the compiler, provided that A and B are mapped variables or that (the horror!) you are compiling without the /M switch. The expression evaluates to true (-1) if A equals B, and or false (0) otherwise. Use of the /P switch disables that dubious feature within subroutine and function/procedure calls, and instead interprets the expression as a request to set the named parameter A to the value B. However, there is possibility that calls with named parameters might be compiled under an older compiler or without the /P switch, resulting in a syntactically correct but semantically confused RUN file. To avoid this possibility, in programs that use named parameters, you should include a conditional compilation test to detect an attempt at compilation without /P and to report it as an error, e.g.:

++ifndef ABC_NAMED_PARAMS

++error This program requires compiler 653+ (and /P)

++endif

Now for the examples. Consider the following function which takes the names of players at the first, second and third base positions and displays them as a sentence, as in the famous Abbott & Costello routine, i.e. "Who's on first, What's on second, and I Don't Know's on third".

function fn'lineup$(first$ as s0, second$ as s0, third$ as s0) as s0

Traditionally, any of the following would be legal invocations of the function, at least from the compiler's perspective:

? fn'lineup$()

? fn'lineup$("Who")

? fn'lineup$("Manny","Moe")

? fn'lineup$(spam$,spam$,spam$,spam$)

The first three examples specify fewer than the three expected parameters, but since there is no enforcement of minimum parameter counts, the compiler is happy. The routine itself can test .ARGCNT to see how many were actually passed. The fourth example specifies an extra parameter, which the compiler is happy to pass, and the routine may simply ignore, although it also has the ability to retrieve such additional parameters using explicit XGETARG statements.

Using named parameters, any of the following are also legal:

? fn'lineup$(first$="Who", second$="What", third$="I don't know")

? fn'lineup$(second$="Jack", first$="Manny")

? fn'lineup$("Eenie", "Meenie", third$="Mo")

The first simply adds the names of the parameters, making the code a bit more self-documenting. The second illustrates that you can rearrange the parameters since the compiler can match the names up to their proper positions, and you can also omit trailing parameters, in this case third$, provided it doesn't create a gap. The third example illustrates that you can combine ordered and named parameters, as long as the ordered ones ("Eenie" and "Meenie" in this case) come first.

These, however, are illegal:

? fn'lineup$(first$="Who", shortstop$="Curly")

! no such parameter: shortstop$

? fn'lineup$(first$="Manny", "Mo", "Jack")

! ordered parameters cannot follow named parameters

? fn'lineup$(first$="Tiny", second$="Fats", first$="Tiny")

! parameter first$ specified twice

? fn'lineup$(second$="What", third$="Nobody")

! missing mandatory first$ parameter

The last example above deserves clarification. Although traditionally all parameters were optional, it was never possible with ordered parameters to omit one, other than at the trailing end of the parameter list. Consequently, to preserve runtime compatibility, we don't want to allow that to happen with named parameters either, at least by default.

However, by adding default values for one or more parameters in the function/procedure definition, we can effectively instruct the compiler regarding which parameters are mandatory and thereby have it to more of the work of error checking and standardizing function and procedure calls. To accommodate default values, the syntax for declaring a parameter has been enhanced to:

<paramname>{=defvalue} as <type>{:modifier}

For example:

function fn'lineup$(first$="Who" as s0, second$ as s0, third$="I don't know" as s0) as s0

With the updated function definition, we can reevaluate how the compiler would treat the example calls:

? fn'lineup$()

! illegal (missing mandatory second$ parameter)

? fn'lineup$("Who")

! illegal (" " ")

? fn'lineup$("Manny","Moe")

! ok (missing third$ defaults to "I don't know")

? fn'lineup$(spam$,spam$,spam$,spam$)

! ok

? fn'lineup$(first$="Who", second$="What", third$="I don't know")

! ok

? fn'lineup$(second$="Jack")

! ok (first$ defaults to "Who" and third$ to "I don't know")

? fn'lineup$("Eenie", "Meenie", third$="Mo")

! ok

Finally, if we want to make our fn'lineup$() function available in a library where it might be compiled with an older version of the compiler, we can use conditional compilation to specify two versions of the function definition—one traditional (ordered parameters only) and one modern (with named parameters and default values):

++ifdef ABC_NAMED_PARAMS ! if /P (named parameter supported)

function fn'lineup$(first$="Who" as s0, second$ as s0, third$="I don't know" as s0) as s0

++else ! traditional version

function fn'lineup$(first$ as s0, second$ as s0, third$ as s0) as s0

++endif

fn'lineup$ = first$ + "'s on first, " + second$ + ",s on second, and " + third$ + ",s on third."

endfunction

History

2014 January, A-Shell 6.1.1373: Named parameters implemented in A-Shell.


Parameter Passing (In)

Modified September 2014; see History

Any variables in the formal parameter list (var1,...,varN) will be assigned automatically from the calling parameters, converting as necessary. For parameters without explicit "as <typsiz>" clauses, such as flags and width in the Fn'Dec2Hex$ example (see User-Defined Function Examples), their types will be determined by the normal rules for unmapped variables. Otherwise the types will be as declared. (Here the rule regarding string parameters having to end in $ does not apply.) In all cases, the types of the calling parameters will be converted as best they can to the types of the formal parameters. If the call does not specify all the parameters, any leftover are set to 0 or null. Any parameters passed which go beyond those defined in the formal parameter list will not be automatically converted to anything, but they will remain accessible on the stack (along with all the other parameters) where they can be retrieved with explicit XGETARG statements (just as you would in an SBX). (This kind of flexibility might be useful in a function that handles different argument types, depending on the number of parameters passed.) The number of parameters passed will be available in the system dot variable .ARGCNT, and their types and sizes will be available via the dot functions .ARGTYP(argno) and .ARGSIZ(argno).

The parameter list may be empty, in which case you use an empty pair of parentheses ().

Also see the discussion on Parameter Type and Size.

To pass a structure or array as a parameter, you can use the following technique. Let's say we want to pass the following array of structures to a function:

map1 shifts(40)

map2 empid,s,10

map2 in,b,4

map2 out,b,4

Since BASIC does not have a syntax by which we can refer to the entire array shifts(), we can use the overlay feature instead, i.e.:

map1 shiftx

map2 shifts(40)

map3 empid,s,10

map3 in,b,4

map3 out,b,4

Now we can pass the entire structure as a single variable, shiftx, i.e.:

total'hours = fn'add'shifts(shiftx)

The function can then receive the structure as a single x720 entity and break it back out into the original array of structures using the same kind of overlay, e.g.

Function fn'add'shifts(shiftx as x720) as f6

map1 shiftx2,@shiftx ! overlay shiftx2 on passed structure

map2 shifts(40) ! so we can access it via this array

map3 empid,s,10

map3 in,b,4

map3 out,b,4

Starting with version 5.1, a considerably more elegant technique for passing complex parameters, such as structures and arrays, is via Defined Structures. To illustrate, in the example above, we could have defined a structure to contain the shifts() array:

define MAX_SHIFTS = 40

defstruct ST_SHIFT_ARRAY

map2 shifts(MAX_SHIFTS)

map3 empid,s,10

map3 in,b,4

map3 out,b,4

endstruct

map1 shiftx,ST_SHIFT_ARRAY

Function fn'add'shifts(shiftx as ST_SHIFT_ARRAY) as f6

map1 hours,b,4

map1 h,f

for h = 1 to MAX_SHIFTS

hours = shiftx.out(h) - shiftx.in(h)

next h

...

Besides offering a simpler, more intuitive syntax, a big advantage of using a defined structure is that it eliminates the need to manually match up the size of the unformatted variable (e.g. shiftx as x720 vs. shiftx as ST_SHIFT_ARRAY). Thus, if you change the definition of the structure, a recompile is all that would be required to synchronize it to the existing functions.

As of A-Shell 6.1.1389, arrays—including arrays of structures and collections—declared with DIMX may be passed by reference; see Passing DIMX Arrays.

A related issue occurs with passing string arguments to functions, in that you often don't know how large to make them. For example, consider the following function which formats a name from its individual parts:

Function Fn'Format'Name$(first$ as s20, mid$ as s20, last$ as s30) as s50

The problem is, how do we decide on the appropriate sizes for the parameters and returned string? The best way to handle this is to use common defined symbols through the application, so that they are always consistent:

define MAX_FIRST = 20

define MAX_MID = 20

define MAX_LAST = 30

define MAX_NAME = 50

map1 EMP

map2 E'FIRST,S,MAX_FIRST

map2 E'MID,S,MAX_MID

map2 E'LAST,S,MAX_LAST

map1 NAME$,S,MAX_NAME

....

NAME$ = Fn'Format'Name$(E'FIRST, E'MID, E'LAST)

....

Function Fn'Format'Name$(first as s MAX_FIRST, mid$ as s MAX_MID, last$ as s MAX_LAST) as s MAX_NAME

Note that when using defined symbols in place of literal numeric values, you need a space between "s" (for string) and the symbol.

See Also

• References to the :INPUTONLY and :OUTPUTONLY clauses on the User-Defined Functions page.

• Sample programs in [908,61] of the EXLIB demonstrate array passing by reference.

• Dynamic Arrays (DIMX)

History

2014 September, A-Shell 6.1.1389: A-Shell now supports Passing DIMX Arrays to functions/procedures by reference.


Parameter Passing (Out)

In addition to the Return Expression of a function, both functions and procedures can pass updated values of the parameters they received back to the calling routine, by using XPUTARG.

See Also

• References to the :INPUTONLY and :OUTPUTONLY clauses on the User-Defined Functions page.

• The discussion on Parameter Type and Size.


Passing DIMX Arrays

Modified (Example 3) August 2015

Arrays can be passed as parameters to functions/procedures/subroutines, but the techniques vary depending on whether the array is static or dynamically mapped. For static mapped arrays, the only available technique is to map an X variable as an overlay over the array, e.g.

map1 blob

map2 array(200)

map3 field1,s,4

map3 field2,f,6

...

call Proc(blob) ! pass the array by means of the overlay

Passing DIMX arrays, by contrast, requires one of the following special methods:

• Using Dynamic Overlays to pass a copy of the array as a blob.

• Using pass-by-reference; see following discussion

Unlike the normal pass-by-value method for parameter passing, in which the called routine receives a copy of the parameter, pass-by-reference provides the called routine an alias—essentially a pointer—to the original parameter/array. This is much more efficient than making a copy of the entire array and then having to transfer that copy back to the original on return. Both the alias array and the original array refer to the same set of elements; the only difference between them is the name. Any changes made to the alias array (including resizing or auto-extending it) are directly made to the original array (since they are the same array).

Passing an array by-reference is architecturally nearly the same as just accessing it globally—i.e., using ++extern or ++pragma auto_extern within the called routine to bring the global array into scope. The main advantages are that it makes the code (on the calling side) somewhat more explicit/self-documenting, and it provides the called routine the flexibility to act on different source arrays (determined by the caller).

The syntax for indicating an array to be passed or received by reference is to use an empty set of parentheses, e.g. ARY(), as in the following examples.

Example 1: Pass DIMX array of structures to function / procedure

dimx CUST(0), ST_CUST, auto_extend

...

call Add'Items'To'Array( ARY(), 5 ) ! pass CUST() by reference to function

...

procedure Add'Items'To'Array( ary() as ST_CUST, count as b2) ! rcv array by reference

map1 p,i,2

map1 i,i,2

p = .extent( ary() )

for i = p+1 to p+count

ary(i).field = <data> ! ary() is effectively alias for passed CUST()

next i

endprocedure

In the above example, the array a() within the procedure becomes an alias to the array ARY() in the calling routine, and any changes made to a() within the procedure are reflected in ARY() immediately.

Neither the compiler nor runtime system (currently) can verify that the passed and received structure types are the same; the runtime system can only verify that the structure sizes are the same. This could allow for a kind of polymorphism—or more likely, subtle bugs—if you do not take care to make sure that the structure types are in fact the same. In the above example, both the source array ARY() and the received array a() are explicitly declared as the same structure type, ST_CUST.

Note: Do not attempt to use XPUTARG to copy the array back to the caller; this would make no sense.

Example 2: Pass DIMX array of dynamic blobs to function / procedure

The syntax and other logic for passing a DIMX array of X,0 elements is essentially the same as in the example above, e.g.

dimx XRY(0),X,0,auto_extend ! declare DIMX array of variable length blobs

...

call Add'Items'To'Array( XRY() ) ! pass XRY() by reference to procedure

...

procedure Add'Items'To'Array( xry() as x0) ! rcv array by reference

map1 i,f

do while <some condition>

xry(i) = <some variable length string or binary data>

loop

endprocedure

The source array must be defined at the global or module-scope—i.e., PRIVATE DIMX—level, rather than locally within a function. This is to ensure that the contents remain valid when referenced within another scope.

Currently this only works for X,0 (and not S,0) variables. The restriction may be lifted, but there is no particular need since dynamic X variables are practically interchangeable with dynamic S variables anyway. The main distinction between X and S has to do with the whether bytes past the first null are considered significant, but this isn't really a factor when loading string data into dynamic X variables, since the variable size would be trimmed to eliminate any bytes after the null terminator anyway.

Example 3: Pass DIMX array of structures to XCALL SBX

Passing a DIMX array of structures to an XCALL (SBX) is similar to passing one to a function or procedure, at least from the calling side, e.g.

dimx myary(0),ST_MYSTRUCT,auto_extend ! define source array

...

xcall MYSBX,myary(),... ! specify in arg list with empty ()

On the receiving side (within the SBX), because there is no equivalent of the formal parameter declaration like there is in Functions and Procedures, the SBX has to declare a surrogate array using a special form of the DIMX statement with the byref modifier, and the initial subscript value set to -1, e.g.: .:

dimx locary(-1), ST_MYSTRUCT, byref ! define surrogate local array

The surrogate local array will not work correctly unless the subscript in the dimx statement is -1, and the byref clause is specified. Prior to 6.1.1415 (compiler edit 744), the compiler failed to complain about invalid subscript values such as 0 or 1.

This method only works for passing a Dynamic array of structures, not for a simple dynamic array of standard types.

To receive the array passed by reference, use the normal xgetargs syntax, but with an empty set of parentheses for the local surrogate array, e.g.

xgetargs locary(), ...

History

2014 November, A-Shell 6.1.1398: Pass-by-reference extended to XCALL (SBX)

2014 October, A-Shell 6.1.1391: Pass-by-reference feature introduced for functions and procedures (not XCALLs)


Return Expression

Reviewed May 2009

The default return value is 0 for numeric functions and "" (null) for string functions. To set another return value, assign it to the variable matching the function name (e.g. FN'name = -1). Note that this is similar in concept to the RETURN(<expression>) statement in an SBX, except that it doesn't end the function.

The return variable otherwise functions as a standard variable and can be used in expressions and be assigned a value multiple times (only the last one will matter at the time the function returns). As an example of one possibility, in the Fn'Dec2Hex$ sample function above, the return variable Fn'Dec'Hex$ receives its value by being passed as a parameter to an XCALL:

xcall MIAMEX, MX_OCVT, decval, width, OT_MEM or flags, Fn'Dec2Hex$

A special case occurs when the function returns a defined structure. In this case, in order to obey the naming rules, the function name must end with a $. But the $ is dropped when referencing members of the structure. Consider this example of a function which returns an item structure when passed an item ID.

defstruct ST_ITEM

map2 id,s,10

map2 descr,s,30

map2 price,f

endstruct

map1 item,ST_ITEM

item = Fn'Item$("A12345")

end

Function Fn'Item$(itemid as s10) as ST_ITEM

Fn'Item.id = itemid

Fn'Item.descr = "some description"

Fn'Item.price = 7.99

End Function

Note that the name of the function has a $ on the end (Fn'Item$), but when referring to the individual fields within the structure, the $ is dropped (Fn'Item.id = itemid).

Also note that the return value of the function is a copy of the entire ST_ITEM structure as it exists at the end of the function, even though there is no explicit reference to the structure as a whole. Any members of the structure which are not assigned would simply default to zeros or nulls, just as they would for a traditional unformatted MAP1/MAP2 structure.


Local Variables

Any MAP statements defined between FUNCTION and ENDFUNCTION are considered local stack variables, which are allocated and initialized for each instance of the function.

You may also prefix MAP statements within the function definition with STATIC (e.g. STATIC MAP1 S'COUNT,F) to make the local variable persistent across instances of the function. Such a variable will only be initialized once, the first time the function is called.


Global/External Variables

Updated and reviewed May 2011

By default, only variables defined within the function or procedure (i.e. Local Variables) are accessible within that routine. This is generally a good thing, as it helps prevent inadvertent references to the wrong variables, as well as unintended side-effects from calling a function or procedure. But the ability to access variables defined outside the routine can be enabled, by any of the following methods:

• Private Map: You can share variables between a group of related functions or procedures by grouping them all within a single file and declaring the shared variables at the top of the file using PRIVATE MAP statements. See MAP Statement Extensions.

• AUTO_EXTERN may be used to expose all global variables.

• EXTERN_BEGIN, END: You can expose a list or block of global variables by repeating the original MAP statements for those variables within the function or procedure, enclosed by ++PRAGMA EXTERN_BEGIN and ++PRAGMA EXTERN_END, e.g.

++PRAGMA EXTERN_BEGIN

MAP1 SOME'VAR,F,6

MAP1 ANOTHER'VAR,S,20

++INCLUDE MOREVARS.MAP

++PRAGMA EXTERN_END

• EXTERN may be used to expose individual global variables.


AUTO_EXTERN

Revised June 2012

++PRAGMA AUTO_EXTERN {"<boolean>"}

Enables or disables the visibility (with the local function or procedure) of variables defined globally—i.e. with standard MAP statements outside any function or procedure. The argument defaults to "TRUE", so the following are equivalent:

++PRAGMA AUTO_EXTERN "TRUE"

++PRAGMA AUTO_EXTERN

++pragma auto_extern ! pragmas are case insensitive

The setting is reset to FALSE at the start of each function or procedure, so must be specified whenever you want to reference global variables within a routine. The only point of specifying an argument of "FALSE" would be if you first enabled it, then later in the function didn't have any further need to reference global variables and wanted to protect against accidentally doing so.

Example

PROCEDURE MYPROC(p1 as f)

++PRAGMA AUTO_EXTERN ! expose all global vars to this procedure

...

SOME'VAR = SOME'VAR + p1 ! add parameter p1 to global variable SOME'VAR

...

ENDPROCEDURE

The above technique, while undermining one of the benefits of using PROCEDURE as opposed to old-style GOSUBs, does provide a convenient way to migrate from unstructured GOSUBs to structured PROCEDURES. Essentially all you need to do to convert a reasonably well-designed GOSUB into a proper PROCEDURE is to add the PROCEDURE keyword, an empty parameter list, the AUTO_EXTERN pragma, remove the RETURN, and add the ENDPROCEDURE, e.g.

The following GOSUB ...

MYPROC:

...

RETURN

can be converted to a PROCEDURE as follows:

PROCEDURE MYPROC()

++PRAGMA AUTO_EXTERN

...

! RETURN ! (RETURN may also be converted to EXITPROCEDURE)

ENDPROCEDURE

Note that the above illustration ignores certain issues that may complicate such conversions. If the GOSUB has RETURN statements other than at the physical end, these can be converted to EXITPROCEDURE statements. But a PROCEDURE may not contain GOSUB (or CALL) statements to other old-style GOSUB routines, so they would have to be converted as well. Also, any GOSUB MYPROC (or CALL MYPROC) statements referencing the original routine would have to be converted to CALL MYPROC(). These are all fairly mechanical steps though, after which you would be in position to incrementally access the modularization/isolation/encapsulation advantages of proper procedures with local variables and true parameter passing.

See Also

• EXTERN


EXTERN

Updated and reviewed May 2011

As an alternative to exposing all global variables to a function or procedure with AUTO_EXTERN, you can instead expose individual global variables via ++EXTERN statements:

++EXTERN SOME'VAR,F,6

++EXTERN SOME'ARRAY()

There are few subtleties and disclaimers to consider when using either of the above methods to declare specific global variables as being visible within a local procedure:

• Declaring a variable with ++EXTERN or ++PRAGMA EXTERN_BEGIN does not have any effect on the original global variable definition, although it does allow the code within the procedure or function to modify the global variable at runtime.

• The type and size may be omitted in the local extern declaration. Also, for arrays, the array dimensions may be omitted by just using (). However, if you do specify a type, size, or array dimensions, then they must match those in the original global definition of the variable. For example:

!(main program)

MAP1 GFLAGS(5),B,1

MAP1 SFLAG$,S,1

...

PROCEDURE TEST()

++EXTERN GFLAGS(5),B,1 ! valid

++EXTERN GFLAGS(5),F ! invalid (types don't match)

++EXTERN GFLAGS(5),B,2 ! invalid (sizes don't match)

++EXTERN GFLAGS(4),B,1 ! invalid (subscripts don't match)

++EXTERN GFLAGS() ! valid (equivalent to GFLAGS(5),B,1)

++EXTERN SFLAG$ ! valid (equivalent to SFLAG$,S,1)

• The MAP level does not need to match (it doesn't even get specified for the ++EXTERN statements). But to the extent that there is any discrepancy between the local and global definitions, it is the global one that actually matters. The local one simply allows the local routine to access the global variable.

Another alternative to individual ++EXTERN statements is to use ++PRAGMA EXTERN_BEGIN and ++PRAGMA EXTERN_END to bracket some ordinary MAP statements (or a ++INCLUDE referencing more MAP statements), for example:

++PRAGMA EXTERN_BEGIN

MAP1 SOME'VAR,F,6

MAP1 ANOTHER'VAR,S,20

++INCLUDE MOREVARS.MAP

++PRAGMA EXTERN_END


Exit Label $EXIT

Rewritten August 2016

If the special label $EXIT: is included in a function or procedure, the EXITFUNCTION statement will transfer to that label, rather than to the physical end of the function—i.e. the ENDFUNCTION statement. This allows you to consolidate cleanup code and/or assignment of the function return value in a single place, and eliminates the common bug of forgetting to assign the return value prior to an EXITFUNCTION statement. For example: "

FUNCTION FN'TEST() AS I4

open #999, "TEST.LOG", output

...

IF <some condition) EXITFUNCTION

...

...

$EXIT:

if eof(999)>=0 close #999

FN'TEST = <expr> ! assign return value

ENDFUNCTION

In the example above, execution hits the $EXIT label either as the result of the EXITFUNCTION statement, or by just falling into it. This assures that the file is closed and the return value assigned, regardless of which logical path is taken. The one exception would be in the case of a BASIC error, which in the above example, would bypass the $EXIT label. To cover that case, error trapping logic could be added as follows:

FUNCTION FN'TEST() AS I4

on error goto TRAP

open #999, "TEST.LOG", output

...

IF <some condition) EXITFUNCTION

...

...

EXITFUNCTION ! skip over error trap

TRAP:

...

RESUME $EXIT

$EXIT:

if eof(999)>=0 close #999

FN'TEST = <expr> ! assign return value

ENDFUNCTION

In the modified example above, we added a second EXITFUNCTION to avoid falling into the error trap. The error trap code has the option of resuming explicitly to the $EXIT label, (as in the case above), just like it could resume to any other label within the function. Or it could bypass the $EXIT code with RESUME ENDFUNCTION {WITH_ERROR {N}). See Error Trappingfor more details.

Notes

• The $EXIT label functions the same way in procedures as in functions, except substituting EXITPROCEDURE and ENDPROCEDURE for EXITFUNCTION and ENDFUNCTION

• All of the keywords and labels discussed here are case insensitive, including the $EXIT label.

• Be careful not to include an EXITFUNCTION or EXITPROCEDURE statement within the $EXIT: code, lest you create an infinite loop.

History

2011 July, A-Shell 5.1.1223: RESUME behavior changed to skip the code following the $EXIT, so as to reduce chance of infinite error trapping loops if an error occurred within that code. Previously, RESUME ENDFUNCTION resumed to the $EXIT label, if present.

2010 September, A-Shell 5.1.1192: Feature added to A-Shell


Error Trapping in Functions

Updated and November 2016

By default, BASIC errors are internally filtered in such a way that the error appears to the caller to have occurred on the line that called the function. This allows the stack to be properly unwound before doing an unstructured ON ERROR GOTO out of the function. You may, however, create a local error trap inside the function, using the regular ON ERROR GOTO statement. The local error trap may resume back to locations within the function. A new variation of the RESUME statement also allows the local error trap to forward errors to the caller:

RESUME ENDFUNCTION {WITH_ERROR {N}}

Without the optional WITH_ERROR clause, this acts like a normal RESUME LABEL, except that a special reserved virtual label ENDFUNCTION is used to indicate the end of the function. A common way to use this feature would be:

FN'name = err(0) ! assign basic error # to function value

RESUME ENDFUNCTION ! return to caller (with error cleared)

This would clear the Basic error condition (so it doesn't trigger the caller's ON ERROR GOTO), but it would still return to the caller the error number so that the caller could take action in a more structured manner (as opposed to via an error trap).

If the WITH_ERROR {N} clause is specified, then the function returns, but the current error (or error N, if specified) is set, causing the caller to get an error on the line that called the function. RESUME WITH_ERROR is equivalent to what happens if you don't establish error trapping within the function at all.

Note that since the local error trap code must be within the function, some care must be taken to make sure that it doesn't get executed except on error. One technique would be to use an EXITFUNCTION or EXITPROCEDURE label just above it, for example:

PROCEDURE TEST()

ON ERROR GOTO TRAP

...

...

EXITPROCEDURE

TRAP:

PRINT "Error #";ERR(0);" in procedure TEST()"

RESUME ENDPROCEDURE WITH_ERROR 199

ENDPROCEDURE

See Also

• Call Stack Tracing

Subtopics

RESUME ENDFUNCTION


RESUME ENDFUNCTION

Added August 2011

The RESUME ENDFUNCTION (or ENDPROCEDURE) statement is meant to resume at the exit point of the routine, but with the introduction (in 5.1.1192/ compiler edit 462) of the explicit Exit Label $EXIT, there was some ambiguity as to which exit point the RESUME was to refer to. Initially, it referred to the $EXIT label (if present), since, after all, the purpose of the explicit $EXIT label was to force the execution of some code prior to exiting the routine, regardless of how the routine was terminated. But, after some field experience, it became clear that this was neither the expected behavior, nor was it particularly safe, since it introduced the possibility of an infinite loop if an error occurred while processing the code following the $EXIT label.

So, as of 5.1.1223 (compiler edit 487), RESUME ENDFUNCTION (or ENDPROCEDURE) now resumes at the physical end of the routine, skipping any code following an $EXIT label.

If you really want to execute the code at your $EXIT label upon resuming from an error (and are sure that your code is error-free), you can resume explicitly to that label by specifying it explicitly in the RESUME statement:

RESUME $EXIT

Note that the WITH_ERROR clause is not permitted in this case. It only makes sense when resuming directly to the caller (i.e. ENDFUNCTION/ENDPROCEDURE).


Invoking A Function

To invoke the function, just reference it using array syntax, i.e.:

A = FN'name(x,y,z)

You may also invoke it as a statement rather than an expression, using:

CALL FN'name(x,y,z)


Private Functions and Procedures

Added October 2016

Function and Procedure definitions within ++include modules may be preceded with the keyword PRIVATE to make them invisible outside of that ++include file. This is analogous to the use of the PRIVATE keyword to declare a variable as being visible only within the ++include file. For example:

PRIVATE FUNCTION FN'TEST() AS F6

....

ENDFUNCTION

The two most likely motivations for declaring a function or procedure to be private are:

• As a namespace mechanism to prevent conflicts with procedures of the same name in other include files. Previously, the only way to avoid this risk would have been to append or prepend some module-specific text (perhaps the module name) to the routine name, but this ends up making your routine names overly long, making them difficult to type and read.

• As a way of making the code easier to understand or debug later. (Eliminating the possibility that the routine is called from anywhere outside the current module eliminates the need to consider impossible scenarios that would otherwise be difficult to rule out without searching every possible file that could use this module.)

History

2016 August, A-Shell 6.3.1523, compiler edit 770: Add private attribute for functions and procedures.


Indirect Function Calls

A reference to a function or procedure may now be passed as an argument to another function or procedure. This is an advanced technique that is mainly useful in multi-level (often recursive) algorithms consisting of a generic intermediate layer and a specific lower layer which may need to be customized for each particular problem. The indirect function call technique allows you to effectively customize the generic intermediate routine without actually having to modify it. Instead, you pass your custom routine to it, which it then calls indirectly to do the parts of the algorithm which you want to customize.

The custom routine in this scenario is sometimes referred to as a "callback routine", since the idea is for the generic intermediate routine to call your routine back to perform the part of the algorithm requiring customization.

For example, when parsing an XML file, you may want to employ a generic routine to walk the tree, but a custom routine to process nodes that meet some criteria. Because of the recursive nature of the routine to walk the tree, it is difficult for it to exit back to your application each time it hits one of the target nodes, without losing its position and ability to continue to the next node. The solution is to design the generic routine to accept a callback routine to be called for each target node. Each application can then use the generic routine in a different way by passing a different callback routine to it.

The scheme consists of three parts:

1. The Callback Routine.

This is a normal function or procedure.

2. The Generic/Intermediate Routine

This receives the callback reference and makes calls to the callback routine. In this routine, the parameter to receive the indirect/callback reference must be defined as follows:

Procedure Foo( ..., @fn'cb() as lblref, ... )

For functions, the formal name must follow the standard naming rules, i.e. start with "Fn'" and end with $ if the functions returns a string value. In all cases it must start with "@", and end with the "as lblref" clause. An empty pair of parentheses, as in the example above, is optional. (Parameters to be passed to the indirect routine are not specified in the declaration.) Beyond that, the name may be anything, for example:

@fn'callback as lblref

@FN'PROC$ AS LBLREF

@Fn'Custom$() as lblref

@myproc() as lblref

The above parameter declarations would apply to a numeric function, two string functions, and a procedure, in that order.

Inside the intermediate routine, you can call the callback routine using the name specified in the declaration. For example:

call fn'cb(arg1,...) ! call actual callback with actual args

Note: unlike nearly all other formal parameter types, lblref parameters default to .NULL rather than "" if the caller does not supply the actual parameter. This allows you to test whether the function reference was supplied, e.g.

if .ISNULL(fn'cb) then ! if myproc not passed

call my'default'proc(...) ! use a default routine

else

call fn'cb(...) ! else call the passed routine

endif

Within the intermediate routine, if you need to pass the callback routine indirectly again to another routine, or recursively to yourself, then retain the @ prefix, e.g.

Procedure Foo(..., @fn'cb() as lblref, ...) ! intermediate rtn

...

call Foo(...,, @fn'cb(), ...) ! pass callback again indirectly

...

endprocedure

3. The call to the generic/intermediate routine

In this you pass the reference to your callback routine as a parameter. Here you must precede the actual callback routine name with "@" and use an empty set of parens, e.g.

Function Fn'Bar(...) ! actual callback routine

...

Endfunction

...

call Foo(...,@Fn'Bar(), ...) ! passing callback to intermediate Foo()

Note: if you fail to specify the "@" prefix when passing the callback routine to the intemediate routine, it will still be syntactically and semantically legal, but the result will be completely different. To clarify, consider the following two examples:

call Foo(Fn'Bar())

call Foo(@Fn'Bar())

In the first call, the function Fn'Bar() is evaluated first and its return value is passed to the procedure Foo(). In the second call, a reference to the Fn'Bar() function is passed indirectly to the procedure Foo(), which will then be able to call that function without knowing its real name.

Example 1

The following example illustrates the scheme using a generic intermediate SOSLIB routine Fn'Dir'Scan() which scans a directory tree recursively looking for files whose names match a pattern. For each file that matches, it calls your custom routine with the filespec so that you can perform some processing on it. By using the callback technique, the generic recursive directory scanning logic can be re-used without modification in many different applications; the customized callback routine allows each application to process the files differently.

Function Fn'Dir'Scan(dir$ as s260, wild$ as s100, &

@procfile() as lblref) as i4

do

file$ = <next entry in directory>

if <file$ is a normal file and matches wild$>

Fn'Dir'Scan += 1 ! count matching files

call procfile(entry$) ! callback routine for file

elseif <file$ is a subdir>

count += Fn'ProcDir(file$, wild$, @profile()) ! recursion

endif

loop until <end of directory>

EndFunction

To use the Fn'Dir'Scan routine, we need to define our callback routine and pass it by reference to the Fn'Dir'Scan routine. For a simple example, here's a callback routine that just prints the file name:

Procedure Show'File'Info(fspec$ as s260:inputonly)

print fspec$

EndProcedure

Now we can use the generic Fn'Dir'Scan() function to print the names of the .bp files in all of the subdirectories of c:\vm as follows...

count = Fn'Dir'Scan("c:\vm", ".bp", @Show'File'Info())

Later in the same app we might want to copy all the matching files to a backup directory. We can use the same Fn'Dir'Scan() routine, but supply a different callback function...

Procedure Backup'File(fspec$ as s260:inputonly)

xcall MIAMEX, MX_COPYFILE, fspec$, ...

EndProcedure

...

count = Fn'Dir'Scan("c:\vm", "*.bp", @Backup'File())

Example 2

See this more complete example in the SOSLIB .


User-Defined Function Examples

Here is a simple example of a function to format a decimal integer value as a hex string:

Function Fn'Dec2Hex$(decval as b4, flags, width) as s16

map1 hexon,f

xcall MIAMEX, MX_GETHEX, hexon ! see if we are in hex mode

if (not hexon) then xcall MIAMEX, MX_SETHEX, 1 ! if not, set it

xcall MIAMEX, MX_OCVT, decval, width, OT_MEM or flags, Fn'Dec2Hex$

if (not hexon) then xcall MIAMEX, MX_SETHEX, hexon ! restore octal

EndFunction

This slightly more complex example of a function to allocate a file illustrates some additional capabilities, such as static local variables and error trapping:

Function Fn'Alloc(spec$ as s120, bytes as b4) as b2

map1 blocks,f,6

static map1 s'tot'allocations,f

on error goto Trap ! local error trap

blocks = int((bytes + 511) / 512)

allocate spec$,blocks

s'tot'allocations = s'tot'allocations + blocks

Fn'Alloc = 0 ! unnecessary but explicit

exitfunction ! exit function

Trap: ! note this label doesn't conflict with outer TRAP

Fn'Alloc = err(0) ! set return value to error #

resume endfunction ! clear Basic error and return

EndFunction

In the above example, the local static variable s'tot'allocations will get incremented by the number of blocks each time the function is called. (It doesn't serve any purpose in this example, as there is no way to retrieve it, but it might, for example, be used to prevent the program from allocating too many blocks in one session, or for computing statistics.)


Procedures

Syntax

{PRIVATE} PROCEDURE procname(var1{=defval} {as <typsiz>{:<mod},...varN{=defval} {as <typsiz>{:<mod})

<optional local MAP statements, with optional STATIC prefix>

<optional XGETARGs>

<nearly any kind of statements>

XPUTARG n,<expression> ! return (1 or more) parameters

ENDPROCEDURE

Notes

Procedures are exactly like User-Defined Functions (which see, for many details) except that they cannot be used as expressions, and they don't return an expression value. (Like functions, or SBX routines, they can update any of the parameters passed.) They also use similar but separate keywords:

FUNCTION PROCEDURE

ENDFUNCTION ENDPROCEDURE (also END FUNCTION and END PROCEDURE)

EXITFUNCTION EXITPROCEDURE

To call the procedure, use a form of the CALL statement:

CALL procname(var1,...varn)

History

2016 August, A-Shell 6.3.1523, compiler edit 770: Add private attribute for functions and procedures.

2014 January, A-Shell 6.1.1373: Named parameters implemented in A-Shell.


Error Trapping

This is a placeholder to remind the authors that documentation for this topic needs to be written.

Here are two links that might be helpful:

• Error Trapping in Functions

• Error Trapping in Subroutines


Dot Functions

Like Dot Variables, Dot Functions are so named because they begin with a period (dot).When adding new reserved words to A-Shell, there is always the problem of possibly using a word that a programmer has used as a variable or label. Consequently, we have taken to creating reserved words that begin with a period, since this is illegal in user variables and thus guaranteed not to conflict with anything. It's not a perfect solution, but it works.


Call Stack Tracing

Added December 2012

When a Basic error occurs and the system trace opcode BASERR is set, details about the error will be automatically logged to the ashlog.log file. For example:

04-Dec-12 14:36:50 [JACKX201:02-2]<TEST1:UTIL99> Trapped Basic Error #10 at location counter 11219

04-Dec-12 14:36:50 [JACKX201:02-2]<TEST1:UTIL99> Call stack trace, from program TEST1 :

From loc 494, Xcall UTIL99

From loc f42d, Call Proc() @f5d6

From loc fc85, Call Proc() @10d37

The first line indicates that the error #10 occurred at location 11219 (hex) in UTIL99.SBX which was called by TEST1; and that it was trapped.

As of A-Shell 6.1.1325, if the error occurs anywhere but the main body of the main program, a call stack trace will be shown as well, so as to help you identify how the program got to where the error occurred. For deeply nested errors, this can be a significant aid to debugging. The above stack trace starts out in program TEST1, location 494 (hex), where there is an XCALL UTIL99. Next, at location f42d within UTIL99.SBX, there is a call to procedure whose address is 5fd6. You'll need to use the LSX file to look up that location to determine the name of the procedure. Similarly, from within that procedure, there is another procedure call at location fc85, to a procedure whose address is 10d37.

Under UNIX, the call stack trace will also be logged in the case of segmentation fault (which should be a rare occurrence, but when it does happen, the stack trace is invaluable since there's no way to trap the error before the entire process is terminated.

History

2012 December, A-Shell 6.1.1325: Feature added to A-Shell


Extensions

Besides supporting the entire AlphaBASIC 1.3 and 1.4 language definitions, A-Shell/BASIC ("ASB") supports a variety of extensions which add significantly to its power, as well as making it easier for programmers familiar with other modern languages to feel more at home in ASB. In the following documentation, these are divided into three sets:

Name | Descriptions
PLUS Extensions | Features that are part of the AlphaBASIC Plus standard
A-Shell Extensions | Features that have been added to A-Shell but which are not formally part of any other BASIC standard. Many of these have been inspired by equivalent functions in other languages.

Subtopics

PLUS Extensions

A-Shell Extensions


PLUS Extensions

The /X:1 switch (or equivalently, COMPLP) extends the compiler support to include certain statements which were originally implemented by BASIC Plus under AMOS; these are listed below. Refer to the AlphaBASIC PLUS User's Manual published by Alpha Microsystems for more details on these language features.

Note that although A-Shell supports these BASIC Plus language extensions in source code, in no way does it support the .RP (compiled BASIC Plus) file format. Instead, it compiles them as non-standard extensions to the .RUN format, and any such .RUN files will not be compatible with RUN.LIT or RUNP.LIT under AMOS. Thus, if you choose to use these language extensions and want to run them under both A-Shell and AMOS, you will have to recompile the source on both platforms.

The /RC (Run Compatible) on COMPIL, when used in place of the /X:1 or /X:2 switch, allows many of these extensions to be compiled into a RUN format that remains compatible with AMOS. In the following table, the "/RC?" column says whether, when compiling with the RC switch, use of this statement or feature will produce a run file that is run compatible ("RC") with AMOS. NOTE: THIS PARAGRAPH is repeated in A-Shell Extensions. If you change it here, re-copy/paste there.

Extension | /RC? | Meaning
AMOS |  | Execute AMOS commands as subroutines
CMDLIN |  | Retrieve command line
DEFINE | Yes | Define a symbolic constant
DIVIDE’BY’0 |  | Determine how to handle divide by zero
DO LOOP | Yes | Repeat loop while (or until) a condition is (or becomes) true.
EDIT$ |  | String editing function
ERRMSG(x) |  | Returns the text of the error message associated with the specified error number (from the SYS:ERRMSG.xxx file).
EXIT | Yes | May be placed inside of a DO...WHILE or For ... Next loop to cause an immediate exit of the loop.
FILL$ |  | Copies the given expression, partially or multiple times, up to the specified length.
FOR … NEXT | Yes | Traditional loop structure using a loop counter.
GETKEY |  | Input a character
Hex, Octal, ASCII Values | Yes | Specifying literal values in an alternate radix
I variable type |  | Integer variable type
IF / ENDIF | Yes | IF <condition> THEN statements ENDIF
INPUT RAW |  | Raw input, from file channel or keyboard, into X variables.
ISAM’INDEXED {‘EXCLUSIVE}, ISAMP’INDEXED {‘EXCLUSIVE} | Yes | These file type specifiers may be used in file OPEN statements to clarify if the file is to be handled as ISAM 1.0 or ISAM-A. See /I switch above. Note that this applies to AlphaBASIC 1.4 as well as BASIC Plus.
LOOKUP ("fspec") |  | Similar to LOOKUP but returns file size as value of expression. Note that a zero block file returns 0.5.
ODTIM |  | Day / Time output conversion/formatting
OPEN for APPEND |  | Enhancement to OPEN #CH, FSPEC, APPEND
PRAGMAS |  | See PRAGMAs in A-Shell Extensions.
READ'ONLY |  | File open mode modifier
REPEAT | Yes | Jump to top of loop structure to begin next iteration
STRIP(var) or STRIP$(var) |  | Returns var with all trailing spaces removed.
SWITCH | Yes | Conditional execution based on value of an expression.


A-Shell Extensions

In addition to the AlphaBASIC and AlphaBASIC Plus statements, A-Shell also supports a set of statements which are only available under A-Shell—i.e., are not part of the AlphaBASIC environment. These statements are listed in the table below, and are referred to as the A-Shell Extensions. To invoke these extensions, use:

• /X:2 to create a standard .RUN file

• /X:3 to create an .SBX file

Note that /X:3 does not disturb an existing .RUN, so it is possible to compile the same source into both a .RUN and a .SBX, as follows:

.COMPIL MYPROG/X:2 ; create MYPROG.RUN

.COMPIL MYPROG/X:3 ; create MYPROG.SBX

However, in order to make this workable, you'll need to modify the ASHINC:XCALL.BSI file to merely set a flag indicating if it is running in SBX mode or not, instead of aborting with an error message if run directly using RUN MYPROG. You would then test that flag to decide whether to pick up and return parameters.

The /RC (Run Compatible) on COMPIL, when used in place of the /X:1 or /X:2 switch, allows many of these extensions to be compiled into a RUN format that remains compatible with AMOS. In the following table, the "/RC?" column says whether, when compiling with the RC switch, use of this statement or feature will produce a run file that is run compatible ("RC") with AMOS. NOTE: THIS PARAGRAPH is repeated in Plus Extensions. If you change it here, re-copy/paste there.

Extension | /RC? | Meaning
3D Print Tab | Note 1 | Tab(x,y,z). See Three-D Print Tab.
Call Stack Tracing |  |
Comment | Yes | Comment may follow an & on a continuation line
COMPILER_VERSION Macro |  |
Conditional Compilation | Yes |
DEBUG |  | Control variable. If /DEBUG compile switch specified, acts as if it equals 1, otherwise 0. If /DEBUG switch is not specified, then it may still be activated at runtime by using SET DEBUG, or MX_DEBUG. Note that for backwards compatibility, mapping DEBUG explicitly as an ordinary variable will disable the control variable DEBUG. See Note 3 below.
DEBUG statements | Yes | See TRACE and DEBUG Statements.
Defined Structures | Yes | Allows you to assign a type name to a set of MAP statements and then use that as if it was a data type.
DIMX | Note 4 | Enhanced dynamic array allocation. See Dynamic Arrays (DIMX).
Dot Variables |  | Read-only system variables.
DPRINT | Note 2 | Creates a static text control using the current default GUI (proportional) font and with the sunken attribute. Note that if the /X:2 switch not specified, TPRINT is compiled as PRINT. Intended for displaying data fields. See PRINT Statement.
Dynamic variables |  | Dynamically-Sized Variables.
ELSEIF Clauses | Yes | One or more ELSEIF clauses may be inserted into an extended IF/ELSEIF/ELSE/ENDIF statement.
EPRINT |  | Embeds the output fields in edit boxes; is typically used for displaying editable data fields. See PRINT.
ERROR <message> | Yes | Causes the message to be displayed and is treated as a compiler error. This is particularly useful in conjunction with conditional compilation, as shown in the preceding example.
INPUT CSV |  | Input comma separated values
INSTR() |  | When the fourth parameter (flags) is specified (even if 0), the pattern is treated as a regular expression.
ISAM Statements |  |
Line length | Yes | Maximum source line length of 3070 instead of 512.
MAP Statement |  | PRIVATE and PUBLIC keywords for fine tuning scope of variables (MAP or DIMX).
MESSAGE <message> |  | Equivalent to ERROR <message> except that no error is generated.
Nested ++Includes | Yes | Nesting to 13 levels deep
PAD |  | Pad a string with spaces
PRAGMAs | Yes | Compiler directives.
Procedures |  |
REDIMX |  | Re-dimensions an array originally created with Dynamic Arrays (DIMX).
Return <expression> |  | Return value from XFUNC
Shortcut Operators | Yes |
Three-D Print Tab | Note 1 | Tab(x,y,z).
TPRINT | Note 2 | Same as DPRINT but without the sunken effect. Also note that SET AUTOTPRINT causes all PRINT statements to behave at runtime as if they were compiled as TPRINT. See PRINT Statement.
TRACE and DEBUG Statements | Note 3 | These statements open, print to, and close the debug message window.
Underlines in variable names | Yes | Variable names (and constants) may contain underlines. Although this has no special meaning, by convention it is used primarily with constants.
User-Defined Functions |  |
WRITECD |  | Output comma delimited values
WRITETD |  | Deprecated; see WRITECD for important note. Old documentation: same as WRITECD, except that it outputs Tab delimiters instead of comma delimiters.
UNDEF <symbol> | Yes | Causes the specified symbol to be undefined, allowing it to be redefined or to fail a ++IFDEF symbol test.
XFUNC |  | Call an external (SBX) function
XGETARG |  | Retrieve XCALL parameters. See XGETARG, XGETARGS, XPUTARG.
XGETARGS |  | Retrieve XCALL parameters. See XGETARG, XGETARGS, XPUTARG.
XPUTARG |  | Return XCALL parameters. See XGETARG, XGETARGS, XPUTARG.
XREAD |  | Allow record access via explicit record numbers. See XREAD, XWRITE.
XWRITE |  | Allow record access via explicit record numbers. See XREAD, XWRITE.

Note 1: Compiler ignores "z" value.

Note 2: DPRINT / EPRINT / TPRINT are compiled as if PRINT. DO NOT CHANGE THESE NOTE NUMBERS; THEY'RE REFERENCED ABOVE.

Note 3: TRACE.xxxx / DEBUG.xxxx are compiled as XCALL EVTWIN; need to supply AMOS implementation.

Note 4: Statement will be compiled if OPTIONS=RC_DIMX in miame.ini; however, the runtime token is not AMOS-compatible, so you must have other runtime logic to detect AMOS and avoid the statement.


Introduction to GDI Printing

Updated February 2010 (see "History")

Refer to the PASSTHROUGH parameter for a discussion on the GDI printing method versus the "RAW" or PASSTHROUGH method. Note that GDI printing is primarily a Windows topic, but might still apply to A-Shell/UNIX if ATE is available on the workstation as an auxiliary print service. In that case, you would need to use COMMAND=SBX:GDIPRT in the printer init file on the UNIX side.

When working in the Windows environment, it is natural to want to do things in the most Windows-like fashion possible so that your A-Shell application appears to function just like "any other standard Windows application." However, a "standard Windows application" does not open a print file to create a report and then send it to the spooler when the report is complete, as does a typical AlphaBASIC application. Instead, it opens up a "printer context" within Windows' Graphic Device Interface subsystem, and then uses GDI functions to tell the GDI system how to create the report. Even the ordinary text of the report is "fed" to the GDI system, which decides how to render it in a form the printer can use.

Switching to the "standard Windows" technique of creating reports would force you to have to rewrite all of your report programs, and several new language statements would have to be added to BASIC to support it. Since this doesn’t seem practical for the majority of A-Shell programmers who have already developed large numbers of report programs, A-Shell does the conversion dirty work for you. It does this by taking the report file which you sent to the spooler, and then feeds it to the GDI system for you, along with some initial directives to establish the printer orientation, font, etc.

Where does it get these "initial directives?" First, it consults the printer’s initialization file, where it may find such directives as FONT, FONTWIDTH, FONTHEIGHT, ORIENTATION, TMARGIN, LMARGIN, etc. Based on the parameters found there, it creates a suitable printer context and then feeds the contents of your report file to the GDI using that context.

The only problem with this technique is that it doesn’t give you any opportunity to change fonts or issue other special printer graphics commands in the middle of the report. (Even if you knew the printer type in advance, it generally doesn’t work to embed actual escape sequences in the report when using this technique, because the printer driver called by the GDI system to process the text is likely to try to render them graphically as special characters.) To deal with this problem, the A-Shell embedded print directives were developed. These commands may be embedded directly in the print file (as their name suggests) but they are logical directives expressed in a form that the GDI system can understand (after appropriate translation by A-Shell) rather than printer-specific escape sequences. Besides the advantage of actually working at all, this technique has the additional advantage of being device independent.

History

February 2010, A-Shell 5.1.1207: GDI Printing refinement: When a //GDI directive fails, the directive itself is printed (rather than the intended effect of the directive). In addition, if the directive failed because of a Windows error, then the error code will be printed at the end of the line, e.g. "(err 1400)". You can look up Windows error codes on the web, or translate them using MX_ERRNOMSG.

March 2008, A-Shell 5.1.1110: This release of A-Shell included a new product/function called APEX," for A-Shell Preview and EXport. In order to accommodate the needs of the print preview logic in APEX, the core of the A-Shell's GDI printing code underwent a major rewrite. Nothing was changed about how GDI print operations work, and there should in fact be no impact on GDI printing as a result of the rewrite. Nonetheless, the fact of the rewrite is mentioned here so as to keep A-Shell developers well informed.

Subtopics

Writing GDI Print Directives

Parameters: Symbols vs. Values

Line (Vertical) Spacing

Printing Special Symbols


Writing GDI Print Directives

Here are some rules and guidelines for dealing with A-Shell's GDI print directives.

• To embed GDI print directives in your print file, they must begin in column one with // (two forward slashes) followed by the name of the directive and its parameters.

• A comma must immediately follow the directive, and commas must separate all parameters, with no intervening spaces.

• String arguments may be quoted with the double-quote mark "like this" to make sure punctuation characters within the string itself—especially embedded commas—are not confused with the syntax of the command.

• Embedded GDI directives are only processed if PASSTHROUGH=OFF.

• Comments, which are ignored for printing purposes, are indicated by beginning a line with "//;", two slashes followed by a semicolon, starting in column 1. This is useful for documenting your other GDI print directives which might otherwise be less than obvious when examining the file in a text editor. Note that comments may not appear elsewhere, like on the end of the line after an exclamation point as in ASB.

• To change font or issue some other GDI print directive in the middle of a line of output, append a backslash to the end of the first part(s) of the line to hold the position so that the next line of output starts where the previous one left off. See the example in the next section for further clarification.

• Some printer/printing characteristics, such as paper orientation (landscape or portrait), can be changed only with printer initialization file commands and not with GDI commands.

• While most GDI printing operations can be performed by embedding GDI Print Directives into the print file, there are some printer init commands that may affect or work in conjunction with GDI Print Directives. Specifically, the commands XOFFSET, YOFFSET, XORIGIN, YORIGIN control the "fine" positioning of the print on the paper.

• Also note that the printer init parameters PITCH, LPP, CPP, FONT, FONTHEIGHT and FONTWIDTH may affect the way plain text is rendered, even when it is found in a print file otherwise full of GDI print directives.

• Neither the GDI directives nor their associated parameters are case sensitive.

Sample GDI Printfile

This example of a GDI printfile illustrates a few important things such as comments, embedded GDI directives, and the use of the backslash line terminator to allow a change of font in the middle of a line.

//; This is an example of a printfile using embedded GDI directives.

//; Any line starting with //; is a comment and is ignored during printing

//; Set units to 1/100 of an inch

//SETMAPMODE,LOENGLISH

//; Establish font (otherwise we'll get the default or one set by printer init

//SETFONT,120,Times New Roman,0,16

Lines like this are printed using the current font,

and advance down the page in the normal way.

//TEXTOUT,25,45,"Text can also be output with //TEXTOUT at specific positions"

//RECTANGLE,40,75,240,100,1

//TEXTCENTER,40,75,240,100,"This text is in a shaded box"

//;TEXTxxx does not move internal cursor, but MOVETO does

//MOVETO,0,110

//;Lines ending in backslash leave cursor in position at end of line

This line changes to \

//SETFONT,120,Times New Roman,0,16,0,3

Underlined Italic \

//SETFONT,120,Times New Roman,0,16,0,0

in the middle of the line.

The above sample would print as shown below. Note the use of the backslash to break the last line into parts so that the font could be changed in the middle of the line.


Parameters: Symbols vs. Values

Many GDI printing parameters can be expressed either numerically (in normal base 10 or hex notation), or symbolically, using symbol names that happen to match those used by Windows, as well as being defined in ASHINC:ASHELL.DEF.

Prior to build 945, A-Shell forced you to express all such parameters in base ten numeric format within the print file itself, resulting in GDI commands like the following:

//SETFONT, 120, Arial, 34, 0, 512, 1

Beginning with build 945, you can express those arguments using the hex notation (&h022) or symbolic names as documented with the individual GDI directives. So the above command could be expressed in any of the following ways:

//SETFONT, 120, Arial, &h022, ANSI_CHARSET, FW_EXTRABOLD,FS_ITALIC

//SETFONT, 120, Arial, VARIABLE_PITCH | FF_SWISS, ANSI_CHARSET, FW_EXTRABOLD,FS_ITALIC

//SETFONT, 120, Arial, variable_pitch | ff_swiss, ansi_charset, fw_extrabold,fs_italic

//SETFONT, 120, Arial, variable | swiss, ansi, extrabold, italic

These examples illustrate the following points:

• Upper and lower case doesn't matter.

• You can use the vertical bar symbol to combine two symbolic values into a single parameter. (This applies only to symbolic names, not to decimal or hex values.)

• You can drop the suffixes and prefixes such as _CHARSET, _PITCH, FW_, FS_, etc.

This last point may cause some confusion, since normally symbol names (like variable names) must be precise. If you handle any of these parameters as numeric values (perhaps storing them in numeric variables) then you will want to use the precise symbols as defined in ASHINC:ASHELL.DEF, e.g. FONT'FAMILY = FF_SWISS, since these are interpreted by the compiler, which is not very forgiving. But if you are going to use the symbol names as literal strings in the print file, the A-Shell print formatter will parse them by looking for the "important" parts of the symbol names. Thus, the prefixes and suffixes which are common to all the symbols in a group are ignored and need not be included.

Use of the symbol names rather than the numeric values will make both your programs and the print files themselves easier to understand and therefore to modify.


Line (Vertical) Spacing

Reviewed May 2009

Although it is possible to create output in which every bit of text is explicitly positioned (e.g. using TEXTOUT), it is common for some or even all of the text in a GDI report to rely on some kind of automatic line spacing. To this end, the GDI output system maintains a virtual "cursor" (print head?) which marks the position where the next character will be output, unless some kind of explicit repositioning command is issued first. This cursor moves horizontally (based on the character widths) as text is output, and vertically whenever a line terminator (CRLF or just LF) is processed.

The remainder of this topic discusses the various commands and parameters which determine how the vertical line spacing is calculated.

LPP in the printer init file: The initial line spacing is determined by the combination of the LPP (lines per page) parameter in the printer init file and the effective paper size (which may be determined at print time based on user actions and/or printer driver defaults). For example, if LPP=63, and the effective paper length (minus the physical printer margins) is 10.5 inches, the initial line spacing will be set to 1/6 inch. If there is no LPP specified in the printer init file (or if there is no printer init file), a default value of 66 is used for portrait and 51 for landscape. Note that unless the printer init file also specifies PITCH=AUTO, the line spacing will be independent of the initial font size (which is determined by a FONT parameter in the printer init file, SETFONT directives in the print file itself, or the printer driver defaults).

SETVMI: This directive in the print file overrides any previous line spacing and establishes new spacing. Note that such spacing is independent of font and paper sizes. See comments below for details on precision.

RESETLPP: This directive in the print file cancels the line spacing established by the printer init file and/or a prior SETVMI. Once the default line spacing has been reset in this way, it will be automatically adjusted to match the natural line spacing of font of the current font (and will continue to be automatically adjusted by subsequent SETFONT statements).

SETFONT: These directives in the print file do not normally change the line spacing established by the printer init file and/or a prior SETVMI, unless the prior line spacing has been reset by a RESETLPP statement, in which case the line spacing is adjusted to match the natural cell height (including external leading) of the font.

SETTEXTALIGN: This does not affect the line spacing, but does affect the relationship of the characters to the "cursor". Without an explicit SETTEXTALIGN directive, the cursor position is taken to be the upper left corner of the next character cell.

Comments

Prior to A-Shell 5.1.1150.0, the vertical line spacing resulting from the above factors was always rounded down to the nearest pixel of the output device. This sometimes resulted in overall vertical spacing less than anticipated. For example, if you used the combination of //SETMAPMODE,TWIPS and //SETVMI,180 to establish 8 lines per inch spacing, on a 300 DPI device, that comes to 37.5 pixels per line, which was being rounded to 37. By the bottom of the page, those half-pixels could add up to the equivalent of an entire line. But changing the DPI of the output device to 600 would have made the rounding error go away.

Starting with A-Shell build 5.1.1150.0, the line spacing is instead maintained internally in tenths of pixels and only rounded to the nearest pixel when actually positioning a line of text. This eliminates the accumulation of rounding / conversion errors as you move down the page, and makes the spacing nearly immune to changes in the device resolution (both good things) but could result in slightly different vertical spacing (i.e. more precise) vs. the prior version.


Printing Special Symbols

You may insert nearly any special symbol into printed text by embedding the corresponding Unicode Symbol Entity Reference into the text (whether plain text or text passed as an argument to TEXTOUT). These Symbol Entity References must have one of the following syntaxes:

&#ddd; decimal version, ddd are decimal digits

&#xhhhh; hex version, hhhh are hex digits

In either case, the numeric value is taken as a reference to the corresponding UNICODE "code point". Note that the trailing semi-colon is required.

Example

The formula for the circumference of a circle is 2&#x03c0;r

(&#x03c0; is converted at print time to the symbol for pi)

See also

SETOPTION, TEXTOUT


Print Directive List

Updated November 2013 (added SETOPTION)

Directive | Description
Totpages (%#) | Total pages in document
BIN | Specifies paper bin or tray
DUPLEX | Sets DUPLEX options
ELLIPSE | Draws ellipse
ESCAPE | Passes raw ESC codes to printer
IMAGE | Inserts image
LINETO | Draws a line
META | Embeds unspecified meta data
METAFILE | Inserts metafile
MOVETO | Positions cursor
ORIENTATION | Accepts two arguments, LANDSCAPE and PORTRAIT. Overrides the orientation previously set in the printer init file, spooler switches, or default.
PAPERSIZE | Set paper size
PASSTHROUGH | Set printer mode
PDFX | Controls generation of PDF documents
POLYGON | Draws a polygon
RECTANGLE | Draws a rectangle
RESETFONT | Restores original font.
RESETLPP | Resets the current lines-per-page value
SETBKCOLOR | Sets background color
SETBRUSH | Sets line thickness and style for filling
SETFONT | Sets font
SETMAPMODE | Set position for subsequent drawing
SETOPTION | Selectively enables various options affecting GDI printing.
SETPEN | Sets line thickness and style for drawing
SETPENEX | Extended version of SETPEN
SETTEXTALIGN | Sets alignment method
SETTEXTCOLOR | Sets text color
SETVMI | Sets vertical spacing
TEXTCENTER | Outputs and centers a line of text
TEXTINDENT | Variation of TEXTOUT for hanging indents
TEXTOUT | Outputs a line of text
TEXTRIGHT | Outputs a line of text right justified
TEXTRECTANGLE | Output multiline text into rectangle
XOFFSET, YOFFSET | Make minor positioning adjustments.
XORIGIN, YORIGIN | Define offset from paper corner.
XMDATA, XMFIELDS | Control XTEXT mail merge
XTEXT | Print a text or RTF file into rectangle


Totpages (%#)

The pseudo-directive %#, inserted anywhere in the printfile, will be converted to the total number of pages in the printfile. Note that "totpages" is not part of the command; just the symbol %#. Also note that unlike the other GDI print directives, this one does NOT require the // prefix. See the discussion of the EZSPL.SBR parameter totpages for more details.


BIN

Updated and reviewed November 2011

//BIN, bin-ID

BIN is one of the GDI print directives with a Printer Init File Equivalent. For detailed information, see the printer init file command BIN.

Unlike other such directives, which must occur at the top of the file, BIN can occur at any point in the print file. If printing has already begun when BIN is encountered, the effect is delayed until the next page break. To force it to have an immediate effect, insert a chr(12) (form feed) character at the start of the line following the BIN command.


DUPLEX

Reviewed March 2011

//DUPLEX, mode

DUPLEX specifies which of the three types of duplexing will be used. The possible values, along with their several aliases, are shown in the following table.

Value | Aliases
Horizontal | Horz, H, Short, S, 3
Vertical | Vert, V, Long, L, 2
None | Off, False

DUPLEX is one of the GDI printing directives with a Printer Init File Equivalent.


ELLIPSE

//ELLIPSE, left, top, right, bottom, {fill}

ELLIPSE draws an ellipse within a specified bounding rectangle.

Parameters

left, top, right, bottom

Coordinates of the bounding rectangle, in the current mapping units, within which the ellipse is drawn. Note that if these coordinates describe the special case of a square, then the resulting ellipse will actually be a circle.

fill

If specified, causes the ellipse interior to be filled with various shades of gray or colors. See the table of fill values under RECTANGLE for details.


ESCAPE

//ESCAPE, B1, B2, B3, B4,... (up to B14 max)

ESCAPE is used for passing raw ESC codes to the printer in the midst of GDI output.

Each parameter should be a decimal value representing the value of a single byte. Parameters B2 thru B14 are optional.

This command is most useful for passing PCL commands to a PCL-compatible printer when you can't figure out how to accomplish the same thing using GDI commands. For example, laser printers normally have a built-in physical margin of 0.25 inches around the outer edit of the paper. But there is a PCL command to adjust this so that the first column printed is closer or farther from the edge of the paper. (This is useful for calibrating a printout to a form.) The PCL to move the left margin 300 decipoints to the right is:

ESC &l300U

If you try to just embed this command in a GDI printout, it will probably be ignored by the driver. But using the ESCAPE command, you can embed it as follows:

//ESCAPE,27,38,108,51,48,48,55


IMAGE

Updated November 2012; see History

//IMAGE, imagespec, left, top, right, bottom {,flags, borderwidth, imagespec2, rotation, pageno}

IMAGE works like METAFILE except that it supports BMP, JPG, PCX, TIF and PNG format images. It requires, however, that an external graphics library, VIC32.DLL, be present and licensed. Note that if any error occurs while trying to print the image, including the specified rectangle extending beyond the printable region of the page, the IMAGE command itself will print rather than the image. See the topic Parameters: Symbols vs. Values if you have questions about which to use.

Note that you must specify a SETMAPMODE option other than TEXT.

Parameters

imagefilespec

File specification of the image (AMOS-style or native). PNG files with WMF extensions are supported. Note that true metafiles with WMF extensions should be handled by METAFILE.

left, top, right, bottom

Bounding rectangle (within current coordinate system) into which the image will be fit. The image may be stretched to fill the rectangle, depending on the flags argument. Setting the right and/or bottom parameter to 0 will be interpreted as the rightmost and/or bottommost edge of the page. Use 0,0,0,0 to fill the entire page, minus the printer’s physical margins.

flags

Add together the applicable options: caution: table is duplicated in XCALL Ref / AUI Image; update there if you update here

Symbol | Value | Description
IMGF_HALFTONE | &h001 | Use halftone print method.
IMGF_SCATTER | &h002 | Use scatter print method.
IMGF_STRETCH | &h004 | Stretch image to fit bounding rectangle. Otherwise retain aspect ratio, meaning the image will likely be smaller than the rectangle in one of the two dimensions.
IMGF_SCALEQ | &h008 | Interpolate—i.e., use hq scaling.
IMGF_FORCEXFER | &h010 | (ATE) Force image filespec to be treated as relative to the host and transfer it to the client. Applies to IMGOP_LOAD and IMGOP_LOADDISP.
IMGF_OPTIONAL | &h020 | Applies only if imagefilespec is missing. Then: if imagefilespec2 is present, print it. If it is not present, print nothing. Value may also be expressed as the text "Optional." See "Image Is Not Present" discussion, below.
IMGF_OFFSET | &h040 | Causes images to be shifted according to the XOFFSET and YOFFSET values. Normally images only obey the XORIGIN and YORIGIN values, ignoring the XOFFSET and YOFFSET values (which allows text to be shifted relative to images when lining up computer-generated forms). But when using multiple XOFFSET and YOFFSET statements to shift/repeat sections of GDI output, the ability to move the images along with everything else is critical.

borderwidth

If non-zero, specifies the width, in pixels, of a solid black border to be drawn around the outside of the rectangle

imagefilespec2

File specification of the image to be printed if imagefilespec1 is not present.

rotation

The angle in degrees, as in the SETFONT directive. Note that the image is first rotated, then fitted to the specified coordinates.

pageno

Specifies the page from within a multi-page TIF file. The first page is considered page number one, but 0 or nothing is also treated as 1. Note that to use APEX as a multi-page TIF image viewer, you would need to first use the AUI_IMAGE IMGOP_PAGEINFO operation to determine the number of pages, then generate a series of IMAGE directives, one for each page, probably separated by page breaks.

File Locations

A-Shell will look for the referenced image file in the directories pointed to by the environment variables ATECACHE and ATE, if it is not found in the originally specified directory. This is mainly useful for ATE printing, where the host may pre-transfer images to one of the cache directories without having to modify the print file or deal with incompatibilities between the directory structure used on the host and on the ATE client.

See the print filter ATPXFR.SBX (in [907,29] of the SOSLIB) for a way to automate such transfers in conjunction with AUXLOC printing. Also see the A-Shell Forum for a detailed description of the issue.

The GDI print commands IMAGE, XTEXT, and METAFILE will locate the specified file in the same directory as the printfile if it fails to find it in the directory specified in the GDI directive or in the local cache. This is mainly a convenience when printing from another directory. For example, if a printfile BAS:TEST.PRT contains //IMAGE,TEST.JPG,... and you tried to print it from another directory using PRINT BAS:TEST.PRT, versions of A-Shell prior to 995.3 would have failed to find the image TEST.JPG in the BAS: directory, because you weren't logged there. It also comes in handy when moving print files and their associated images to another location (such as with ASHLPD), since now you can combine all the associated files in an arbitrary directory.

Beginning with A-Shell 1111 of 3 May 08, XTEXT, IMAGE, and METAFILE will now look for the file in the same directory as the printfile itself, if not found at the location specified, even when the location specified is a UNIX path. This was previously true, since 5.0.999, but only when the original spec was a Windows path. The new logic is mainly of use in ASHLPD or other environments where you generate the GDI printfile under UNIX and then transfer it to Windows.

Image Is Not Present

Beginning in A-Shell build 1181 of May 2010: A new flag and optional second filespec parameter have been added to allow more flexibility in handling the case where the specified image is not present. Normally in such a case, the text of the IMAGE command will be printed at the current "cursor" location on the page. If you would rather have nothing printed, then you can specify the new flag IMGF_OPTIONAL (&h020). You may also specify a second image filespec, which, if the first image is not present, will be printed instead. Either or both of these can be useful in cases where the image file name is derived from some other data (such as a part number), but is not always present (i.e. not every part has an associated image). Rather than the application having to check individually for the presence of each one, the IMAGE command can now do the work for you.

Note that the IMGF_OPTIONAL value can also be expressed as the text "OPTIONAL", for example:

//IMAGE,p123.jpg,100,100,200,200,OPTIONAL,1,generic.jpg

In this example, if p123.jpg is present, it will be printed. If not, and generic.jpg is present, it will be printed. If neither is present, nothing will be displayed (including no border), and there will be no indication of an error.

Also see the print filter ATPXFR.SBX (distributed in the SOSLIB) and the META GDI directive for alternate approaches to making sure that image files referenced by IMAGE directives are transferred to the client PC before needed during remote (AUXLOC:) printing.

History

2013 September, A-Shell 6.1.1362: Add pageno parameter.

2013 February, A-Shell 6.1.1339: IMAGE now fully supports printing of PNG images, including with rotation, using the new GDI+ library.

2012 November, A-Shell 6.1.1322: Add rotation parameter.

2012 November, A-Shell 6.0.1263: Image position may now be set relative to current position, without knowing your current position on the page. The left and/or top coordinate parameters may be set to zero to indicate the current horizontal and vertical position. The right and/or bottom coordinate parameters may be set to negative values to indicate width and height, rather than absolute right and bottom positions.For example,

//IMAGE, spec, 0, 0, -100, -200

will scale the image to 100 by 200 units (in the current mapmode) and position it with the upper left corner at the current cursor position.

2012 May, A-Shell 6.0.1249: Added IMGF_OFFSET


LINETO

//LINETO, x, y

LINETO draws a line, using the current pen (see SETPENEX), from the previous cursor position to the specified position. The parameter x specifies the ending horizontal position and y the ending vertical position, both using the current mapping units.

The current mapping unit is determined by the SETMAPMODE directive.


META

Reviewed March 2013

//META, type, param1, param2, ...

META can be used to embed unspecified meta data in the printfile. The META lines will not print or display in APEX, but will remain in the file, possibly of use to archival or other post-printing routines.

The string parameter type specifies the type of operation or meta-data being used. The parameters following type, if any, are determined by the type of meta-data being passed and the parameters that have been defined for that type of data or operation.

Since META was introduced in A-Shell 5.1.1133 of December 2008 and will therefore not be recognized by earlier versions, the syntax //;META,... is also allowed. (//; indicates a comment line normally, so A-Shell will not display the line, but 5.1.1133+ will still recognize it.)

The only META type currently implemented is FTP, for transferring files between host and PC. See the following topic.

Also see the print filter ATPXFR.SBX (distributed in the SOSLIB) for another approach to making sure that auxiliary files related to printing (such as images referenced by an IMAGE directive) are transferred to the remote PC before needed during printing.

Subtopics

FTP


FTP

//META, FTP, dirflag, hostpath, localpath, {flags}

If the META FTP command is seen by APEX running within ATE, it will attempt to perform an FTP transfer of hostfile to/from localpath.

Note that this command is a sub-command of META, which see for more information.

Parameters

dirflag

Direction code; see AG_FTP in Tab (-10,x) Functions for dirflag values and meanings.

hostpath

should be in native format, to be understood by the FTP server on the host.

localpath

should be in PC format, or it may use the special syntax "@.xxx" where xxx is the desired file extension. The "@." will be replaced by the complete filespec of the file currently being printed or previewed, minus its extension. This is useful for sending printfile sidecar files which will be matched up later based on having the same filename, but where you don't know the complete filename that will be assigned by ATE or APEX to the printfile. (ATE/APEX typically create versions of the original file, in the Documents\APEX directory, with a unique numeric suffix.)

flags

The optional flags argument may be set to 1 to cause any FTP errors to be display in an error message dialog. If this option is not set, any such failure will go unreported, which might be preferable in the context of printing.


METAFILE

Updated May 2008

//METAFILE, metafilespec, leftorg, toporg, right, bottom

METAFILE "plays" an existing Win32 "enhanced" metafile into the current output context, stretching or squeezing as needed to fit within the specified rectangle.

Parameters

metafilespec

File specification of the image (AMOS-style or native)

left, top, right, bottom

Bounding rectangle (within current coordinate system) into which the metafile will be fit.

Comments

A metafile is a device-independent set of instructions for creating graphic output. Metafiles can be created by a number of popular graphics or drawing programs. As an example, you might use a forms-layout program to create a blank form and then output it as a metafile. The form could then be merged with text and images using the METAFILE command. (This would normally be much easier than using TEXTOUT and LINETO commands to create a form.)

The metafile will be played using the current coordinate system, unless the metafile itself changes the coordinate system. Metafiles that are meant to always appear in the same place on the page should set their own mapping accordingly, and should be played back with the origin set to 0,0. On the other hand, metafiles that are meant to be resized and positioned (e.g. a logo or signature) should be setup to start at location 0,0 in the current coordinate system. This way it can be repositioned with the leftorg and toporg parameters, and sized by changing the mapping system.

Technical Note

In all other cases, the mapping modes are based on the origin being at the upper right corner of the page, with the units increasing in the positive direction as you move down and across the page. However, for metafiles, this is only true for mapping mode Text. For all other modes, the origin is still the upper left corner and the horizontal units increase as you move across the page, but the vertical units decrease (i.e. increase in the negative direction) as you move down the page. Consequently, if your metafiles are internally based on a mapping mode other than Text, you must set the same mode prior to playing the metafile (unless the metafile internally sets its own mapping mode.) Regardless of what happens inside the metafile, the current position and mapping mode for subsequent drawing primitives is preserved (i.e. unchanged).

File Locations

A-Shell will look for the referenced image file in the directories pointed to by the environment variables ATECACHE and ATE, if it is not found in the originally specified directory. This is mainly useful for ATE printing, where the host may pre-transfer images to one of the cache directories without having to modify the print file or deal with incompatibilities between the directory structure used on the host and on the ATE client.

The GDI print commands IMAGE, XTEXT, and METAFILE will locate the specified file in the same directory as the printfile if it fails to find it in the directory specified in the //GDI directive or in the local cache. This is mainly a convenience when printing from another directory. For example, if a printfile BAS:TEST.PRT contains //IMAGE,TEST.JPG,... and you tried to print it from another directory using PRINT BAS:TEST.PRT, versions of A-Shell prior to 995.3 would have failed to find the image TEST.JPG in the BAS: directory, because you weren't logged there. It also comes in handy when moving print files and their associated images to another location (such as with ASHLPD), since now you can combine all the associated files in an arbitrary directory.

Beginning with A-Shell 1111 of 3 May 08, XTEXT, IMAGE, and METAFILE will now look for the file in the same directory as the printfile itself, if not found at the location specified, even when the location specified is a UNIX path. This was previously true, since 5.0.999, but only when the original spec was a Windows path. The new logic is mainly of use in ASHLPD or other environments where you generate the GDI printfile under UNIX and then transfer it to Windows.


MOVETO

//MOVETO, x, y

MOVETO positions the internal cursor to the specified point relative to the current mapping mode (see SETMAPMODE). The parameter x specifies the starting horizontal position and y the starting vertical position, both using the current mapping units.

Its only effect will be on subsequent operations (e.g. LINETO) and subsequent text that is not part of an explicit GDI command.

MOVETO may also be used to disable A-Shell's auto-page break. A single //MOVETO,0,0 anywhere on each page tells A-Shell to turn off its line-counting logic.


PAPERSIZE

Added August 2009

//PAPERSIZE,<size>

The <size> parameter may either be one of the symbolic names, or the equivalent numeric value. For example, the following two are equivalent.

//PAPERSIZE,LEGAL

//PAPERSIZE,5

One way to get the numeric equivalents is to activate the LP trace and print a file containing any PAPERSIZE command; this will cause all the supported paper size names (and numbers) to be listed in the log or debug window.

PAPERSIZE is one of the GDI printing directives with a Printer Init File Equivalent.

History

2009 August, A-Shell 1158: Function added to A-Shell


PASSTHROUGH

//PASSTHROUGH ON

//PASSTHROUGH OFF

The PASSTHROUGH option may be toggled as above. PASSTHROUGH is one of the GDI printing directives with a Printer Init File Equivalent.


PDFX

PDFX is A-Shell's "print to PDF file" subsystem, which consists of an entire set of GDI printing directives related to producing and post-processing PDF files. All of these commands begin with "//PDFX," followed by a key and then a value. For example, the following command tells PDFX to overwrite the existing file if it exists:

//PDFX,Save.When.Exists,1

The most common function of PDFX is to produce PDF documents such as invoices and automatically email them to clients. PDFX includes a variety of email-related commands for that purpose.

The PDFX subsystem is documented in a separate help file which you can retrieve from the A-Shell documentation page. Contact MicroSabio if you have questions or would like to add PDFX to your A-Shell license.


POLYGON

Added January 2011

//POLYGON, MODE, BRUSH, X1, Y1, X2, Y2, X3, Y3 {...X10, Y10}

POLYGON draws a polygon based on up to 10 points. Straight lines are drawn between the points using the current pen, including a line from the last point back to the first. The points are specified in the current map mode.

MODE specifies the polygon fill mode:

Mode | Meaning
0 | Use existing mode (whatever was last set)
1 | ("Alternate") Fills in the area between odd and even sides
2 | ("Winding") Fills in any area with a non-zero "winding value".

The difference between the modes is not significant for simple enclosed polygons, but becomes apparent with polygons whose sides cross over themselves. An illustrative example would be a five-pointed star, whose lines intersect to create a pentagon in the middle. The alternate fill mode would fill in the points, whereas the winding fill mode would fill in the entire region.

The winding value is defined as the number of times a pen used to draw the polygon would go around the region.

History

2011 January, A-Shell 6.0.1203: Added to A-Shell


RECTANGLE

Reviewed September 2011

//RECTANGLE, left, top, right, bottom {,fill {,crwidth {,crheight}}}

RECTANGLE draws a rectangle at the specified coordinates in the current mapping mode (as determined by SETMAPMODE), with optionally rounded corners.

Parameters

left, top, right, bottom

specify the respective sides of the rectangle, in the current mapping units

fill

select a value for fill from the table below. See the topic Parameters: Symbols vs. Values if you have questions about which to use.

Symbol | Value | Description
WHITE_BRUSH | 0 | White
LTGRAY_BRUSH | 1 | Light gray
GRAY_BRUSH | 2 | Gray
DKGRAY_BRUSH | 3 | Dark gray
BLACK_BRUSH | 4 | Black
NULL_BRUSH | 5 | Hollow (default)

The light gray, gray, and dark gray fill values will be overridden by a brush defined using SETBRUSH.

Regardless of the fill option, a border will be drawn around the rectangle using the current pen (see SETPENEX). To achieve a solid colored rectangle with no apparent border, set the RGB background in both the SETPENEX and SETBRUSH to the same color.

crwidth, crheight

These optional parameters refer to the "corner radius" width and height, in the current mapping units. For normal (symmetrical) rounded corners, crheight is not needed, and crwidth should be set to the radius of the circle used to draw the arc of the rounded corner. When crheight is specified, the corners are made from the arc of an ellipse whose total height (bounding rectangle) is two times crheight and whose total width is two times crwidth.


RESETFONT

Added June 2013

//RESETFONT

RESETFONT restores the font that was initially calculated based on the printer init and auto-pitch settings. This is useful in reports where you rely on the automatic font settings for the beginning section of the report, then switch to some explicit SETFONT settings, perhaps for a summary page, and then want to return to the original font.

History

2013 June, A-Shell 6.1.1354: Function added to A-Shell


RESETLPP

//RESETLPP

RESETLPP resets the current lines-per-page (LPP) value, which is used to determine the vertical line spacing, so that the line spacing will be based instead on the current font. Even when there is no explicit LPP value in the printer init file, a default LPP is established based on the paper size and default font. Once established, changing the font does not change the vertical spacing (unless you use the RESETLPP command).

For example, assume that the default LPP results in vertical line spacing of 6 lines per inch. If you then change to a 24 point font, and output multiple lines, the lines will overlap vertically because the 24 point font is taller than 1/6 of an inch. To avoid that and instead adjust the vertical line spacing to what would be natural for a 24 point font, just use the RESETLPP command either before or immediately after the SETFONT, as shown here:

//ResetLPP

//SetFont,240,Arial

This line output in 24 point Arial

So is this line (with natural 24 point spacing)


SETBKCOLOR

//SETBKCOLOR, r, g, b

SETBKCOLOR sets the background color to be used for subsequent text output. The r, g, and b (red, green, blue) values have the same meaning as in the SETTEXTCOLOR command (which see for a discussion of the RGB color system). The default background color is 255,255,255 (white), which is taken as transparent. Any other background color setting will cause a ribbon of background color to be written along with any text. For example, this would be necessary in order to print white on blue.

When one color is written on top of another, generally the effect is not additive. Rather, the last written foreground and background colors will prevail. The exception is when the background is 255,255,255 (white), this is taken as transparent and thus will not affect the underlying background color (allowing, for example, text to be written on top of an image.) If you wanted your overlay text to have its own white background, you should set the background color to 254,254,254, which is very nearly white but opaque rather than transparent.


SETBRUSH

//SETBRUSH, style, hatch {, r, g, b}

SETBRUSH is similar to SETPENEX except that it selects a brush that is used only to fill in rectangles and ellipses, and only then when you use the fill options light gray, gray, and dark gray. In those cases, the brush defined previously by SETBRUSH will be used instead of the default brush. See the topic Parameters: Symbols vs. Values if you have questions about which to use.

Parameters

style

Select one of the following styles: Symbol | Value | Description
BS_SOLID | 0 | Solid
BS_NULL | 1 | No brush (negates SETBRUSH)
BS_HATCHED | 2 | Hatched, set below

hatch

If style is set to BS_HATCHED, then hatch defines the type of hatch pattern used by the brush, from the following table:

Symbol | Value | Description
HS_HORIZONTAL | 0 | Horizontal lines (- - - - -)
HS_VERTICAL | 1 | Vertical lines (| | | | |)
HS_BDIAGONAL | 2 | Diagonal lines (\ \ \ \ \)
HS_FDIAGONAL | 3 | Diagonal lines (/ / / / /)
HS_CROSS | 4 | Crosshatch (+ + + + +)
HS_DIAGCROSS | 5 | Diagonal crosshatch (x x x x x)

r, g, b

The r, g, and b parameters are optional, but if specified, must all be specified. See the SETTEXTCOLOR directive for notes.


SETFONT

Updated December 2009

//SETFONT, height, face, pitch-family, {charset, weight, style, rotation, width}

SETFONT is used to select the printer font. If not used, the font will be determined by the FONT parameter within the printer initialization file. The last four parameters are optional, or may be specified as zero for defaults. Note that the color of the font will be black characters on a white transparent background, unless overridden by a SETTEXTCOLOR directive. See the topic Parameters: Symbols vs. Values if you have questions about which to use.

Also see the "Update Note" section at the bottom of this page.

TIP: To change font in the middle of a line of text, use the backslash (\) line terminator on the line prior to the font change in order to suppress the automatic line feed. For this and other tips, pointers and relevant information about writing GDI printing directives, please see Writing GDI Print Directives.

Parameters

height

Height of the font in tenths of points. For example, use 120 to select a 12 point font.

face

Face name of the font. These are the names that appear in the typical Windows font selection dialogs. Typical face names are Courier New, Helvetica, Fixed Sys, Times Roman, etc.

pitch-and-family

Formed as the sum of the following:

Symbol | Value | Description
DEFAULT_PITCH | 0 | Default pitch, don't care about family.
FIXED_PITCH | 1 | Fixed pitch (monospace).
VARIABLE_PITCH | 2 | Variable pitch (proportional space).

Symbol | Value | Description
FF_DONTCARE | &h000 | Don't care.
FF_ROMAN | &h010 | Roman family (serifs, variable pitch.) Example: Times Roman.
FF_SWISS | &h020 | Swiss family (sans serifs, variable pitch.) Example: MS Sans Serif.
FF_MODERN | &h030 | Modern family (fixed pitch, serif or sans serif.) Examples: Courier, Pica, Elite.
FF_SCRIPT | &h040 | Script family (fonts that look like handwriting.) Examples: Script, Cursive
FF_DECORATIVE | &h050 | Decorative family (novelty fonts.) Example: Old English.

charset

Specifies the desired character set, from the following values:

Symbol | Value | Description
ANSI_CHARSET | 0 | ANSI
DEFAULT_CHARSET | 1 | Don't care
SYMBOL_CHARSET | 2 | Symbols
OEM_CHARSET | 255 | OEM (system dependent)

weight

Specifies the desired boldness of stroke, from the following choices. Note that most of these are not supported but are mapped to the nearest supported choice.

Symbol | Value | Description
FW_DONTCARE | 0 | Don't care
FW_THIN | 100 | Thin
FW_EXTRALIGHT | 200 | Extra Light
FW_LIGHT | 300 | Light
FW_NORMAL | 400 | Normal
FW_MEDIUM | 500 | Medium
FW_SEMIBOLD | 600 | Semibold, demibold
FW_BOLD | 700 | Bold
FW_EXTRABOLD | 800 | Extrabold, ultrabold
FW_HEAVY | 900 | Heavy

caution: this table (above) is duplicated in XCALL Ref / AUI Control / fontattr

style

Specifies font style options.

Symbol | Value | Description
FS_UPRIGHT | &h00 | Normal upright
FS_ITALIC | &h01 | Italic
FS_UNDERLINE | &h02 | Underline
FS_STRIKEOUT | &h04 | Strikeout

rotation

The default is zero. Rotation is specified in degrees, with positive numbers being rotated clockwise.

width

This option allows you to stretch or squeeze the width of the font independent of the height. The units of width are equivalent to that of height (tenths of points). Beginning in A-Shell build 1168 of 11 December 2009, you may also use width to specify the character width in terms of the number of characters that would fit on a line, by setting it to the negative of that value. For example, to select a font that would fit 90 characters across the page, set width to -90.

Examples

//SETFONT,120,Arial

This is 12 point Arial, standard options

//SETFONT,100,Times Roman,0,0,200,1

This is 10 point Times Roman, extra light weight, italic

//SETFONT,120,Courier,FIXED_PITCH,ANSI_CHARSET,FW_EXTRABOLD,FS_UPRIGHT

This is 12 point Courier (or something similar in fixed pitch), extra bold, upright

Comments

In the context of fixed-pitch (mono-spaced) fonts, the terms "pitch" and "point" are sometimes confused or at least conflated by the traditional typewriter-era rule-of-thumb that a 12 point font (e.g. Courier, Pica) was equivalent to 10 pitch (10 CPI or characters per inch horizontal), while a 10 point font (e.g. Elite) was equivalent to 12 pitch. In the digital era, that rule-of-thumb falls apart, especially with proportional fonts, where the relationship between height in points and number of characters per inch is completely unpredictable, but even with fixed-pitch fonts, due to the fact that the characters can be made wider or thinner without changing the height. If it is important to select a font with a certain pitch (CPI), use the width parameter to specify it explicitly.

Also note that while there is a natural relationship between the vertical line spacing (LPI or lines per inch vertical) and the font height (i.e. point size), changing the font does not automatically change the line spacing. See the GDI printing directive RESETFONT.

Update Note: A-Shell build 1149 of 16 May 09

GDI printing bug fix/refinement: The width parameter in the SETFONT statement now works more precisely and reliably with fixed pitch fonts, across all font families, printers and resolutions. Previously, certain fonts (most notoriously Courier) didn't "behave" very well. And in addition, since the individual cell width was being rounded to the nearest integer number of pixels, small adjustments to the width were often not having the desired effect with lower printer device resolutions. Now, the cell width is interpolated to 1/8 of a pixel, resulting in fine control even with 100 DPI (e.g. fax) devices.

COMPATIBILITY WARNING: This "fix" could possibly result in a small change in the horizontal character spacing of existing printouts. The change will probably be small, and will always represent a correction, but it is possible that having worked out precise spacing by trial-and-error, you may need to make adjustments after this fix. (After considerable soul-searching and public comment, we decided that since width is a relatively new parameter, rarely used, that the likelihood of this fix actually improving the spacing of existing reports was many times greater than the chance of it making a report worse. But if you use the width parameter to fine tune the fixed pitch spacing of a very precise form, and especially if you used trial-and-error rather than math to figure out the ideal width, you may need to take another look. (The upside is, anyone affected by this would have been at risk of their reports looking different on different printers; so even if you have to make an adjustment, the report will now print consistently across devices.)

A more detailed discussion is available on the A-Shell forum.


SETMAPMODE

//SETMAPMODE, mode

SETMAPMODE establishes the coordinate system for subsequent GDI operations that take positional parameters. Note that in all modes, the point 0,0 is the upper left corner of the page, and the units increase as you go down and across the page. The mode parameter may be expressed as one of the following:

Mode | Description
Text | This is the default coordinate system. Each unit is equal to a pixel. For example, if outputting to a 300 DPI laser printer, each unit is 1/300 of an inch. Note that the horizontal and vertical resolution of the output device may differ.
Loenglish | Units are 1/100 of an inch.
Hienglish | Units are 1/1000 of an inch.
Lometric | Units are 1/10 of a millimeter (254 per inch.)
Himetric | Units are 1/100 of a millimeter (2540 per inch).
Twips | Units are 1/20 of a typesetting Point. A Point is 1/72 of an inch, so a Twip is 1/1440 of an inch.
Decipoints | Units are 1/10 of a typesetting Point (i.e. 1/720 of an inch). Two decipoints equals one twip.


SETOPTION

Updated November 2013

//SETOPTION, option {,boolean}

SETOPTION selectively enables various options affecting GDI printing.

Parameters

embedded-entity-references

enables the interpretation of the symbol entities via their UNICODE values. The default is to treat them as plain text, thus eliminating the remote chance that a semi-random string of data/text will be misinterpreted as containing embedded symbol entities.

ignore-escape-errors

causes A-Shell to ignore errors occurring during the processing of the ESCAPE directive. Normally, when such errors occur, the GDI directive itself is printed to the target device, to make it easier to spot the fact that the directive contained an error. But in the case of ESCAPE, if you redirect the output to a device incompatible with the one for which the ESCAPE sequence was intended, an error may be "normal", hence you wouldn't want it to appear in the output. For example, if you use ESCAPE to embed some special PCL command into a document, but then send it to a PDF generator instead, you would probably want the fact that the PDF driver didn't support the ESCAPE to be ignored.

no-auto-page-breaks

Turns off automatic page break logic. This is handy in single-page GDI files that contain a mixture of drawing commands and many lines of plain text. The same effect has previously been achievable by inserting a //MOVETO,x,y command anywhere on the page, but this is more self-documenting. Note that as with all other SETOPTION attributes, the initial setting is FALSE, while the default {,boolean} parameter is TRUE. So typically the command is only used to enable the attribute (making the {,boolean} unnecessary to specify).

textrect-conservative-vert

Normal TEXTRECTANGLE logic (syntax one) is such that it will start a new line of text as long as the starting point is above the bottom of the rectangle. But in the typical alignment, the starting point is at the upper left corner of the text cell, allowing the last line of text to straddle the bottom of the rectangle. Developers may have previously (before textrect-conservative-vert was available) worked around this problem by drawing the border of the RECTANGLE below the specified bottom of the TEXTRECTANGLE.

This parameter, textrect-conservative-vert, provides a cleaner approach, assuming you don't want to switch all your text alignment to use TA_BOTTOM. It effectively moves the threshold point (used to decide whether another line will fit in the rectangle) up by the current vertical line spacing. This way, you can use the same coordinates for the TEXTRECTANGLE as for the RECTANGLE.

textrect-nowrap

This parameter allows you to disable wrap within TEXTRECTANGLE (syntax one). It may be useful in situations where you have multiple lines of text that already have hard line breaks and you would prefer to truncate the lines that are too long rather than cause a wrap and end up losing some of the text at the bottom. Note that this effect has long been available with TEXTRECTANGLE syntax two, simply by omitting the TRF_WORDBREAK option.

UTF8

When specified, the remainder of the file is considered to be in UTF8 encoding, which is compatible with 7 bit ASCII characters (0-127), but interprets bytes with the 8th bit set as a lead-in to a multi-byte sequence supporting the entire range of UNICODE code points. When printing files which start with the special 3 byte sequence EF EB BF, UTF8 mode is activated automatically. This is a semi-standard protocol for identifying UTF8-encoded text files, favored by Microsoft.

Example

//SETOPTION,EMBEDDED-ENTITY-REFERENCES

Symbol: &#x03a9; Code: \

//SETOPTION,EMBEDDED-ENTITY-REFERENCES,0

&#x03a9;

Comments

The booleans (default = TRUE) can be:

FALSE: FALSE, F, 0, N, OFF

TRUE: TRUE, T, 1, Y, ON (or anything else)

Since the options are all initialized to FALSE at the start of each print request, you must specify the enable the options of interest at the start of each print file. But since the default Boolean switch is TRUE, you generally don't need to specify that argument, except when you need to turn an option back off again, after having first enabled it earlier in same file.

Note: All parts of this directive are case insensitive.

History

2012 November, A-Shell 6.0.1365: Add UTF8

2012 October, A-Shell 6.0.1261: Add textrect-conservative-vert and textrect-nowrap

2012 August, A-Shell 6.0.1154: Add no-auto-page-breaks parameter

2012 June, A-Shell 6.0.1152: SETOPTION added to A-Shell


SETPENEX

//SETPENEX, style, thickness {r, g, b}

SETPENEX selects a "pen" (line thickness and style) for subsequent line drawing operations—e.g. LINETO and RECTANGLE. SETPENEX is an EXtended version of, and supersedes, the original SETPEN.

Parameters

style

Select one from each of the sections shown in the table. Also see Comments, below.

Symbol | Value | Description
PS_SOLID | 0 | Solid pen
PS_DASH | 1 | -------
PS_DOT | 2 | .......
PS_DASHDOT | 3 | _._._.
PS_DASHDOTDOT | 4 | _.._.._
PS_ENDCAP_ROUND | 0 | Round endcaps (default)
PS_ENDCAP_SQUARE | &h0100 | Square endcaps
PS_ENDCAP_FLAT | &h0200 | Flat endcaps
PS_JOIN_ROUND | 0 | Round joins (default)
PS_JOIN_BEVEL | &h1000 | Bevel joins
PS_JOIN_MITER | &h2000 | Miter joins

thickness

Thickness of the pen is defined in current map mode units. (A value of zero will result in a thickness of 1 pixel.) Note that this differs from the similar function SETPEN, which interprets thickness as being in pixel units.

r, g, b

The r, g, and b parameters are optional, but if specified, must all be specified. See the SETTEXTCOLOR directive for notes.

SETPENEX was added to A-Shell in Build 931 of 22 May 05.

Comments

A sample print file, SETPEN.TXT is available in the EXLIB _EXLIB to illustrate the new options. Note, however, that the join options do not appear to have any effect (or at least I don't know what they do.) They have been implemented and documented to match the underlying Windows ExtCreatePen() function, but it isn't clear what they are for.

The endcap options are quite useful though. By default, line segments have rounded endcaps consisting of a semicircle with diameter equal to the width of the line, making them more significant as the line thickness increases. The square option makes the endcaps square, which is equivalent to extending the lines by half their thickness, on each end. This may seem illogical at first (i.e. why not just ask for a longer line?) but is actually useful for making complete corners. If you don't want any endcaps, then use the flat option (which is probably what you were expecting in the first place).

Subtopics

SETPEN


SETPEN

Note: SETPEN has been succeeded by SETPENEX, which offers a greater range of options. Although SETPEN is supported, SETPENEX should be used unless there is a good reason for not doing so.

//SETPEN, style, thickness {,r, g, b}

SETPEN selects a "pen" (line thickness and style) for subsequent line drawing operations—e.g. LINETO and RECTANGLE.

Parameters

style

Select one of the following:

Value | Description
0 | Solid (default)
1 | Dash (only valid when pen thickness is 1)
2 | Dot (only valid when pen thickness is 1)
3 | Dash-Dot (only valid when pen thickness is 1)
4 | Dash-Dot-Dot (only valid when pen thickness is 1)
5 | NULL
6 | Inside frame

thickness

Thickness of the pen in pixels. (0 is treated the same as 1.) Note that previous versions of this documentation incorrectly indicated that the units for thickness were based on the current map mode. See SETPENEX for an enhanced version of SETPEN which does use the current map mode units.

r, g, b

The r, g, and b parameters are optional, but if specified, must all be specified. See the SETTEXTCOLOR directive for notes.


SETTEXTALIGN

//SETTEXTALIGN, flags

SETTEXTALIGN determines way text is aligned within the character cell grid. The default is the upper left corner of the character cell, meaning that //TEXTOUT,x,y text will print the text below and to the right of the position x,y. Add together the applicable options, one for each coordinate, from the table below. See the topic Parameters: Symbols vs. Values if you have questions about which to use.

Symbol | Value | Description
Horizontal Alignment
TA_LEFT | 0 | x coordinate aligns with left side of character cell. (Default)
TA_RIGHT | 2 | x coordinate aligns with right side of character cell.
TA_CENTER | 6 | x coordinate aligns with center of character cell.
Vertical Alignment
TA_TOP | 0 | y coordinate aligns with top of character cell. (Default)
TA_BOTTOM | 8 | y coordinate aligns with bottom of character cell.
TA_BASELINE | 24 | y coordinate aligns with character baseline.


SETTEXTCOLOR

//SETTEXTCOLOR, r, g, b

SETTEXTCOLOR sets the color to be used for subsequent text output.

The r (red), g (green), b (blue) values may each range from 0-255. You can use these to specify virtually any color, regardless of whether your printer actually supports it. Some common color values are shown below.

R,G,B | Color | R,G,B | Color
0,0,0 | Black | 192,192,192 | Gray
255,255,255 | White | 255,0,255 | Magenta (intense)
255,0,0 | Red (intense) | 183,231,58 | Lime green

Comments

To figure out the values for special colors, you can use the Settings | Colors dialog in A-Shell. Click on a color, then select the Define Custom Color button and you will see a dialog which allows you to select any color from a three-dimensional grid. The third dimension is a slide bar on the right side that controls lightness and darkness. As you move the color cursor around, you will see the color values changing. Don't confuse them with the Hue, Saturation, and Luminescence values, which are part of an alternative system of defining colors.

Note that when one color (e.g. text) is written on top of another, the effect is not additive. Rather, the last written color replaces the underlying one(s). So for example, you can write white text on top of a dark background—e.g., image, solid rectangle, etc.—by outputting the background first, then the text. The following set of directives illustrates this by outputting two white text strings inside a black circle.

//;Print multiple independent white strings in one black circle

//SETMAPMODE,LOENGLISH

//ELLIPSE,100,100,200,200,BLACK_BRUSH

//SETTEXTCOLOR,255,255,255

//SETFONT,200,ARIAL,DEFAULT_PITCH,ANSI_CHARSET,FW_LIGHT

//TEXTCENTER,100,120,200,135,"US"

//SETFONT,320,ARIAL,DEFAULT_PITCH,ANSI_CHARSET,FW_HEAVY

//TEXTCENTER,100,145,200,175,"9.5"

See this A-Shell forum link for an image of the results produced by this script.


SETVMI

Updated May 2009

//SETVMI, #

SETVMI sets vertical line spacing, where # is the desired number of units (must be an integer) in the current map mode to set the "Vertical Motion Increment" to—i.e., vertical line spacing. This can be useful when filling in pre-designed forms that require a certain uniform line spacing that isn't quite what you would otherwise get from setting the LPP value in the printer init file or by setting a particular font and then using RESETLPP.

Note that if you want 6 lines per inch, to be precise, you may need to first switch to a the TWIPS mapmode, since its units per inch can be evenly divided by 6. For example:

//SETMAPMODE,TWIPS

//; set 6 lines per inch (1440/240 = 6)

//SETVMI,240

You can then switch back to another map mode, but that defeats the purpose, since the units will be converted and rounded down. So converting to LOENGLISH, for example, would give you the equivalent of //SETVMI,16. (In that case, you might have done better by just setting //SETVMI,17).

Update Note: A-Shell build 1149 of 16 May 09

GDI printing bug fix/refinement: SETVMI vertical spacing is now interpolated to fractional pixels, rather than being rounded to the nearest pixel. This corrects a problem where, depending on the VMI factor and resolution, you might have ended up with vertical spacing that was off by a fraction of a pixel. That doesn't sound like much, but by the time you get to the bottom of a page (60+ lines) a half pixel error multiplies to 30 pixels, which might be as much as an entire line. This problem typically showed up when switching between a laser printer (at 600 or 1200 DPI) and a PDF or FAX device at 100-300 DPI. And even then, it would generally have gone unnoticed unless you were using a mixture of GDI directives to draw boxes (which wouldn't have been subject to a per-line error accumulation) and regular print lines to fill them in.

COMPATIBILITY WARNING: Existing printouts which used SETVMI to set the vertical spacing necessary for print lines to line up with boxes drawn with GDI primitives may be affected by this (generally in a way that improves the alignment, unless you happened to have relied on the accumulated rounding error without realizing it).

See this A-Shell Forum thread for a more detailed discussion.


TEXTCENTER

Updated December 2013; see History

//TEXTCENTER, left, top, right, bottom, text

TEXTCENTER outputs a line of text, positioning it in the center of the specified rectangular coordinates. TEXTCENTER also supports embedded entity references.

Parameters

Left, top, right, bottom

Specify the respective sides of the bounding rectangle, in the current mapping units. Note that if the rectangle has no height (bottom >= top) then the text is vertically positioned based on the top parameter and the current SETTEXTALIGN setting. Otherwise, it is not affected by SETTEXTALIGN.

text

A string of text to output, up to a maximum of 512 characters (after expansion of any variables). TEXTCENTER does not require quoting of the text argument if it contains commas, although quoting is allowed and recommended.

See TEXTRECTANGLE for a more powerful variation of outputting text within a rectangular area.

History

2013 December, A-Shell 1370: An unmatched leading quote is now treated as a literal character. Previously it was stripped.

2012 November, A-Shell 6.0.1263: TEXTCENTER now supports embedded entity references; previously these were only processed by TEXTOUT and for raw text.


TEXTINDENT

//TEXTINDENT,x,y,text

//TEXTINDENT

TEXTINDENT is a variation of TEXTOUT designed for outputting multiple lines of text at a particular indent.

The first form of the command acts exactly like TEXTOUT except:

• it establishes an indent value of x, so that subsequent lines output without using TEXTOUT will retain the same indent.

• it sets the internal printer 'cursor' to the specified x,y position so that subsequent lines (output without any explicit positioning) will appear in the expected place.

• you can set x and/or y to -1 to refer to the current x and/or y position (useful when you don't know the current position). Note that for the x position, you might need to use the technique of ending the previous output with a backslash ("\") to hold the position, for example:

//TextOut,100,100,Our indented text starts here---> \

//TextIndent,-1,100,[Start Indented Text]

[2nd line of indented text]

//TextIndent

The second form (without any arguments) disables the indent, restoring the original margin.

This command is useful when outputting a multiline block of text, such as you would get from INFLD multiline mode or INMEMO. For example, assuming that we have retrieved the multiline text into a variable MEMO$, you might use the following code:

PRINT #CH, "//TEXTINDENT,";XPOS;",";YPOS;",";MEMO$

PRINT #CH, "//TEXTINDENT" ! turn indent off

Note that because the MEMO$ variable contains embedded CRLF terminators, in the printfile it would look something like the this:

//TEXTINDENT,150,300,This is the first line of the memo

This is the second line of the memo

This is the third line of the memo

//TEXTINDENT

Also note that the vertical spacing for the subsequent lines (second and third lines in the example immediately above) is determined based on the last established font, and is the same as what you would get when outputting text without using TEXTOUT.

Although in general it is necessary to quote arguments that contain embedded commas, neither TEXTINDENT nor TEXTOUT require it. This is particularly useful when outputting a multi-line string directly from some data source like INMEMO or a multi-line INFLD.


TEXTOUT

Updated December 2013; see History

//TEXTOUT, x, y, text

TEXTOUT outputs a line of text starting at the specified position. Note that any text lines in the printout which are not GDI commands (i.e. don’t start with //) are essentially handled the same as TEXTOUT commands except that the starting position is calculated to be the current position. TEXTOUT, however does not update the internal cursor and thus does not affect the position of subsequent text operations. text does not require quotes, even if it includes commas. Also see SETTEXTALIGN.

Parameter | Description
x | Starting horizontal position, using the current mapping units. Note that -1 may be used to specify the current position; this can be useful when you don't know the position.
y | Starting vertical position, using the current mapping units. Note that the position marks the upper right corner of the cell in which the first character is printed. This is usually a few pixels above the tops of the letters. Also note that -1 may be used to specify the current position; this can be useful when you don't know the position.
text | A string of text to output, up to a maximum of 512 characters (after expansion of any variables). It is not necessary to quote this argument, even if it contains embedded commas. See explanatory note under TEXTINDENT.

For information on printing special characters and symbols, see Printing Special Symbols.

History

2013 December, A-Shell 1370: An unmatched leading quote is now treated as a literal character. Previously it was stripped.


TEXTRIGHT

//TEXTRIGHT, x, y, text

The logic is the same as for TEXTOUT, except that the specified xy position marks the right edge of the output rather than the left edge. Note that the vertical position with respect to the reference point is still determined by the SETTEXTALIGN options. As with TEXTOUT, TEXTRIGHT does not require that the text argument be quoted if it includes commas..


TEXTRECTANGLE

Updated June 2014; see History

Syntax One

//TEXTRECTANGLE, left, top, right, bottom

bla bla bla bla bla bla bla bling

bla bla bla bla bla bla

//TEXTRECTANGLE

TEXTRECTANGLE is similar to the TEXTINDENT command, both in what it is used for and also in the fact that it consists of a starting and ending command (the ending command has no arguments), with any number of lines of text in between the two.

TEXTRECTANGLE formats the text to fit within the rectangular coordinates provided, applying word wrap to the lines as needed. Note that any existing CRLF line terminators will be respected; in the example above, the word "bling" will mark the end of a line, no matter how the rest of it formats.

If the text does not all fit in the rectangle, the last word will be printed with an ellipsis (...) following it. See MX_GDICALC for information on calculating in advance how much text will fit.

TEXTRECTANGLE supports rotated multi-line text, with autowrap. Support is limited; it doesn't clip to the rectangle if there are too many lines to fit.

TEXTRECTANGLE also supports embedded entity references. Previously these were only processed by TEXTOUT and for raw text.

Some text rotation options are also supported; see History, below.

See the EXLIB program MMOGDI for an example.

Syntax Two

//TEXTRECTANGLE, left, top, right, bottom, flags, text

This variation (identified by the six parameters) is both simpler to use than the traditional multi-part TEXTRECTANGLE sequence, and offers some additional features such as multi-line horizontal and vertical centering.

flags may be any sensible combination of the following:

Flag | Value | Meaning
TRF_TOP | &h00000000 | top justification
TRF_LEFT | &h00000000 | left justification
TRF_HCENTER | &h00000001 | horizontal centering
TRF_RIGHT | &h00000002 | right justification
TRF_VCENTER | &h00000004 | vertical centering
TRF_BOTTOM | &h00000008 | bottom justification
TRF_WORDBREAK | &h00000010 | wrap the text onto multiple lines
TRF_SINGLELINE | &h00000020 | output text as a single line
TRF_EXPANDTABS | &h00000040 | expand tabs (8 spaces each)
TRF_NOCLIP | &h00000100 | no clipping
TRF_EXTERNALLEADING | &h00000200 | incl. ext. leading in spacing
TRF_CALCRECT | &h00000400 | calc only (use with MX_GDICALC)
TRF_PATH_ELLIPSIS | &h00004000 | path ellipsis
TRF_END_ELLIPSIS | &h00008000 | end ellipsis
TRF_WORD_ELLIPSIS | &h00040000 | word ellipsis

As with other GDI printer directives, the flags can be specified as a decimal value, hex value, or using the symbol names.

text may be any string of up to 16384 characters. It may include "^M" symbol(s) to indicate hard CRLF(s).

History

2014 June, A-Shell 1387: Single-line TEXTRECTANGLE now supports character wrap in the 90, 180, -90 and -180 rotations. Previously only word wrap was supported and if any lines were too long, the output was way out of position.

2013 December, A-Shell 1370: An unmatched leading quote is now treated as a literal character. Previously it was stripped.

2012 November, A-Shell 6.0.1263: TEXTRECTANGLE now supports rotated multi-line text, with autowrap; that support is limited, it doesn't clip to the rectangle if there are too many lines to fit. TEXTRECTANGLE also supports embedded entity references; previously these were only processed by TEXTOUT and for raw text.

2012 October, A-Shell 6.0.1261:

• TEXTRECTANGLE (syntax one, with multiple lines) now adds an ellipsis "..." to the right of the last line in the case where the last visible line is not truncated, but there are additional lines of text (with hard line breaks) that did not fit into the box.

• New SETOPTION flag "TEXTRECT-CONSERVATIVE-VERT" improves vertical spacing control.

• New SETOPTION flag "TEXTRECT-NOWRAP" disables wrap within TEXTRECTANGLE. This may be useful in situations where you have multiple lines of text that already have hard line breaks and and you would prefer to truncate the lines that are too long rather than cause a wrap and end up losing some of the text at the bottom.

2011 October, A-Shell 5.1.1235: TEXTRECTANGLE now supports limited rotation options (TRF_SINGLELINE with 90, -90, or 180 degree rotation only). Note that the rectangle itself is not rotated, nor is the interpretation of the alignment options (TRF_LEFT, TRF_TOP, etc. remain relative to the rectangle in the standard orientation of the page. Only the text is rotated. See the new sample GDI text file, TEXTRECTR.TXT[908,37] for examples.

2011 August, A-Shell 5.1.1230: Added Syntax Two

2007 April, A-Shell 4.9.986: Increased the maximum paragraph length supported by the TEXTRECTANGLE command to 16K from 2K. This is considerably longer than can fit on a page, which is the effective limit for what a single TEXTRECTANGLE can handle anyway. Larger paragraphs can still be analyzed by MX_GDICALC, it would inevitably break them up into rectangles (or entire pages) that were individually less than 16K (unless perhaps you used 2 point type in an effort to cram 16K of unreadable text on a page).

An error message box will be displayed if any single line of the printfile exceeds the 16K limit.

Note that neither MX_GDICALC nor TEXTRECTANGLE support the line continuation character (\) so unless you want to insert your own line breaks, the entire paragraph has to be output as a single line (with the only CRLF being at the end).

2005 May, A-Shell 4.9.986: Routine added to A-Shell


XMDATA, XMFIELDS

Reviewed May 2008

//XMFIELDS, fldnam1|fldnam2|...|fldnamN

//XMDATA, data1|data2|...|dataN

//XTEXT, left, top, right, bottom, fspec{, pageoffset}

These commands facilitate mail merge with XTEXT.

Mail merge is supported only by XTEXT documents in RTF or SSE format. To create the template, edit the document and insert field names by highlighting them and pressing Control-D to give them the double underline style. To perform the merge/print operation, insert one or more XMFIELDS statements (to define the field names), one or more XMDATA statements (to define the field replacement data), and one or more XTEXT directives (one for each page or rectangle of output). You will also need at least a SETMAPMODE statement to define the measurement units which are required by the XTEXT statement, plus any other //GDI directives that you want (i.e. to combine application-generated output with the mail merge output).

Syntax:

The individual field names and data items must be delimited by the vertical bar (|). You can use multiple XMFIELDS and XMDATA statements, if you have a lot of fields (or long data). The important thing is that the Nth data item matches up with the Nth field name. (So in the example above, all occurrences of "fldnamN" in the document would be replaced by "dataN".

XMFIELDS and XMDATA both require a single comma after the name of the directive, but after that, the fields are delimited with |. Fields may contain commas and quotes but they are treated like any other character.

The optional pageoffset parameter is used to specify the starting position within the fspec document for the merge. Use negative numbers for page numbers, positive for byte offsets. (-1 = page 1, -2 = page 2, etc.)

Note that the XMFIELDS and XMDATA definitions remain live for the duration of the spool operation (i.e. the processing of the text file containing those directives, not the RTF documents reference by XTEXT). Also note that the XTEXT statement used for the mail merge operation is identical to that previously documented for printing regular XTEXT text. (The only difference between XTEXT mail merge/print and regular XTEXT printing is whether there are fields defined which match up with fields in the document. So you could, for example, define a set of 30 fields and corresponding data items, then issue several XTEXT commands which may or may not reference any of those fields.)

Example:

//SETMAPMODE,LOENGLISH

//XMFIELDS,Name|Address|City

//XMDATA,Jack|123 Main St.|Woodland Hills

//XTEXT,50,50,800,1000,mydoc.rtf,-1

^L

//XTEXT,50,50,800,1000,mydoc.rtf,-2

In the above example, we are printing a 2 page mail merge document. Note the need for the chr(12) (appearing as "^L") to mark the page break.

History

2008 May, A-Shell 5.1.1111: Added to GDI Printing Directives.


XOFFSET, YOFFSET

Updated May 2012

//XOFFSET, ###

//YOFFSET, ###

These commands effect minor horizontal and vertical adjustments to the overall positioning of everything on the page except images. The units are twips (1440 to the inch), with positive values shifting the output down and to the right, negative up and to the left.

Because these commands do not affect images (e.g. IMAGE), they are most useful for adjusting text relative to a background image being used as a form. They are also the easiest way to shift an entire document (one without images), perhaps to line up better with a pre-printed form. TMARGIN and LMARGIN, which may seem similar, are actually very limited for that purpose, given their coarseness, side effects, and the fact that they have no effect on objects explicitly positioned with GDI directives.

XOFFSET and YOFFSET are among the operators that may be used both as printer init file commands and as GDI printing directives. However, since the kinds of benefits provided by ?OFFSET tend to be document-specific rather than printer-specific, it makes more sense to use them as GDI printing directives than as init file commands.

See also, and compare to, XORIGIN/YORIGIN, which are usually preferable.

Note that when used in conjunction with XORIGIN and YORIGIN (which see), the effect is additive. This might make sense if you used XORIGIN and YORIGIN in all your printer init files to standardize the origin across all your printers, and then found that you need to shift the contents of a particular report, or if you needed to shift the text relative to the images.

Note also that XOFFSET and YOFFSET can be used more than once. This is useful for repeating a printing pattern with a vertical and/or horizontal offset.

History

2012 January, A-Shell 6.0.1248: Added ability to use commands more than once.

2011 January, A-Shell 6.0.1202: Added to GDI Printing Directives.


XORIGIN, YORIGIN

Updated December 2011

//XORIGIN, ###

//YORIGIN, ###

These commands define the minimum offset, in twips, from the top left physical corner of the paper to the 0,0 print position.

A-Shell and APEX will operate on the LARGER of the (a) XORIGIN,YORIGIN values and (b) the physical margin as defined by the printer driver. So in other words, if you set them each to 360, you should get at least 1/4" top/left margin, even on printers (like some image printers, PDF printers, and even APEX itself) that don't have any built-in physical margin limitation. This can be very useful in reducing the alignment fluctuations between different printer models caused by differing hardware paper margins.

While similar to the XOFFSET/YOFFSET commands, these differ in two important ways: First, they affect everything on the page, including images. Second, they interact with the physical margin of the printer in such a way as to eliminate the minor differences in physical margins between printers, thus improving device independence when precise positioning on the page is important. To fully achieve that benefit, you should set the XORIGIN and YORIGIN values to be at least as large as the largest physical margin on any printer you expect to print to, because the effective (0,0) point will be set to the larger of the physical margin and the XORIGIN/YORIGIN specification. In most cases, 400 twips (slightly more than 1/4") should be sufficient.

See the forum discussion Generating Forms on Demand for a look at how the XORIGIN, YORIGIN, XOFFSET and YOFFSET commands help with alignment and printer independence.

XORIGIN and YORIGIN are among the printer commands that may be used both in the printer init file and in reports themselves as GDI printing directives. However, since the benefits of standardizing the origin point are probably not specific to a single document or even a single printer, it generally makes more sense to use these commands in the printer init file(s).

These directives must appear before any commands or text that generate printable output. As mentioned above, these directives have a Printer Init File Equivalent.

History

2012 June, A-Shell 6.0.1253: Changed "these directives must appear in first eight lines" to "...before any printable output."

2011 January, A-Shell 6.0.1202: Added to GDI Printing Directives.


XTEXT

Updated May 2008

//XTEXT, left, top, right, bottom, fspec {, offset}

XTEXT permits printing a text or RTF file via XTEXT into a specified rectangle.

left, top, right, bottom

define the printing boundaries, using the current map mode.

fspec

file to print; must be a plain text or RTF file.

offset (default 0)

starting character offset within the file where printing will begin. This is mainly of use if you have to split the output into multiple XTEXT rectangles.

The output will be wrapped, if necessary, to fit within the left and right boundaries of the rectangular area, and will be clipped if it goes beyond the bottom limit. See MX_GDICALC for a method of determining in advance how much of the file will fit within the area.

XTEXT currently works only in portrait mode.

File Locations

The GDI print commands IMAGE, XTEXT, and METAFILE will locate the specified file in the same directory as the printfile if it fails to find it in the directory specified in the //GDI directive or in the local cache. This is mainly a convenience when printing from another directory. For example, if a printfile BAS:TEST.PRT contains //IMAGE,TEST.JPG,... and you tried to print it from another directory using PRINT BAS:TEST.PRT, versions of A-Shell prior to 995.3 would have failed to find the image TEST.JPG in the BAS: directory, because you weren't logged there. It also comes in handy when moving print files and their associated images to another location (such as with ASHLPD), since now you can combine all the associated files in an arbitrary directory.

Beginning with A-Shell 1111 of 3 May 08, XTEXT, IMAGE, and METAFILE will now look for the file in the same directory as the printfile itself, if not found at the location specified, even when the location specified is a UNIX path. This was previously true, since 5.0.999, but only when the original spec was a Windows path. The new logic is mainly of use in ASHLPD or other environments where you generate the GDI printfile under UNIX and then transfer it to Windows.


Introduction to (-10,x) Functions

A-Shell supports a series of Tab(-10,x) functions to access certain extended Windows features. These functions apply not only to A-Shell Windows, but also to A-Shell on all other platforms as long as ATE is being used as the terminal emulator. Note that many of the functions have higher-level XCALL wrappers (typically using MIAMEX.SBR or AUI.SBR), which in most cases are preferable, since the wrapper automatically decides whether to execute the command on the server or forward to the client, and also handles the complications of retrieving a response via the keyboard channel. Otherwise, for functions that return a response, the caller has to either use an INPUT statement or the MX_AGWRAPPER function. The main advantage of using the Tab(-10,x) functions directly is that they don’t require A-Shell support on the server side, and thus could be used by nearly any operating system.

The Tab(-10,x) command is equivalent to the raw byte sequence <ESC>GUI<x>.

Also see ZTERM Escape Sequences in the appendix.

See the next topic, TAB(-10,x) Function Listing, for a table containing a list of functions, brief descriptions, and links to detailed descriptions.

Usage Notes

The general format of the commands is:

? tab(-10, x); <arg1> <delim> <arg2> <delim>. . .<argn>; chr(127);

where "x" may be either a number ("23") or a symbol ("AG_WINEXEC"). The AG_xxx symbols were introduced in November 2006 so as to make A-Shell code more readily understandable. The following two statements, one using the traditional number and the other using the symbol, are equivalent:

? tab(-10,23); cmdlin; chr(127);

? tab(-10,AG_WINEXEC); cmdlin; chr(127);

While not strictly mandatory, it is highly recommended that all Tab(-10,x) statements be terminated with a semicolon (as in the examples above). Otherwise, a CRLF will be output (as it is for any PRINT or ? statement which does not end with a semicolon); in the case of Tab(-10,x) commands, that terminating CRLF would be entirely spurious and might cause unwanted side effects on your screen (like scrolling).

The <delim> may vary from one command to the next, but it usually a dash ("-"), tilde ("~"), or comma. Any argument that itself contains an embedded delimiter character must be quoted. It is important to note that all cases, the literal delimiters must appear in the output string, as the entire string is parsed by the terminal driver (or ATE client) rather than by the compiler. Also note that all Tab(-10,x) commands must be terminated with a chr(127) (which cannot appear in the list of arguments). For example, the AG_SAVERES command takes two arguments and uses a comma for a delimiter. The following would be legal:

? TAB(-10,AG_SAVERES);CMD$;",";ID; chr(127);

? TAB(-10,AG_SAVERES);"S,5";chr(127);

This, however, is not legal syntax:

? TAB(-10,AG_SAVERES);CMD$,ID;chr(127);

The problem with the last example is that the comma separating the two arguments is interpreted by the compiler and runtime system, but not actually output to the terminal device.

If the command returns a response, typically you will need some kind of input statement following the Tab(-10,x) statement to retrieve the response. For example:

? TAB(-10,AG_GETENV); "MIAME"; chr(127);

INPUT LINE "",ENV$

INPUT LINE (as shown above) is preferable to INPUT, since the returned text may contain commas (which would act as delimiters). In the case of commands that return a single byte response (typically chr(13) for "ok" and chr(3) for "error", following the ZTERM Escape Sequences protocol), keep in mind that the chr(3) (aka "Control C") will abort your program if you don't take steps to trap it. Typically in these cases, it is better to disable Control-C processing (see CCOFF.SBR) and use a byte-oriented input routine like ACCEPN.

The operation of inputting the response can be problematic, due to the possibility of the operator managing to manually force keyboard characters into the input stream ahead of the command input. Typically, the AG_xxx function will lock the keyboard to prevent this, but that can be manually unlocked by the user. And there is also the possibility of type ahead (characters already typed but not yet received by the application) getting mixed in. In addition, you may not want the returned characters to appear on the screen (for which you can set NOECHO mode, or use an input routine that doesn’t echo, like ACCEPN). To reduce or even eliminate these complications and simplify your application coding, we recommend using the XCALL equivalent of the AG_xxx function (when available, as noted in the table above), and if there is no specific XCALL equivalent, you can use the generic MX_AGWRAPPER function to encapsulate the sending of the command and inputting of the response. The XCALL wrapper generally takes care of all the issues just described.

See the sample program TCRTEX.BAS in DSK0:[7,376] for examples of the Tab(-10,x) extended TCRT commands.


TAB(-10,x) Function Listing

The following table is sorted alphabetically by symbol name. The same table sorted by value is provided after the Notes, below.

Symbol | Value | Notes | Description
AG_ATEDISCONNECT | 44 | 1 | Force immediate ATE Disconnect
AG_ATTRSUB | 68 |  | Change Underline Attribute
AG_AUTOPARENT | 87 | 3 | ? tab(-10,AG_AUTOPARENT); ctrlid; chr(127); equivalent to MX_AUTOPARENT
AG_BEVEL | 13 | 3 | Set Beveling Flags; equivalent to MX_BEVEL
AG_BROWSEFOLDER | 70 | 3,5 | Select Windows Folder; equivalent to MX_BROWSEFOLDER
AG_CHKPCNET | 74 | 3,5 | Check ATE network state; equivalent to MX_CHKPCNET
AG_CLIPBOARD | 65 | 3 | Perform Clipboard Operations; equivalent to MX_CLIPBOARD
AG_CLRINBUF | 106 | 1,3 | Clears the ATE client input buffer: ? tab (-10,AG_CLRINBUF); chr(127). Note that MX_CLRINBUF will automatically issue this command, so you would normally only use AG_CLRINBUF separately in specialized situations.
AG_CONTROL | 20 | 3,5 | Edit GUI Control
AG_DATETIME | 64 | 1,5 | Retrieve ATE Date and Time
AG_DELAYOP | 107 |  | Run Delayed Operation in Background
AG_DESIGN | 61 | 6 | Design mode operations
AG_DISCONNECTPW | 53 | 1 | Password for Disconnect
AG_EVENTWAIT | 33 | 3 | Event Wait; equivalent to AUI_EVENTWAIT
AG_EVTMSG | 57 |  | Output Debug Message
AG_FILESTATS | 31 | 3,5 | Get File Stats; equivalent to MX_FILESTATS
AG_FLASHWINDOW | 28 |  | Flash Window
AG_FTP | 22 | 1,2,5 | FTP
AG_FTPSETPW | 29 | 1,2 | Set FTP Login / Password
AG_FTPSYNC | 55 | 1,2 | Used internally with ATSYNC.LIT. Please inquire if you are interested in this function.
AG_GETENV | 45 | 4,5 | Get ATE Environment Variable
AG_GETFLAGS | 92 | 6 | ? tab(-10,AG_GETFLAGS); opcode; chr(127); Retrieves a single digit (0 or 1) followed by a CRLF, indicating if theme support is active on the client.
AG_GETOFD | 47 | 3,5 | Display Open/Save File Dialog; equivalent to MX_GETOFD
AG_GETSHELLPATH | 71 | 3,5 | Retrieve Windows Path; equivalent to MX_GETSHELLPATH
AG_HANDSHAKE | 85 | 1 | Send/receive various info with ATE client
AG_HOLDKBD | 36 | 1, 6 | Set ATE Keyboard Hold.
AG_IATIMEOUT | 79 | 1,3 | Set/Retrieve Timeout Period; equivalent to MX_IATIMEOUT
AG_IMAGE | 35 | 3 | Image Processing.
AG_ISFOREGROUND | 78 |  | Test for Foreground Status
AG_MENU | 21 | 3,5 | Edit Menu Control, invoke menu command
AG_MESSAGEBEEP | 3 |  | Beep
AG_MESSAGEBOXOK | 4 | 3,5 | Display OK / Cancel Message Box
AG_MESSAGEBOXSTD | 17 | 3,5 | Display Standard Message Dialog
AG_MINTITLE | 1 |  | Set Minimized Window Title
AG_MKDIR | 32 | 3,5 | Make Directory; equivalent to MX_MKDIR
AG_MOUSE | 100 |  | Set / Restore AutoMouse
AG_NEWPRODUCT | 6 | 6 | Allows override of certain info in About box.
AG_OPTIONS | 69 | 4,5 | Set/retrieve OPTIONS for ATE
AG_OSVER | 66 | 3 | Get OS Info
AG_PALETTE | 15 | 5 | Query colors. See Define or Query Color Palette.
AG_RAWDATA | 83 | 1 | Send raw data
AG_RELEASEKBD | 49 | 1,3 | Release ATE Keyboard Release
AG_RESETWINDOW | 16 |  | Reset Window
AG_SAVERES | 40 |  | Save / Restore Screen with ID
AG_SBRFLAGS | 102 | 4,5 | Set / Retrieve SBR Flags
AG_SENDKBD | 82 |  | Send Keyboard Characters
AG_SETCOLOR | 15 |  | Define or Query Color Palette
AG_SETCURSOR | 50 |  | Set Mouse Cursor
AG_SETENV | 77 | 3,4 | Set Environment Variable; similar to MX_SETENV but applies to client side.
AG_SHLEXEC | 24 | 3,5 | Shell Execute; equivalent to MX_SHELLEX
AG_SHORTCUT | 72 | 3,5 | Create A Shortcut; equivalent to MX_SHORTCUT
AG_SHOWFONT | 99 |  | Display font info (deprecated)
AG_SHOWWINDOW | 27 | 3 | Show Window; equivalent to MX_SHOWWINDOW
AG_SPOOLCFG | 54 | 1 | Auxiliary Port Control
AG_STATUSLINES | 34 |  | Enable / Disable Status Lines
AG_SYSCOLOR | 63 |  | Change RGB Value
AG_SYSBCLR | 26 | 3 | Associate A-Shell and Windows Colors; equivalent to MX_SYSBCLR
AG_TRACE | 76 | 4,5 | Clear/Set/Query ATE Trace Flags
AG_WALLPAPER | 39 |  | Display Wallpaper
AG_WEBCACHE | 108 |  | Get/Set WEBCACHE Options
AG_WINEXEC | 23 | 5 | Execute Windows Command Line
AG_WINPTR | 56 | 3,5 | Display printer selection dialog; equivalent to MX_WINPTR
AG_WINSETTINGS | 46 | 3,5 | Get / Set / Load / Save Settings; equivalent to MX_WINSETTINGS
AG_WINTITLE | 2 |  | Set Normal Window Title
AG_WRAP | 62 |  | Enable/Disable Wrap
AG_XFUNC | 25 | 5 | Call SBX as a Function (numeric)
AG_XFUNC2 | 73 |  | Call SBX as a Function (no return value)
AG_XFUNCS | 75 | 5 | Call SBX as a Function (string)

Notes

1 Applies only to ATE. It may be technically possible to use the command in non-ATE situations, but it doesn’t make much sense.

2 Requires that an FTP service be activated on the server, which uses the same root directory as A-Shell running on the server (which is rarely the case with Windows).

3 The MX_xxx or AUI_xxx equivalent is preferable, as it will be simpler to use (no need for an INPUT statement to retrieve the result) and will automatically route the command to the ATE client or handle locally on the application server, depending on the environment. Note, however, that in some cases, the MX_xxx or AUI_xxx equivalent may support an option of whether to perform the function on the server or forward it to the ATE client, whereas the AG_xxx functions are always sent to the client. See the MX_xxx / AUI_xxx documentation for details. In the case of A-Shell/Windows without ATSD, the client and server are effectively the same.

4 Similar to the MX_xxx equivalent, but always works relative to the client PC, whereas the MX_xxx equivalent always works relative to the application server. In the case of A-Shell/Windows without ATE, the two are functionally the same.

5 In lieu of using ? Tab(-10, AG_xxx) followed by some form of INPUT to retrieve the response, we recommend the use of the MX_AGWRAPPER function as a way of combining the two operations into a single XCALL (provided server is running A-Shell and the MX_AGWRAPPER function is available).

6 Used mostly or entirely for internal purposes only. Please inquire if you want more information on this function.

Table Sorted by Value

Symbol | Value | Notes | Description
AG_MINTITLE | 1 |  | Set Minimized Window Title
AG_WINTITLE | 2 |  | Set Normal Window Title
AG_MESSAGEBEEP | 3 |  | Beep
AG_MESSAGEBOXOK | 4 | 3,5 | Display OK / Cancel Message Box
AG_NEWPRODUCT | 6 | 6 | Allows override of certain info in About box.
AG_BEVEL | 13 | 3 | Set Beveling Flags; equivalent to MX_BEVEL
AG_PALETTE | 15 | 5 | Query colors. See Define or Query Color Palette.
AG_SETCOLOR | 15 |  | Define or Query Color Palette
AG_RESETWINDOW | 16 |  | Reset Window
AG_MESSAGEBOXSTD | 17 | 3,5 | Display Standard Message Dialog
AG_CONTROL | 20 | 3,5 | Edit GUI Control
AG_MENU | 21 | 3,5 | Edit Menu Control, invoke menu command
AG_FTP | 22 | 1,2,5 | FTP
AG_WINEXEC | 23 | 5 | Execute Windows Command Line
AG_SHLEXEC | 24 | 3,5 | Shell Execute; equivalent to MX_SHELLEX
AG_XFUNC | 25 | 5 | Call SBX as a Function (numeric)
AG_SYSBCLR | 26 | 3 | Associate A-Shell and Windows Colors; equivalent to MX_SYSBCLR
AG_SHOWWINDOW | 27 | 3 | Show Window; equivalent to MX_SHOWWINDOW
AG_FLASHWINDOW | 28 |  | Flash Window
AG_FTPSETPW | 29 | 1,2 | Set FTP Login / Password
AG_FILESTATS | 31 | 3,5 | Get File Stats; equivalent to MX_FILESTATS
AG_MKDIR | 32 | 3,5 | Make Directory; equivalent to MX_MKDIR
AG_EVENTWAIT | 33 | 3 | Event Wait; equivalent to AUI_EVENTWAIT
AG_STATUSLINES | 34 |  | Enable / Disable Status Lines
AG_IMAGE | 35 | 3 | Image Processing.
AG_HOLDKBD | 36 | 1, 6 | Put ATE into "keyboard hold" mode
AG_WALLPAPER | 39 |  | Display Wallpaper
AG_SAVERES | 40 |  | Save / Restore Screen with ID
AG_ATEDISCONNECT | 44 | 1 | Force immediate ATE Disconnect
AG_GETENV | 45 | 4,5 | Get ATE Environment Variable
AG_WINSETTINGS | 46 | 3,5 | Get / Set / Load / Save Settings; equivalent to MX_WINSETTINGS
AG_GETOFD | 47 | 3,5 | Display Open/Save File Dialog; equivalent to MX_GETOFD
AG_RELEASEKBD | 49 | 1,3 | Release (un-buffer) keyboard ; equivalent to MX_RELEASEKBD
AG_SETCURSOR | 50 |  | Set Mouse Cursor; same as tab(-1,160)
AG_DISCONNECTPW | 53 | 1 | Password for Disconnect
AG_SPOOLCFG | 54 | 1 | Auxiliary Port Control
AG_FTPSYNC | 55 | 1,2 | Used internally with ATSYNC.LIT. Please inquire if you are interested in this function.
AG_WINPTR | 56 | 3,5 | Display printer selection dialog; equivalent to MX_WINPTR
AG_EVTMSG | 57 |  | Output debug message
AG_DESIGN | 61 | 6 | Design mode operations
AG_WRAP | 62 |  | Enable/Disable Wrap
AG_SYSCOLOR | 63 |  | Change RGB Value
AG_DATETIME | 64 | 1,5 | Retrieve ATE Date and Time
AG_CLIPBOARD | 65 | 3 | Perform Clipboard Operations; equivalent to MX_CLIPBOARD
AG_OSVER | 66 | 3 | Get OS Info
AG_ATTRSUB | 68 |  | Change Underline Attribute
AG_OPTIONS | 69 | 4,5 | Set/retrieve OPTIONS for ATE
AG_BROWSEFOLDER | 70 | 3,5 | Select Windows Folder; equivalent to MX_BROWSEFOLDER
AG_GETSHELLPATH | 71 | 3,5 | Retrieve Windows Path; equivalent to MX_GETSHELLPATH
AG_SHORTCUT | 72 | 3,5 | Create A Shortcut; equivalent to MX_SHORTCUT
AG_XFUNC2 | 73 |  | Call SBX as a Function (no return value)
AG_CHKPCNET | 74 | 3,5 | Check ATE network state; equivalent to MX_CHKPCNET
AG_XFUNCS | 75 | 5 | Call SBX as a Function (string)
AG_TRACE | 76 | 4,5 | Clear/Set/Query ATE Trace Flags
AG_SETENV | 77 | 3,4 | Set Environment Variable; equivalent to MX_SETENV
AG_ISFOREGROUND | 78 |  | Test for Foreground Status
AG_IATIMEOUT | 79 | 1,3 | Set/Retrieve Timeout Period; equivalent to MX_IATIMEOUT
AG_SENDKBD | 82 |  | Send Keyboard Characters
AG_RAWDATA | 83 | 1 | Send raw data
AG_HANDSHAKE | 85 | 1 | Send/receive various info with ATE client
AG_AUTOPARENT | 87 | 3 | ? tab(-10,AG_AUTOPARENT); ctrlid; chr(127); equivalent to MX_AUTOPARENT
AG_GETFLAGS | 92 | 6 | ? tab(-10,AG_GETFLAGS); opcode; chr(127); Retrieves a single digit (0 or 1) followed by a CRLF, indicating if theme support is active on the client.
AG_SHOWFONT | 99 |  | Display font info (deprecated)
AG_CLRINBUF | 106 |  | Clears the ATE client input buffer: ? tab (-10,AG_CLRINBUF); chr(127). Note that MX_CLRINBUF will automatically issue this command, so you would normally only use AG_CLRINBUF separately in specialized situations.
AG_DELAYOP | 107 |  | Run Delayed Operation in Background


Play Sound File

Added May 2013

? tab(-10, AG_PLAYSOUND); fspec, flags {rtnsts}; chr(127);

AG_PLAYSOUND (105) forces the ATE client to play a sound file.

fspec and flags are the same as for the MX_PLAYSOUND. rtnsts may be set to non-zero if you want to get the return status in the keyboard buffer. Otherwise (if 0 or omitted), there is no response.

Note that fspec must be a PC native filespec, and that AG_PLAYSOUND supports the standard image file search path and %env% variables.

History

2013 Novemer, A-Shell 6.1.1367: Command added to A-Shell


Set Minimized Window Title

? tab(-10, AG_MINTITLE); mintitle; chr(127);

AG_MINTITLE (1) changes the title that is displayed on the task bar when the application is minimized. Also see ZTERM Escape Sequences in the Appendix.

Parameters

mintitle

Title string.

Example

? TAB(-10,AG_MINTITLE);"Killer App";chr(127);


Set Normal Window Title

? tab(-10, AG_WINTITLE); title; chr(127);

AG_WINTITLE (2) changes the title that displays on the title bar of the A-Shell window. Also see ZTERM Escape Sequences in the Appendix and SET.LIT for other ways of setting the title.

Parameters

title

Title string.

Example

? TAB(-10,AG_WINTITLE);"Once Upon an App";chr(127);


Display OK / Cancel Message Box

? tab(-10, AG_MESSAGEBOXOK); btnflag; msg; tilde; title; chr(127);

AG_MESSAGEBOXOK (4) displays a message in a dialog box that is positioned along the bottom couple of lines of the window. This is meant to approximate the GUI version of MESAG.SBR. For example:

Parameters

btnflag

A single character which must be a space (ASCII 32) to display just an OK button in the dialog, or an exclamation point (ASCII 33) to display both OK and CANCEL buttons

msg

A text string containing the message to display in the body of the dialog.

title

A text string to be displayed on the title bar of the dialog.

Example

? TAB(-10,AG_MESSAGEBOXOK);"!Make sure you have a backup before posting!"; ~Read This!";chr(127);

Notes

The dialog returns a single byte to the keyboard buffer indicating which button was pushed: ESCAPE (ASCII 27) for the Cancel button and RETURN (ASCII 13) for the OK button.

See Also

• AG_MESSAGEBOXOK,

• MSGBOX.SBX

• EVTMSG.SBX and XTRMSG.SBX in the SOSLIB


Set Beveling Flags

? tab(-10, AG_BEVEL); str(bevelflags); chr(127);

AG_BEVEL (13) provides a way to set the values that are on the Settings | Beveling dialog.

Parameters

bevelflags

Typically 255 to turn on beveling and replace all the standard line drawing characters with 3D versions. 0 deactivates beveling.

Example

? TAB(-10,AG_BEVEL);"255";chr(127); ! turn beveling on

? TAB(-10,AG_BEVEL);str(0);chr(127); ! turn beveling off

Notes

Note that beveling works best with a gray or pastel background; see AG_PALETTE for details on defining colors from within the program. Also note that you can turn on beveling via the Settings | Beveling menu, and then save it permanently in the settings file. For more information, see Beveling.


Define or Query Color Palette

? tab(-10, AG_SETCOLOR); ctype, cnum, r, g, b; chr(127);

? tab(-10, AG_PALETTE); ctype, cnum {,r,g,b}; chr(127);

AG_SETCOLOR (15) provides a way to programmatically modify the color that is associated with a specific color palette entry (aka color number). For example, in the standard palette, color 2 is a rather primary intense blue. If you would rather have a more pastel blue, then you can either modify the definition of color 2 on the Display | Colors dialog, or via this command.

Beginning with A-Shell 1115 of June 2008, you may also query the RGB definitions of any of the A-Shell palette colors using the second syntax above. AG_PALETTE and AG_SETCOLOR have the same value, 15, but AG_PALETTE seems like less of a misnomer when querying rather than setting.

Parameters

ctype

1=set fg color, 2=set reduced fg color, 3=set bg color, 4=get fg color, 5=get reduced fg color, 6=get bg color

cnum

a single digit (0-7) indicating the number of the palette entry you want to query or set

r,g,b

The R, G, and B values (0-255), used when ctype <= 3.

When ctype >= 4, the command will send back into the keyboard buffer a string formatted as "R,G,B" indicating the RGB values currently defined for the specified palette entry.

Examples

! set fg color #2 to RGB(33,44,222)

? TAB(-10,AG_SETCOLOR);"1,2,33,44,222";chr(127);

! query bg color 7

? TAB(-10, AG_PALETTE);"6,7"; chr(127);

INPUT "", R, G, B

Notes

You can experiment with RGB values on the Settings | Colors dialog by clicking on one of the color buttons and then Define Custom Color.

Although you can use this method to define colors that are more like the standard Windows colors (which are more pastel than the default DOS-like palette colors), for certain logical colors, like the standard window background (gray), text font (black), and edit window background (white), perhaps a better method would be to use the Associate A-Shell and Windows Colors command or SET.LIT TERMINAL options to associate a color palette number with a particular Windows logical color. That way, the user can adjust the color settings logically in the Control Panel and the A-Shell color palette will adjust with it.

History

2008 June, A-Shell 5.1.1115: Add the ability to query the current color definition. Add support for the more standard comma delimiters, although you may continue to use dashes instead.


Reset Window

? tab(-10, AG_RESETWINDOW); chr(127);

AG_RESETWINDOW (16) resets the window to the colors, size, font, and other parameters according to the current settings file.

See the –o command line switch for details on specifying a settings file. Also see MX_SHOWWINDOW, which offers another way of doing the same thing (in addition to querying and setting various window characteristics).


Display Standard Message Dialog

? tab(-10, AG_MESSAGEBOXSTD); flag1; flag2; msg; tilde; title; chr(127);

AG_MESSAGEBOXSTD (17) displays a standard Windows message box dialog, which consists of a title bar, text message (up to 1024 characters) and a set of buttons as in the following example. Note how different versions of Windows produce different versions of the dialog, with no changes to the A-Shell code.

Note that MSGBOX.SBX provides a more convenient interface to this function, and offers the additional bonus of detecting if the environment doesn’t support GUI functions, implementing the message box in text mode via INMEMO.SBR if necessary.

Parameters

flag1

A single character whose ASCII value is 32 plus the sum of a single choice from each of the following two tables (a button choice and an icon choice):

Value | Button Option
0 | OK button
1 | OK and CANCEL buttons
2 | ABORT / RETRY / IGNORE buttons
3 | YES / NO / CANCEL buttons
4 | YES /NO buttons
5 | RETRY / CANCEL buttons

Value | Icon Option
16 | ICON: "X" (stop)
32 | ICON: "?" (question)
48 | ICON: "!" (exclamation)
64 | ICON: "i" (information)

For example, the sample message dialog above would have set the flag1 parameter to chr(32+2+48)

flag2

A single character whose ASCII value is 32 plus the sum of zero or more options from the following table:

Value | Description
1 | Default is button #2
2 | Default is button #3
4 | Dialog is task modal
8 | Dialog is system modal
64 | Add a help button

msg

A text string containing the message to display in the body of the dialog.

title

A text string to be displayed on the title bar of the dialog.

Example

! simple test of AG_MSGBOXSTD (from doc)

++include ashinc:ashell.def

MAP1 A,F

? TAB(-10,AG_MESSAGEBOXSTD);chr(32+2+48);chr(32+1+4); &

"Best man tried on the bride's ring.";chr(13); &

"Now he can't get it off.~Wedding ceremony crisis.";chr(127);

xcall ACCEPT,A ! receive response (see notes below)

END

Notes

The dialog returns a single byte to the keyboard buffer indicating which button was pushed, according to the following table:

Return Char | Description
33 | OK
34 | Cancel
35 | Abort
36 | Retry
37 | Ignore
38 | Yes
39 | No
40 | A
41 | Help

Unlike the "OK/Cancel Message Dialog (-10,4),which appears as a short but wide dialog along the bottom of the window, this one is more rectangular and appears in the middle of the screen. Also, unlike the OK/Cancel dialog which is really only suitable for single-line messages, this one can handle up to 1024 characters. You can break the lines explicitly, as in the example above, with a chr(13), or you can rely on the routine itself to break the lines as it sees fit.

Also see AG_MESSAGEBOX and MSGBOX.SBX, and, in the SOSLIB, EVTMSG.SBX and XTRMSG.SBX.


Edit GUI Control

? tab(-10, AG_CONTROL), opcode, ctlid, ctext, cstate, ctype, cmd, func, srow, scol, erow, ecol, fgc, bgc, fontattr, fontscale, fontface, tooltip, parentid, rtnflag, winclass, winstyle, winstylex, ctype2; chr(127);

AG_CONTROL (20) is the equivalent of AUI_CONTROL and MX_WINCTL. It is used internally for forwarding those functions from A-Shell/UNIX to ATE, although it also can be used directly with an application to create, delete, or perform various other operations on GUI controls.

The number of required parameters depends on the opcode; see AUI_CONTROL for details and additional information.

To output an explicit double-quote character in the middle of a field, you can "escape" it using HTML syntax, by %22 (a percent sign followed by the value of the character in hex notation). AUI_CONTROL handles this for you—yet another reason to use it instead of AG_CONTROL.

Parameters

Nearly all of the parameters correspond to those already documented for the AUI_CONTROL routine. The only exceptions are the removal of the AUI_CONTROL cstatus parameter (which is output-only and thus has no purpose in the command string sent to the client), and the addition of:

rtnflag

"1" causes the function to return a string of result information in the keyboard buffer. Otherwise there is no response.

Example

? TAB(-10,AG_CONTROL);"1,0,OK,0,";MBF'BUTTON;",%VK_xF101%,",12,5,13,10";chr(127);

? TAB(-10,AG_CONTROL);"1,,Dr A~VK_xF1001~~Dr B...";chr(127);

xcall NOECHO

input STATUS,CTLID


Edit Menu Control

? tab(-10, AG_MENU) opcode, menuid, mnutxt, mstate, mtype, cmd, func, mstatus {,dlgid}; chr(127);

? tab(-10, AG_MENU) opcode, mdfspec, mstate, mstatus {,dlgid}; chr(127);

AG_MENU (21) is the equivalent of the AUI_MENU or MX_WINMNU calls. It is used internally for forwarding those functions from A-Shell/UNIX to ATE, although it also can be used directly with an application to add or delete menu items. It also may be used to invoke built-in menu commands, using this format:

? tab(-10, AG_MENU); ID; chr(127);

Where ID is the ID value of the menu command, from the following list:

Symbol | Value | Description
IDM_ABOUT | 101 | Help..About
IDM_LOAD | 107 | File..Load Settings
IDM_SAVE | 108 | File..Save Settings
IDM_SAVEAS | 109 | File..Save Settings As
IDM_DEFAULTS | 112 | File..Default Settings
IDM_EXIT | 111 | File..Exit [216]
IDM_PRINTS | 110 | File..Print Screen [216][226]
IDM_AUTOMOUSE | 124 | Edit..AutoMouse [211]
IDM_COPY | 115 | Edit..Copy [211]
IDM_PASTE | 116 | Edit..Paste
IDM_SCHEDULE | 106 | Settings..Scheduling
IDM_BEVELING | 122 | Settings..Beveling
IDM_COLORS | 113 | Settings..Colors
IDM_FONTSYS | 123 | Settings..Font..System
IDM_FONTGUI | 132 | Settings..Font..GUI
IDM_FONTGRID | 144 | Settings..Font..Grid [211]
IDM_MISC | 130 | Settings..Misc Settings
IDM_DLGSIZING | 134 | Settings..Dialog Sizing
IDM_PVPREF | 142 | Settings..Preview Preferences [211]
IDM_KBDLOCK | 117 | Settings..Keyboard Lock

Symbol | Value | Description
IDM_ABOUT | 101 | Help..About
IDM_LOAD | 107 | File..Load Settings
IDM_SAVE | 108 | File..Save Settings
IDM_SAVEAS | 109 | File..Save Settings As
IDM_DEFAULTS | 112 | File..Default Settings
IDM_EXIT | 111 | File..Exit [216]
IDM_PRINTS | 110 | File..Print Screen [216][226]
IDM_AUTOMOUSE | 124 | Edit..AutoMouse [211]
IDM_COPY | 115 | Edit..Copy [211]
IDM_PASTE | 116 | Edit..Paste
IDM_SCHEDULE | 106 | Settings..Scheduling
IDM_BEVELING | 122 | Settings..Beveling
IDM_COLORS | 113 | Settings..Colors
IDM_FONTSYS | 123 | Settings..Font..System
IDM_FONTGUI | 132 | Settings..Font..GUI
IDM_FONTGRID | 144 | Settings..Font..Grid [211]
IDM_MISC | 130 | Settings..Misc Settings
IDM_DLGSIZING | 134 | Settings..Dialog Sizing
IDM_PVPREF | 142 | Settings..Preview Preferences [211]
IDM_KBDLOCK | 117 | Settings..Keyboard Lock

Symbol | Value | Description
IDM_ABOUT | 101 | Help..About
IDM_LOAD | 107 | File..Load Settings
IDM_SAVE | 108 | File..Save Settings
IDM_SAVEAS | 109 | File..Save Settings As
IDM_DEFAULTS | 112 | File..Default Settings
IDM_EXIT | 111 | File..Exit [216]
IDM_PRINTS | 110 | File..Print Screen [216][226]
IDM_AUTOMOUSE | 124 | Edit..AutoMouse [211]
IDM_COPY | 115 | Edit..Copy [211]
IDM_PASTE | 116 | Edit..Paste
IDM_SCHEDULE | 106 | Settings..Scheduling
IDM_BEVELING | 122 | Settings..Beveling
IDM_COLORS | 113 | Settings..Colors
IDM_FONTSYS | 123 | Settings..Font..System
IDM_FONTGUI | 132 | Settings..Font..GUI
IDM_FONTGRID | 144 | Settings..Font..Grid [211]
IDM_MISC | 130 | Settings..Misc Settings
IDM_DLGSIZING | 134 | Settings..Dialog Sizing
IDM_PVPREF | 142 | Settings..Preview Preferences [211]
IDM_KBDLOCK | 117 | Settings..Keyboard Lock


FTP

? tab(-10, AG_FTP); dirflag; hostpath; chr(126); localpath; chr(127);

AG_FTP (22) may be used on server installation of A-Shell to cause the ATE client to initiate a file transfer with the server.

Parameters

dirflag

A single character indicating the file transfer type and direction, from the following choices:

Value | Direction | Type | Feedback
0 | Host to PC | Binary | message/dialog
1 | PC to host | Binary | message/dialog
2 | Host to PC | ASCII | message/dialog
3 | PC to host | ASCII | message/dialog
A | Host to PC | Binary | silent
B | PC to host | Binary | silent
C | Host to PC | ASCII | silent
D | PC to host | ASCII | silent

Codes A though D are not ZTERM-compatible, so should only be used when you know the client is ATE. Note that with ATE, the msg/dialog is hardly noticeable (unlike with ZTERM, where it looks just like the standard interactive FTP dialog), so the silent feature isn't that much of an improvement. Still, some people prefer to have their file transfers be invisible to the user.

hostpath

Native specification for the file on the server. If sending to the server, this may specify just the directory, in which case the filename will be taken from the localpath.

localpath

Native (PC) specification of the source file. When transferring to the PC, this may be just a directory, in which case the filename is taken from hostpath.

Return value

A single byte will be placed in the keyboard buffer to indicate success (ASCII 13, aka RETURN) or failure (ASCII 3, aka Control-C).

Examples

! transfer dsk0:test.dat[100,1] on server to dsk0:test.sav[100,999] on PC

? TAB(-10,AG_FTP);"0/vm/miame/dsk0/100001/test.dat";chr(126); &

"%MIAME%\dsk0\100999\test.sav";chr(127);

xcall ACCEPN,A

! transfer dsk0:*.*[1,2] on server to TEMP directory on PC

? TAB(-10,AG_FTP);"0/vm/miame/dsk0/001002/*";chr(126);"%TEMP%;chr(127);

xcall ACCEPN,A

? transfer all files from PC "ATELOCALDIR" directory to /vm/miame/dsk0/033033

? TAB(-10,AG_FTP);"1/vm/miame/dsk0/033033";chr(126); &

"%ATELOCALDIR%\*";chr(127);

xcall ACCEPN,A

Notes

The file wildcard "*" may be used to transfer all the files in a particular directory; see the second and third examples above.

This command only works when the client is ATE. If you have a mixture of ZTERM and ATE clients, you would be better off using the ZTERM Escape Sequences, which work for both ZTERM and ATE. In either case, you are limited to transferring files between the server where the application is running, and the client workstation, using the FTP login credentials stored in the ZTERM or ATE configuration.

If you are running locally under A-Shell/Windows and want to transfer files to an arbitrary FTP server, then use FTPDLX.SBX, which allows you to specify the server IP address and login parameters. For debugging ideas, see FTP Debugging.

Note that the FTP facility described here refers to a Windows-based FTP client. In order to transfer files between the workstation and another computer, the remote end must have an FTP server that accepts connections from your workstation. If you an FTP server is not available on the computer you want to transfer files to or from, then you will have to use some other kind of file transfer method. One possibility is to implement your own protocol using TCPX.SBX. There is a working example of such a protocol, complete with interactive server and client interfaces, in the sample program TCPXFR, which is available in the EXLIB.

If you are having trouble getting FTP transfers to work, you should first verify that your client can establish an FTP connection with the server, by using some other FTP client (such as the Microsoft FTP.EXE program). If it can’t connect, the A-Shell’s FTP won’t be able to either, and if it can connect, then A-Shell’s should be able to also.

As another debugging aid, the FTP routine automatically creates a log file, SYS:FTPDLX.LOG, which contains (somewhat human readable) details about the file transfer operation. In addition, if the environment variable ASHFTPDEBUG is defined, a more detailed, lower-level log will written to %TEMP%\ftpdebug.log (or, prior to 1153.1, c:\debug.log.

Note that AG_FTP (22) uses the A-Shell subroutine FTPDLX.

History

2009 December, A-Shell 1131: You can now request that the PC file name be set to match that assigned to the last file printed via the AUXLOC: channel, by specifying a PC filespec ending in "-#." + the extension. For example,

TAB(-10,AG_FTP);"0/tmp/abcdef.dat~%abcdef-#.dat";chr(127);

This will send the file /tmp/abcdef.dat to the PC, where it will given the full spec ??????.dat, where ????? is the complete path of the last printfile captured by ATE (minus the extension). Note that the only part of the PC filespec which matters in this case was "-#.dat"; including the "abcdef-#.dat" only serves as a fallback if the version of ATE doesn't support the feature, or there was no prior printed filespec to refer to.

This trick can be useful for sending metadata files which should be associated with print files, perhaps containing routing or archiving instructions.

2007 April, A-Shell 986: FTP transfers now support more flexible wildcards. Previously, the only wildcard option was "*" to transfer all files in the source directory. Now you can separately wildcard the file name and extension, and you can include partial literals in both parts of the name. Examples:

/vm/miame/dsk0/007006/*.dat

/vm/miame/dsk0/007006/ab*

c:\vm\miame\dsk0\007006\xyz*.d*

Notes:

• The only wildcard character remains "*" (? is not supported)

• PC filespecs are not case sensitive, but HOST filespecs are.

• The actual code change is in the module FTPDLXcall.DLL 1.2.0.117, which is normally found in the same directory as ASHW32.EXE. It gets loaded on demand when transferring a file via AG_FTP or FTPDLX.SBR or the ZTERM file transfer ESCAPE sequence.


Execute Windows Command Line

? tab(-10, AG_WINEXEC); cmdlin; chr(127);

? tab(-10, AG_WINEXEC); cmdlin; "~"; workdir; chr(127);

Note: see History below for special variations of the syntax.

AG_WINEXEC (23) executes a Windows command line on the local Windows workstation or ATE client. The first syntax shown above assumes the current A-Shell or ATE working directory; the second allows you to specify a different directory.

Parameters

cmdlin

A string containing a valid Windows command line. The string may contain any of the suffix characters supported by HOSTEX.SBR to control how the command line is executed and whether we have to wait for it to complete, as summarized in this table. (Note: only one suffix option, at max, is allowed, and it must be preceded by a space.):

Suffix | Description
 | (no suffix) The process launched by the cmdlin takes the foreground and A-Shell must wait for it to exit.
& | The process is launched in minimized mode and runs independently of A-Shell (i.e. A-Shell doesn’t wait for it.)
% | The process is launched minimized, but A-Shell still waits for it to complete. This is mainly useful for quick commands where you don’t want to distract the user with its display.
$ | The process is launched in the foreground but A-Shell does not wait for it.

Return value

A single byte will be placed in the keyboard buffer to indicate success (ASCII 13, aka RETURN) or failure (ASCII 3, aka Control-C). Note that success just means that the command was successfully executed, not necessarily that the resulting process ran correctly. In the cases where A-Shell is supposed to wait for the command (no suffix or "%" suffix), the byte is not returned until the process exits.

Examples

! launch notepad to view miame.ini on PC and wait

? TAB(-10,AG_WINEXEC);"notepad.exe %MIAMEFILE%";chr(127);

xcall ACCEPN,A

! launch calculator and don't wait

? TAB(-10,AG_WINEXEC);"CALC.EXE $";chr(127);

xcall ACCEPN,A

Notes

Environment variables (known to the PC) may be embedded in the command line using the %VARNAME% syntax, as shown in the first example above.

HOSTEX.SBR provides nearly the same functionality under A-Shell/Windows, but under A-Shell/UNIX executes a UNIX command line on the server, whereas AG_WINEXEC always executes a Windows command line on the local workstation.

Also see the following topic, Shell Execute.

History

2006 October, A-Shell 4.9.969: Two new macros have been added:

TAB(-10,AG_WINEXEC);"$COPY ";src$;" ";dst$;"~";flags;chr(127);

TAB(-10,AG_WINEXEC);"$MOVE ";src$;" ";dst$;"~";flags;chr(127);

These macros provide a clean way to move or copy a file. They are both equivalent to the MX_COPYFILE function and they share the same flags (0=copy, +1=move, +2=overwrite existing destination). The only difference between $MOVE and $COPY is in how the flags argument is defaulted if not specified. Note that this is a deviation from the usual behavior where an omitted numeric argument is equivalent to an explicit zero. In this case, specifying a flags value of 0 or 2 would override $MOVE, converting it to $COPY.

2005 May, A-Shell 4.9.932: AG_WINEXEC now supports a new macro $DEL to delete a file. For example:

? TAB(-10,AG_WINEXEC);"$DEL %ATELOCALDIR%\myfile.dat";chr(127);

input "",A

This would delete the file myfile.dat from the directory specified by the environment variable ATELOCALDIR (which is set by ATE to point to its FTP Local Directory). The return code is CR for success or ^C for failure. Note that a non-existent file is treated as success, so the only error would be if the file existed but could not be deleted.

2005 April, A-Shell 4.9.926: A special symbol, "$ATE", may now be used with AG_WINEXEC to make it easier to launch another ATE session. For example:

? TAB(-10,AG_WINEXEC);"$ATE";chr(127);

? TAB(-10,AG_WINEXEC);"$ATE ";cmdlin;chr(127);

The first example above ($ATE with no other argument) launches another ATE connection to the current server using the current profile, without suspending the current connection.

The second example ($ATE following by additional arguments) launches another A-Shell/Windows session on the local ATE client and passes it the command line cmdlin. You could use this format to launch a connection to some other server, assuming you knew the profile name, for example:

? TAB(-10,AG_WINEXEC);"$ATE telnet ";CFG$;chr(127);

Since ATE connections are established with the telnet command, the above command would launch a new ATE connection using the profile CFG$. Note that by default, AG_WINEXEC suspends the current session until the child session completes. If you don't want that, you must append the special suffix characters used by HOSTEX.SBR. For example, to not suspend the current session, the above command could be amended to add " $", i.e.:

? TAB(-10,AG_WINEXEC);"$ATE telnet ";CFG$;" $";chr(127);

Or you could execute any valid A-Shell command in the child session, for example:

? TAB(-10,AG_WINEXEC);"$ATE VUE %MIAMEFILE%";chr(127);

This would launch VUE to edit ATE's copy of the miame.ini file. Or:

? TAB(-10,AG_WINEXEC);"$ATE VUE %MIAME%\ashlog.log";chr(127);

The above command would VUE ATE's log file.


Shell Execute

? tab(-10, AG_SHLEXEC); objecspec;","; action;","; parms;","; dir;","; showcmd;","; waitflag; chr(127);

AG_SHLEXEC (24) provides an interface to one of the two fundamental mechanisms for launching a new process under Windows, i.e. "Shell Execute". The other method is Execute Windows Command Line, also known as "CreateProcess" or " or "Win Exec". Shell Execute is the method used by Windows itself when you click on a file or shortcut in Explorer, or even type a command line in the Start...Run dialog, and although it supports the ability to form command lines with parameters, it is most commonly used by specifying just an object (e.g. a file, URL, folder, etc.), and letting Windows decide which application is needed to perform the default (or specified) action on the object. Windows does this based on a table of file type associations in the Registry (which you can edit by means of the File Types dialog on the Explorer Tools...Folder Options menu).

Beginning with A-Shell 1137 of 14 Feb 09: When the launch fails, A-Shell will create a SHELLEX.LOG file in the ATE SYS: account with additional details.

Parameters

objectspec

is the specification (Windows format) of the file/object to open or act on, or the URL to link to. For example, you might specify a XLS file, such as "C:\Windows\Temp\My Spreadsheet.XLS", in which case the presumed action would be to launch the spreadsheet program (e.g. Excel) to open the spreadsheet. For example, you might specify a URL, such as "http://www.microsabio.com" in which case the presumed action would be launch the browser and link to the specified web site or HTML document.

Embedded environment variables (using the %env% notation, e.g. %temp%\test.doc) are supported.

You may also specify an executable, such as "%systemroot%\system32\mspaint.exe". (Use the parms parameter for the remainder of the arguments and switches to be passed to the executable.)

A special macro, "$ASHELL" can also be used to launch another session of A-Shell using the same executable and ini file as the current session. (You can combine this with additional switches in the parms parameter to customize the action of the new session.)

Note that in the ATE environment, the objectspec will be evaluated by (and relative to) the ATE client, not the server. If the object originates on the server, you'll have to first transfer it to the ATE client before using Shell Execute on it.

action (Str)

may specify an action: open, edit, print, find, explore or runas. If omitted, the default action for that file association is performed. Typically the default action is "open", which just opens the document. Such actions are defined with the file association in the Explorer Tools...Folder Options...File Types dialog.

Note that the "runas" action invokes the request for elevation dialog. For GUI commands, this is automatic, but for console commands (e.g. regsvr32), it is not, and this would be the only way to get it to prompt the user for the elevation needed. (Otherwise the operation would just fail.) Unfortunately there is no way to programmatically supply the administrator password. If you need something like that, you may want to check out a Microsoft-sponsored utility called "PsExec".

parms (Str)

is an optional list of parameters. Typically parms is used when objectspec contains the name of an executable (e.g. "%miame%\bin\ashw32.exe"), in which combination of objectspec and parms may effectively form a complete command line.

dir (Str)

is an optional starting directory. This can generally be omitted or specified as "".

showcmd

is an optional numeric parameter specifying the way to show the window launched by the program associated with the object and action. If omitted, the default window size will be used. Note that if you do specify the parameter, a value of zero means to make the window invisible. The values are the same as for MX_SHOWWINDOW. Note that this is only a suggestion to the target application. There is no way to force it to follow your suggestion if it insists otherwise.

waitflag

Value | Description
0 | No wait. Focus will most likely remain on launched app.
1 | Wait until launched app exits before returning.
2 | Don't wait, but try to get the focus back.
&h0100 | Combine with any of the above values to return enhanced exit status. See Return Value.

Note that waiting (1) doesn't necessarily wait until the launched app exits. It only waits until the app "signals", which can mean different things for different applications. (It will wait for A-Shell).

Option 2 will now get the focus and keep getting it (if necessary) over a period of 4 seconds, in order to deal with difficult apps (like image viewers) that may take a couple of seconds to launch, after which they set the focus on themselves.

Return value

If the &h0200 bit is not set in the waitflag parameter, the return value will be a single byte to indicate success (ASCII 13, aka RETURN) or failure (ASCII 3, aka Control-C). Note that success just means that the command was successfully executed, not necessarily that the resulting process ran correctly. In the case of waitflag value 1, the status byte is not returned until the sub-process exits, else it is returned as soon as the sub-process is launched.

If the &h0200 flag is set in waitflag, the return value is a string containg a pair of integer values (launch-status and exit-status) separated by a comma. The launch-status indicates whether the sub-process launched ok (0=success, else a standard Windows error code indicating failure). The exit-status is only relevant when combined with waitflag value 1 (i.e. &h0201), in which case it indicates the exit-status returned by the launched sub-process when it exits. Most programs follow the standard of returning 0 for success, else an error code, although the error codes may vary from among programs.

When the launch-status is non-zero, a file will also be left in the current directly, "shellex.log", containing further details about the launch parameters to help in debugging failures.

Examples

! browse to a website using the default browser

? TAB(-10,AG_SHLEXEC);"http://www.microsabio.com";chr(127);

xcall ACCEPN,A

! Open a CSV file (presumably in a spreadsheet app)

? TAB(-10,AG_SHLEXEC);"%ATELOCALDIR%\test data.csv";chr(127);

xcall ACCEPN,A

! Open Explorer to browse a directory on the Windows LAN

? TAB(-10,AG_SHLEXEC);"\\server\share";chr(127);

xcall ACCEPN,A

! Launch email client to send message

? TAB(-10,AG_SHLEXEC);"mailto:arnold@calif.gov";chr(127);

xcall ACCEPN,A

! Launch an instance of A-Shell/Windows to execute an IMGDSX.LIT command

? TAB(-10,AG_SHLEXEC);"$ASHELL,,–e IMGDSX ";IMGSPEC$;",,1,2";chr(127);

! Play a video, SW)SHOWMAXIMIZED, wait, get exit status

? TAB(-10,AG_SHLEXEC);"mplayer2.exe,,/play,c:\temp\vid.wmv,,3,501";chr(127);

input STATUS,EXITSTS

Notes

This method is generally preferred over the Execute Windows Command Line method (e.g. executing an explicit command line with an explicit location and name for the executable) since it eliminates three of the biggest problems normally associated with launching local applications: knowing the actual name of the executable, the command line syntax, and directory where it is located. All of these are taken care of by the association definition.

Under Under Windows versions with UAC (User Account Control), there is an added bonus in that "Shell Execute" will automatically request "elevation" if necessary in order to perform the specified action, whereas "CreateProcesss" will simply fail if the user doesn't have the necessary privileges.

MX_SHELLEX provides the same functionality.

See Also

• ZXPWIN.LIT, which combines the file transfer and shell execute functions with a command line interface

History

2012 June, A-Shell 6.0.1254 / 6.1.1314: Add waitflag value &h0200.


Call SBX as a Function

Numeric Function

? tab(-10, AG_XFUNC); sbxname;", arg1, arg2,....argn"; chr(127);

input "",R

String Function

? tab(-10, AG_XFUNCS); sbxname;",arg1, arg2,....argn"; chr(127);

input line "", R$

No Return Value

? tab(-10, AG_XFUNC2); sbxname; ",arg1,arg2,...argn"; chr(127);

AG_XFUNC (25), AG_XFUNCS (75), and AG_FUNC2 (73) invoke a function implemented via an SBX, returning a numeric, string or no result, respectively. In the first two cases, the result is passed back in the keyboard buffer where it can be retrieved via an INPUT or INPUT LINE statement as shown above.

Sbxname must be the name of an SBX—just the name, no device or extension—stored on the DSK0:[7,6] directory relative to the ATE (or local A-Shell/Windows) client.

The arguments to the SBX are passed in the AG_XFUNC/AG_FUNCS statement as a single string with commas between each argument. So for example, the following statement:

? tab(-10,AG_XFUNCS);sbxname$;"arg1,arg2,arg3";chr(127);

gets executed on the client as it it were:

XFUNC$(sbxname$,"arg1","arg2","arg3")

Comments

Getting the SBX installed on the client is outside the scope of the function. To simplify this prerequisite, see the SOSLIB wrapper function Fn'ATE'SBX which automatically takes care of transferring or updating the SBX from the application/server to the ATE/client if necessary, invoking the routine remotely, and return the result.

See the SOSLIB outine OSVERCLI.SBX [907,33] for an example of a function invoked by AG_XFUNCS using the Fn'ATE'SBX$() wrapper.

An example of a standard routine using this mechanism is ATHTTP.SBX.

Note that the SBX may not perform any standard text mode input operations, as these would interfere with the host/client communication (TELNET/SSH) channel. Instead, if input is needed, use AUI functions, e.g. MSGBOX, EVENTWAIT, INFLD (in GUI mode), etc.

Note that AG_XFUNCS is to AG_XFUNC as the underlying built-in function XFUNC$() is to XFUNC(). The former deals with functions returning a string, while the latter deals with functions returning a numeric value. In both cases, if the specified SBX is not found the return value will be -1, although in the case of AG_XFUNCS, it will be a string representing -1, e.g. "-1", as opposed to the numeric value -1. There is no particular limit on the length of the returned string.

For the numeric and string functions, but not for the no-return value function, see MX_AGWRAPPER a way to encapsulate the two parts of the operation (? Tab and input) into a single XCALL.

History

2016 October, A-Shell/ATE 6.3.1534: Eliminate 1K limit on size of returned string.


Associate A-Shell and Windows Colors

? tab(-10, AG_SYSBCLR); bgsys; comma; bgwin; comma; fgtext {;comma; opcode}; chr(127);

AG_SYSBCLR (formerly SETWINCLR) (26) provides a way to associate some of the A-Shell color palette numbers with the most important Windows colors (the ‘system’ gray commonly used for the background of windows and dialogs, the color used for the background of edit controls, and the standard text color).

Parameters

bgsys

A single digit (0-7) indicating the color number from the A-Shell background palette to be associated with the standard Windows gray (aka "button face" or "dialog background" color). You may also specify "-1" to leave this color alone (in order to set one of the others).

bgwin

A single digit (0-7) indicating the color number from the A-Shell background palette to be associated with the standard Windows color used for the background of edit controls and list boxes (usually white). You may also specify "-1" to leave this color alone (in order to set one of the others).

fgtext

A single digit (0-7) indicating the color number from the A-Shell foreground palette to be associated with the standard Windows text color (usually black). You may also specify "-1" to leave this color alone (in order to set one of the others).

opcode

An optional digit indicating the operation: 0 to set the color associates, 1 to query them. The default is 0 to set.

Return value

If opcode is set to 1, then a string formatted as "#,#,#" will be forced into the keyboard buffer to return the current values of the color associations (in the order of the parameters as shown above).

Examples

! set bg 0 to system gray, bg 1 to edit bg color, and fg 1 to text color

? TAB(-10,G_SYSBCLR);"0,1,0";chr(127);

! query the current colors

? TAB(-10,G_SYSBCLR);0,0,0,1";chr(127);

input bgsys,bgwin,ftext

Notes

The same function can be accomplished with SET.LIT or MX_SYSBCLR, both of which use AG_SYSBCLR to work in both the local Windows and ATE/UNIX environments.


Show Window

? tab(-10, AG_SHOWWINDOW); flags; {","; lft; ","; top; ","; rgt;
","; btn; { ","; rows; ","; cols; { ","; tsts; ","; bsts; { ",";  cid; ",";
hg; ","; vg; { ","; monitors; }}}}}; chr(127);

AG_SHOWWINDOW (27) is equivalent to the subroutine AUI_WINDOW.

If flags >= 0, display window according to the flags and other options. For flags < 0, retrieves information, which is returned formatted as follows (and which you can process via an INPUT or INPUT LINE statement):

flags = -1 or -3 (SW_QRYCTLUNV or SW_QRYCTLPIX):

lft,top,rgt,btm,rows,cols,tsts,bsts,hg,vg

flags = -2 (SW_QRYMON)

lft,top,rgt,btm,0,0,0,0,xres,yres


Flash Window

? tab(-10, AG_FLASHWINDOW); flashop; chr(127);

AG_FLASHWINDOW (28) may be used to force the title bar of the A-Shell window or ATE client to start or stop flashing. This is often useful when the application wants the users attention, but the user has minimized the app and is not paying attention (and the speaker is off). Even when minimized, the flashing on the task bar is hard to ignore.

Parameters

flashop

A single digit 1 to start flashing, and 0 to stop.

Examples

? TAB(-10,AG_FLASHWINDOW);"1";chr(127); ! start flashing

? TAB(-10,AG_FLASHWINDOW);"0";chr(127); ! stop flashing

Notes

Also see ZTERM Escape Sequences in the Appendix. Note that ATE supports both the ZTERM Escape Sequences and AG_FLASHWINDOW, but ZTERM does not support AG_FLASHWINDOW and A-Shell/Windows running locally does not support the ZTERM Escape Sequences. So if you support all three environments, you may want to use the AUI_ENVIRONMENT function to determine which environment you are in.


Set FTP Login / Password

? tab(-10, AG_FTPSETPW); loginname; chr(126); psword; chr(127);

AG_FTPSETPW (29) changes the FTP login information which is otherwise stored in the ATE configuration for the current connection.

Parameters

loginname

FTP login name string

psword

FTP login password string

Examples

? TAB(-10,AG_FTPSETPW);"kane";chr(126);"rosebud";chr(127);

Notes

Only applies to ATE (prior to using the FTP function) not ZTERM. For local A-Shell/Windows FTP, just use FTPDLX.SBX, which accepts explicit arguments for the login name and password.


Get File Stats

? tab(-10, AG_FILESTATS); fspec {,versiz {,hashsiz{, flags}}}; chr(127);

AG_FILESTATS (31) allows you to retrieve info about a file. The return string is of the format:

bytes, mtime, ctime, mode {,ver {,hash {,pcspec}}}

versiz, hashsiz

these are numeric values representing the size of the strings you intend to retrieve them into. If 0 or not specified, then the corresponding field will not be returned. Set versiz=30 to get the #####.#####.#####.#####.##### format; see MX_FILESTATS.

flags

may contain one or more of the following:

Value | Description
&h0001 | Check for fspec in ATE cache directories if not found otherwise
&h0002 | Returned client native spec of located file

Note that MX_FILESTATS is generally use in preference to AG_FILESTATS, because it is easier to use (standard XCALL return values), and works in all the same cases (including ATE), with the one exception that it requires A-Shell on the server. AG_FILESTATS could be used on any kind of server.

History

2011 June, A-Shell 5.1.1222: Add flags parameter, reformat return string


Make Directory

? tab(-10, AG_MKDIR); dirspec; chr(127);

AG_MKDIR (32) creates a Windows directory. To return a status code indicating if the operation succeeded, add a ",1" parameter, i.e.:

? tab(-10,AG_MKDIR);dirspec;",1";chr(127);

input "",status

For more information, see MX_MKDIR, which is the preferred way to access this function.


Event Wait

? tab(-10, AG_EVENTWAIT); parentid; comma; tlid; comma; opcode; chr(127);

AG_EVENTWAIT (33) waits for an event, while allowing the focus to be moves around a set of buttons defined by the parentid and opcode parameters. The command is used internally by ATE for implementing the AUI_EVENTWAIT function, which should be used in applications rather than AG_EVENTWAIT directly.


Enable / Disable Status Lines

Updated April 2011

? tab(-10, AG_STATUSLINES); stslin; ","; visible; ","; textmode; chr(127);

AG_STATUSLINES (34) controls the behavior of the top, bottom and system status lines by making them visible or not, and by specifying fixed or proportional fonts. Making the status lines disappear may give the window a cleaner look, especially if the status lines are not being used. When not visible, the status line space becomes part of the main window (increasing the character cell height). See History, below, for comments on fonts.

Parameters

stslin

Character code indicating which status line is being impacted.

Value | Description
1 | Top status line
2 | Bottom status line
3 | System status line
4 | Save visibility/configuration of all status lines
5 | Restore saved configuration

visible

Value | Description
0 | Invisible
1 | Visible
"" | No change

textmode

Value | Description
0 | Fixed pitch font
1 | Proportional font

Examples

? TAB(-10,AG_STATUSLINES);"1,0";chr(127); ! remove top status line

? TAB(-10,AG_STATUSLINES);"2,0";chr(127); ! remove bottom status line

? TAB(-10,AG_STATUSLINES);"1,1";chr(127); ! restore (enable) top status line

Notes

This capability was implemented via a Tab(-10,x) sequence rather than by extending the existing Tab(-1,202) or Tab(-1,203) commands, because those commands to not have terminators and thus we cannot just add optional arguments. Because Tab(-10,x) commands must be terminated with chr(127), they support variable length arg lists.

History

2011 April A-Shell 5.1.1214: Add stslin options to save and restore status line visibility states.

2011 April A-Shell 5.1.1212: Status line enhancement: The top and bottom status lines can now be displayed using a proportional font.

The default textmode is 0, but automatically switches to 1 if any GUI controls are created before an explicit AG_STATUSLINES command is issued. The assumption here is that if you are using GUI text or other controls in the window, you would probably want the status line text to also use that mode. Once you issue an AG_STATUSLINES command, the mode stays fixed until another AG_STATUSLINES command changes it.

Note that the number of characters allowed on the status line does not change between modes, even though typically proportional text is more compact. Also, the proportional text is tokenized (similar to the way the OPTIONS=GUI_SPC_IND feature works) so that any text tokens preceded by two or more spaces will be repositioned to start in the same position as it would have in fixed pitch mode.


Image Processing

? tab(-10, AG_IMAGE); opcode; parameters; chr(127);

Note: as with most other AG_xxx functions, the XCALL front-end is preferable if available. In this case, that would be AUI_IMAGE, which see for definitions of the parameters—including status—referenced below.

AG_IMAGE (35) provides access to A-Shell's image processing functions. Use the following syntax:

? tab(-10,AG_IMAGE); IMGOP_LOAD; ","; handle; ","; fspec; ","; chr(127);

? tab(-10,AG_IMAGE); IMGOP_CLOSE; ","; handle; chr(127);

? tab(-10,AG_IMAGE); IMGOP_DISPLAY; ","; handle; ","; srow; ","; scol; ","; erow; ","; ecol; ","; flags; chr(127);

? tab(-10,AG_IMAGE); IMGOP_LOADDISP; ","; handle; ","; "; srow; ","; scol; ","; erow; ","; ecol; ","; flags; ","; fspec; chr(127);

? tab(-10,AG_IMAGE); IMGOP_INFO; ","; handle; ","; fspec; ","; chr(127);

? tab(-10,AG_IMAGE); IMGOP_HIDE; ","; handle; chr(127);

? tab(-10,AG_IMAGE); IMGOP_ACQUIRE; ","; handle; ","; fspec; ","; compfactor; ","; appname; chr(127); ","; pages; ","; scanflags;

? tab(-10,AG_IMAGE); IMGOP_SELECTSRC; ","; handle; ","; srcname; chr(127);

? tab(-10,AG_IMAGE); IMGOP_TWERR; ","; handle; ","; chr(127);

? tab(-10,AG_IMAGE); IMGOP_CAPTURE; ","; handle; ","; fspec; ","; compfactor; ","; winid; chr(127);

? tab(-10,AG_IMAGE); IMGOP_SAVEAS; ","; handle; ","; fspec; ","; compfactor; chr(127);

For all but IMGOP_INFO, the return info is formatted as:

INPUT status,handle

For IMGOP_HIDE, it is:

INPUT status,handle,owidth,olength,dwidth,dlength,bpp


Display Wallpaper

? TAB(-10,AG_WALLPAPER); imagespec {,opcode {,dlgid}}; chr(127);

AG_WALLPAPER (39) provides a way to display a bitmap file as "wallpaper" for the background of the main A-Shell window.

Parameters

imagespec

File specification of an image. May be any image type recognized by AUI_CONTROL; JPG is probably the best option here. Either AMOS or native syntax may be used, but it will be interpreted relative to the PC. So if running on a UNIX server with ATE, you must arrange for the file to be present on the PC before you can invoke it.

opcode

Code | Description
0 | (default) Load new wallpaper, deleting any old wallpaper. If imagespec is null, then it just deletes any existing wallpaper. For dialogs, opcode must be 0. The only valid operation is to set the wallpaper to the dialog; it is destroyed when the dialog is deleted.
1 | Clear current wallpaper but save it.
2 | Restore previously saved wallpaper.
+4 | (Add 4). Normally, the wallpaper save and restore operations are destructive in the sense that "save" clears the current wallpaper, and an attempt to restore when there is no saved wallpaper will effectively delete the current wallpaper. To accommodate applications that want to be able to issue redundant save and restore operations, you can add 4 to opcode. Part of the incentive for this feature is that restoring a previously saved wallpaper is much faster than re-loading it from disk.

dlgid

may either be the numeric or alphanumeric identifier for the dialog. If dlgid is zero or omitted, the command works on the main window as before. In most cases, you will want to create the dialog with the bgc parameter set to RGB_TRANSPARENT, else the background of static text controls will cover that portion of the wallpaper.

Examples

Load examples:

? TAB(-10,AG_WALLPAPER);"bmp:pinup1.bmp";chr(127);

? TAB(-10,AG_WALLPAPER);"c:\my documents\wallpaper\rainforest.png";chr(127);

? TAB(-10,AG_WALLPAPER);"%MIAME%\bitmaps\clouds.jpg";chr(127);

? TAB(-10,AG_WALLPAPER);".\my life in pictures.jpg";chr(127);

? TAB(-10,AG_WALLPAPER);"";chr(127); ! (remove wallpaper)

Other examples:

? TAB(-10,AG_WALLPAPER);",1";chr(127); ! Save (and then clear) wallpaper

? TAB(-10,AG_WALLPAPER);",5";chr(127); ! Save (but don't clear) wallpaper

? TAB(-10,AG_WALLPAPER);",2";chr(127); ! Restore wallpaper; clear saved copy from memory

? TAB(-10,AG_WALLPAPER);",6";chr(127); ! Restore wallpaper only if there is saved wallpaper

Notes

Wallpaper is generally only useful when you are going to display a dialog on top of it. Otherwise, unless the wallpaper is very subtle, it makes it difficult to read text displayed on it. VUE and EZTYP temporarily disable the wallpaper (using opcodes 1 and 2). Only BMP files are supported.

The "load" command also automatically "saves" a copy if there is not already a saved copy. Thus you can do a load followed by a restore without a save.

History

2016 December, A-Shell 6.3.1540: AG_WALLPAPER now supports PNG and other image formats for main window wallpaper. This was always the case for dialog wallpaper, but until now the main window wallpaper was limited to BMP files.

2016 September, A-Shell 6.3.1527: Add dlgid and the ability to apply wallpaper to dialogs.


Save / Restore Screen with ID

? tab(-10, AG_SAVERES); cmd; comma; id; chr(127);

AG_SAVERES (40) provides a way to save and restore copies of the screen using an ID number rather than a stack like Tab(-1,202) and Tab(-1,203).

Parameters

cmd

Character code indicating the action to perform:

Value | Description
S | Save screen
R | Restore screen
P | Pop (discard) previously saved screen

id

A numeric digit, 0 thru 9. 0 on the restore or pop commands refers to the last saved screen (whatever id it has).

Examples

? TAB(-10,AG_SAVERES);"S,1";chr(127); ! save screen with ID 1

? TAB(-10,AG_SAVERES);"S,5";chr(127); ! save screen with ID 5

? TAB(-10,AG_SAVERES);"R,1";chr(127); ! restore screen saved as ID 1

? TAB(-10,AG_SAVERES);"R,0";chr(127); ! same as TAB(-1,203)

! (i.e. restore last saved screen)

? TAB(-10,AG_SAVERES);"P,3";chr(127); ! pop/discard screen saved as ID 3

? TAB(-10,AG_SAVERES);"P,0";chr(127); ! pop/discard last saved screen

Notes

This capability was implemented via a Tab(-10,x) sequence rather than by extending the existing Tab(-1,202) or Tab(-1,203) commands, because those commands do not have terminators and thus we cannot just add optional arguments. Because Tab(-10,x) commands must be terminated with chr(127), they support variable length arg lists.

AG_SAVERES sequences are only supported under A-Shell/Windows and under UNIX when the client is ATE.

AG_SAVERES does save and restore GUI controls. However, it is advisable that you clear the screen with Tab(-1,0) before restoring a saved screen which contains GUI controls; otherwise the restore controls will be added to any controls already existing on the screen.

Unlike Tab(-1,202) and Tab(-1,203), which operate on the machine where the software is running, Tab(-10,x) sequences operate on the workstation. Thus, under Linux, the save/restore operation takes place entirely on the workstation. This reduces both network traffic, memory, and CPU usage on the server, but it should be noted that the server's copy of the screen map will not be updated. This could interfere with server-based screen pictures, and also with the operation of TCRTs 202/203 after AG_SAVERES, since those TCRTs interact with the server's screen map. (The problem is temporary though, since the server's screen map gets re-synchronized whenever you clear and repaint the screen with regular, server-based PRINT statements.)


ATE Disconnect

Updated January 2016; see History

? tab(-10, AG_ATEDISCONNECT); {flags{,msg}}; chr(127);

AG_ATEDISCONNECT (44) allows the application running on the server to force the ATE client to disconnect. Typically this causes the ATE client window to close.

Parameters

flags (Num)

may contain one or more of the following bits:

Value | Meaning
&h0001 | Force close-on-disconnect option to ON (no dialog on close)
&h0002 | Force close-on-disconnect option to OFF (display dlg on close)
&h0004 | Don't disconnect (just update the close-on-disconnect and msg options)

msg (string, up to 100 characters)

may contain an optional replacement for the default "Connection reset" message that appears inside a message box when the close-on-disconnect option is not set.

Comments

It is generally considered good style if the application program automatically closes the ATE connection when the user exits or aborts from the main menu (or application login dialog). This eliminates the need for users to learn the various ways of performing independent or manual disconnects (which are usually best avoided altogether). However, there are a few guidelines and points to be aware of when adding this function to your application:

• Although A-Shell/Windows will ignore the command, other emulators will just see a foreign ESC sequence. An easy way to test whether the command is supported is to use the AUI_ENVIRONMENT function and test for the AGF_GUIEXT flag.

• Since the disconnect operation will trigger a SIGHUP signal (same as if the client initiated the disconnection), which in turn will shut down the application, you should perform all your shutdown housecleaning (closing files, etc) before sending the AG_ATEDISCONNECT command.

• For maintenance purposes, it is useful to provide a backdoor around the server-initiated disconnect. (You can base this on the user login, a hidden menu item, a startup switch, etc.)

• To prevent the user from independently or manually disconnecting at an inappropriate time, see Password for Disconnect.

History

2016 January, A-Shell 6.2.1422: The text message option in AG_ATEDISCONNECT is now independent of the flags option. Previous, if the text message was specified, it logged the message to the ashlog file, but effectively forced the flags option to &h0001 (no dialog on close). In other words, the custom message was only being seen in the log, not by the user—which, upon review, seemed just wrong.

2012 September, A-Shell 6.0.1258: Added the two parameters


Get ATE Environment Variable

? tab(-10, AG_GETENV);"var,1"; chr(127);

AG_GETENV (45) will return (in the keyboard buffer) the definition of the specified environment variable as defined to the ATE client (or A-Shell/Windows). In addition to the proper environment variables, the command will also recognize two special ones that are only understood by this command within the ATE client: %ATEEXE% (the full filespec of the client executable, e.g. "c:\Program Files\MicroSabio\ATE\bin\ashw32.exe") and %ATEVER% (the version string for the client executable, e.g. "4.9(930)-1").

If the ",1" is appended to the environment variable name, as shown above, then the result will be "de-mangled" (i.e. converted from the DOS 8.3 compressed format to the full long format), if possible. For example:

? TAB(-10,AG_GETENV);"TEMP",chr(127);

The above command (without the ,1) might return something like:

C:\DOCUME~1\yourname\LOCALS~1\Temp

Using the new syntax, with the,1, the command:

? TAB(-10,AG_GETENV);"TEMP,1",chr(127);

might return something like:

C:\DOCUMENTS AND SETTINGS\yourname\LOCAL SETTINGS\Temp

See Also

• MX_GETENV for retrieving an environment variable from the application server—as opposed to client—machine.

History

2009 October, A-Shell 5.1.1163: The pseudo-environment variable ATELICMODE is supported in AG_GETENV to return a single decimal value containing flags indicating how the ATE workstation was licensed. The bottom 8 bits of the value are 0 if successfully licensed, else one of the LICF_xxx flags from ASHINC:ASHELL.DEF. The next byte(s) contain one or more bit flags from ATELF_xxx:

Symbol | Value | Meaning
ATELF_PROTO | &h0100 | ATE handshake was initiated, and also that the ATE client is at least 5.1.1164.0. (Prior to that, the command ? TAB(-10,AG_GETENV);"ATELICMODE";chr(127) will return an empty string.
ATELF_PC | &h0200 | ATE client has a local license.
ATELF_SRV1 | &h0400 | The server attempted to pass the ATE license via the new streamlined protocol (1162+)
ATELF_SRV2 | &h0800 | The server attempted to pass the ATE license via the LICENS/ATESRV mechanism. This also implies that the server is less than 5.1.1162.0 and/or that the passed license wasn't valid (in which case the lower byte should be <>0).
ATELF_AUX | &h1000 | The server attempted to pass an auxiliary license to the client. (Will always be combined with ATELF_SRV2.)


Display Open/Save File Dialog

Updated July 2013; see History

? tab(-10, AG_GETOFD); path; ","; filter; ","; title; ","; flags; ","; defExt; ","; type; chr(127);

AG_GETOFD (47) displays a standard Windows open or save file dialog, such as the one shown below (from Windows XP). This operation can only take place on a GUI-enabled client, either ATE or some form of A-Shell/Windows.

The parameter formats and values are the same as in MX_GETOFD, which is the preferred way of accessing the function. The return data, sent into the keyboard channel, consists of Files,Flags,FileTitle<CR>. The files parameter contains one or more complete filespecs, separated by chr(10) characters.

this is a linked image

History

2013 July, A-Shell 6.1.1355: Filenames containing commas are now quoted; previously they were not, which almost certainly led to incorrect parsing of the response


Set Mouse Cursor

? TAB(-10, AG_SETCURSOR); chr(CursorCode); chr(127);

AG_SETCURSOR (50) allows you to change the mouse cursor to the symbol of your choice, from the normal A-Shell/Windows cursor of an "I Beam" (which changes automatically to an arrow when the mouse is moved over a button or the menu bar). The value of CursorCode determines the cursor symbol, from the table below:

CursorCode | Description | CursorCode | Description
32 | Arrow | 44 | Watch 4
35 | Pointing hand | 45 | Watch 5
40 | Hourglass | 46 | Watch 6
41 | Watch 1 | 47 | Watch 7
42 | Watch 2 | 48 | I-Beam
43 | Watch 3 |  |

For example, while performing an operation that may take a few seconds, like building a list of customers to load into an XTREE, you can set the cursor to an hourglass with this command:

PRINT TAB(-10,AG_SETCURSOR);chr(40);chr(127); ! set cursor to hourglass

For backwards compatibility, A-Shell/Windows and ATE also support the older Tab(-1,160) command:

print tab(-1,160); chr(CursorCode);

Note that the AG_SETCURSOR syntax should be used in new development.


Password for Disconnect

? tab(-10, AG_DISCONNECTPW); pw; chr(127);

? tab(-10, AG_DISCONNECTPW); pw; "~"; msg; chr(127);

? tab(-10, AG_DISCONNECTPW); pw; "~"; msg; "~"; title; chr(127);

AG_DISCONNECTPW (53) allows the application to establish a disconnect/terminate password, which the user must enter in order to disconnect (from ATE) or terminate (from a local A-Shell/Windows session). When established, this supersedes the big dialog/warning message that otherwise appears when you click on the "X". And perhaps more importantly, it also gets triggered when the "Disconnect" menu option is clicked, which previously exited without any fanfare whatsoever. Syntax is any of the following:

Parameters

pw (String, up to 15 bytes)

If null, the password feature is disabled and disconnect behavior reverts to the way it was before.

msg (String)

can be used to replace the standard message which otherwise appears on the password dialog:

Msg may include a CRLF to force a line break; otherwise it is wrapped to fit the space. Since the space is designed for about 200 lower case characters, if you have a lot less, you might want to use a leading CRLF just to vertically center it.

title (String)

replaces the default title ("ATE Disconnect" or "Terminate A-Shell Session?") of the dialog box that prompts for the password.

Comments

The combined length limit for msg plus title is 248 characters.

Since you can set the password any way you like, some$ people use a formula, perhaps based on the date, or on any information you can obtain programmatically about the environment, job, etc., so that it can be given out as needed without necessarily revealing the formula.

If want to allow the user to disconnect from certain "safe" places (like the main menu), then you can clear the password.

The password is not encrypted, because no matter how secretive we make it, there is no way to stop the user from forcefully disconnecting by such brutal methods as rebooting, pulling the Ethernet cable, powering down, etc. So this is at best a merely a way to discourage sloppiness rather than a way to prevent it entirely.

There is no way to disable the password but still require the user to enter some kind of confirmation. To get something like that effect, just change the message to explicitly state what the 'password' is, e.g. "...or enter 'GERONIMO' in the box below:"

History

2006 March, A-Shell 4.9.952: Added to A-Shell


Auxiliary Port Control

Updated ("copies") March 2011

? tab(-10, AG_SPOOLCFG); file, ptr, fsize, internal, switches; copies; chr(127);

AG_SPOOLCFG (54) allows the host to adjust or control how ATE handles data sent to its "auxiliary port."

Background: Terminal emulators often emulate the auxiliary port feature that some dumb terminals had. Since the most common use of such auxiliary ports was to connect a printer to the back of a terminal, the usual way to emulate this capability is for the terminal emulator to capture the data intended for the aux port and then send it to a Windows printer instead. ZTERM, ATE, and other emulators allow the user to define which printer to use, or to select a "prompt" option in which the user is prompted to select a printer each time data is output to the auxiliary port. The application initiates output to the auxiliary port by sending Tab(-1,82). Everything output to the terminal after this should be captured by the emulator and redirected to the aux port (however it is defined) rather than to the screen. To mark the end of the auxiliary output, the application sends a Tab(-1,83).

Note: ZTERM and ATE also support "serial passthrough", which is a scheme for bidirectional communications with an actual device (such as cash drawer) physically connected to a serial port on the PC. See ZTERM Escape Sequences in the Appendix for more details.

If the application knows that the emulator is ATE (see AUI_ENVIRONMENT), it can adjust the aux port behavior by sending a AG_SPOOLCFG command prior to the start of the auxiliary port operation, i.e. prior to the Tab(-1,82). Note that the effect of the AG_SPOOLCFG command only lasts until the end of the next auxiliary port operation (i.e. the original configuration is restored by the next Tab(-1,83) command).

Parameters

file

is an optional filename to use for the print operation on the client side. This is handled automatically by the AUXLOC: driver so is only of use when you are going to use Tab(-1,82) directly to output text to the aux port (rather than indirectly via spooling to the AUXLOC: driver).

ptr

is an optional printer name, which temporarily overrides the printer choice in the ATE connection properties. Without this feature, the only way to change the ATE printer is for the user to do it manually via the Connection Properties dialog, which makes it hard to ensure synchronization with the needs of the application.

fsize

is an optional parameter specifying the number of bytes to be output. When non-zero, the subsequent auxiliary port output operation will be handled as binary data. This provides a means of transferring a binary file from the server to the client through the terminal channel without requiring FTP.

internal

is a field reserved for internal use. If you want to specify the switches parameter, then insert an extra comma between fsize and switches to mark the position of this parameter.

switches

contains the SPOOL.SBR switches you want to pass to the ATE client. Depending on the circumstances, some or all of them may be ignored—e.g. when the operation is really just a file transfer, the printing switches are not relevant. But if the operation does result in printing, these switches will generally override those otherwise set in the client configuration. One exception is that the APEX Preview Preference settings "Never" and "Always" take precedence over the PREVIEW and NOPREVIEW switches specified by the application.

copies

optional; if not specified, the default is 1. The value will be used by the ATE client to generate multiple copies of the subsequent printfile send via the AUXLOC: mechanism. This feature is primarily used within A-Shell when processing AUXLOC: printing requests. If used directly by an application, you should first verify that the client is ATE 5.1.1208.0 or higher; see MX_GETVER. There is no harm in sending the copies parameter to older versions of ATE, but it will have no effect (and thus the extra copies

Examples

One example of this would be if the app wanted to export a report to PDF, and it "knew" that all ATE clients had a PDF printer whose name started with "PDF":

PRINT TAB(-10,AG_SPOOLCFG)",PDF";chr(127);

xcall SPOOL,FILE,"AUXLOC"

Assuming that there is a printer init file on the server called "AUXLOC" that contained DEVICE=AUXLOC:, this would transfer the file to the PC, and send it to the "PDF" printer regardless of (and without changing) the current printer setting for the ATE connection. We don't need to specify the filename above in the AG_SPOOLCFG statement because the AUXLOC: driver handles that automatically (but we do need the comma so that PDF is properly recognized as the ptr parameter).

Another example would be to use the DISK: pseudo-printer to simulate an ASCII FTP transfer:

PRINT TAB(-10,AG_SPOOLCFG);"DISK:%ATECACHEDIR%";chr(127);

xcall SPOOL,FILE,"AUXLOC"

This would transfer file from the server to the ATE client %ATECACHEDIR% directory, which might be handy if FTP was not available on the server.

See Also

• ATEAPX.SBX (in the SOSLIB), which uses AG_SPOOLCFG to implement both ASCII and BINARY file transfers from the server to the client.

History

2006 March, A-Shell 4.9.952: Added to A-Shell


Display printer selection dialog

Updated April 2012

? tab(-10, AG_WINPTR); chr(127);

AG_WINPTR (56) brings up the "select printer" dialog. The selected printer name, along with the port and driver are returned in the keyboard buffer. For example:

? TAB(-10,AG_WINPTR);chr(127);

INPUT STATUS,PTRNAME$,PTRPORT$,PTRDVR$,ORIENTATION,LENGTH,WIDTH,FORMNAME,DUPLEX,BIN,COLOR,QUALITY

STATUS will be 1 if the user selected a printer, else 0

See MX_WINPTR for the definitions of the remaining parameters.

Note that since ATE and A-Shell/Windows versions prior to 6.0.1248.0 will only return the first four fields, and that INPUT will continue to prompt for parameters that were not supplied, you should first check the version and use an appropriate INPUT statement. Using MX_WINPTR avoids the issue entirely. Another approach would be to use INPUT LINE to get the entire response, then parse it manually, either using INSTR or STRTOK.SBR.

History

2012 April, A-Shell 6.0.1248: Added all parameters after "PTRDVR$"


Enable/Disable Wrap

? tab(-10, AG_WRAP); opcode; chr(127);

AG_WRAP (62) may be used to control wrapping in A-Shell/Windows and ATE. Use opcode "0" (with quotes) to disable, "1" to enable. By default, wrap is enabled.


Change RGB Value

? tab(-10, AG_SYSCOLOR); id{,r,g,b}; chr(127);

AG_SYSCOLOR (63) allows you to change the Windows RGB value for certain parts of the Windows user interface. Note that this is offered on an as-is basis, and is not recommended due to:

• Conflicts between these settings and the current Theme

• Conflicts with the "approved" way of changing Windows desktop settings (via the Control Panel)

• Differences in the way it may work under different versions of Windows

• Possible problems with the way other applications may respond to the fact of color changes (since any such change triggers a notification message to be sent to all affected applications).

That said, you can experiment as you wish. The values for the id parameter are shown in the following table.

Symbol | Value | Symbol | Value
COLOR_SCROLLBAR | 0 | COLOR_INACTIVEBORDER | 11
COLOR_BACKGROUND | 1 | COLOR_APPWORKSPACE | 12
COLOR_ACTIVECAPTION | 2 | COLOR_HIGHLIGHT | 13
COLOR_INACTIVECAPTION | 3 | COLOR_HIGHLIGHTTEXT | 14
COLOR_MENU | 4 | COLOR_BTNFACE | 15
COLOR_WINDOW | 5 | COLOR_BTNSHADOW | 16
COLOR_WINDOWFRAME | 6 | COLOR_GRAYTEXT | 17
COLOR_MENUTEXT | 7 | COLOR_BTNTEXT | 18
COLOR_WINDOWTEXT | 8 | COLOR_INACTIVECAPTIONTEXT | 19
COLOR_CAPTIONTEXT | 9 | COLOR_BTNHIGHLIGHT | 20
COLOR_ACTIVEBORDER | 10 |  |

The RGB values r, g, and b range from 0 to 255 (0,0,0=black; 255,255,255=white).

If you don't specify the r, g, and b values, the Tab function will return a string in the keyboard buffer containing the current r, g, and b values for the specified interface component.

Note that if you are associated A-Shell palette numbers with the standard Windows dialog background, window background, or text, you must do that first before using the AG_SYSCOLOR command.


Retrieve ATE Date and Time

? tab(-10, AG_DATETIME); chr(127);

AG_DATETIME (64) returns the system date and time according to the ATE client. The returned information is in the form of date,time,status where date is the decimal value of the separated date format (see IDTIM.SBR for details), time is the number of seconds since midnight, and status will be 0 if the operation was successful, else a Windows error code. For example:

map1 today,b,4

map1 now,b,4

map1 status,f

? tab(-10,AG_DATETIME);chr(127);

input "",today,now,status

You might then compare this information against the values returned by the DATE and TIME system functions on the server to decide whether the client is reasonably in sync, and if not, you might prompt the client to update the clock on either the server or the client.


Get OS Info

? tab(-10, AG_OSVER); chr(127);

AG_OSVER (66) retrieves information about the current host operating system or ATE, including its name, version, and release, plus the platform that this copy of A-Shell was compiled for. It is equivalent to MX_OSVER, which see for more information. AG_OSVER returns the os'name, os'ver, osrel, and asplatform fields in a single comma-delimited string.


Perform Clipboard Operations

? tab(-10, AG_CLIPBOARD); opcode; ","; srow; ","; scol; ","; erow; ","; ecol; ","; rtnflag; ","; text; chr(127);

AG_CLIPBOARD (65) allows for copying text from a variable or screen coordinates to the clipboard, or for retrieving the contents of the clipboard.

See MX_CLIPBOARD for descriptions of the parameters (except rtnflag).

rtnflag should be set to 1 if the operation is to return data or status. In the case of opcodes 0 and 2 (retrieve clipboard contents), the returned data are those contents. In the case of other opcodes, it can return the status code as defined for MX_CLIPBOARD.

Examples

Copy some explicit text to the ATE clipboard:

! opcode=3, coordinates=0, rtnflag=0 (no response needed)

? tab(-10,AG_CLIPBOARD);"3,0,0,0,0,0,some clipboard text";chr(127);

Retrieve ATE clipboard contents. Note that return string is formatted as 'status,text~' with no trailing CR, so we can't use INPUT to retrieve it. Instead we'll input it one character at a time to build up the string, then parse it into the status and text...

MAP1 PLINE$,S,512

MAP1 A,F

? tab(-10,AG_CLIPBOARD);"2,0,0,0,0,1";chr(127);

do

A = getkey(-1)

if A # 126 PLINE$ = PLINE$ + chr(A)

loop until A=126 ! terminate on tilde (126)

! now parse it out

A = instr(1,PLINE$,",")

if A > 0 then STATUS = PLINE$[1,A-1] : PLINE$ = PLINE$[A+1,-1]

? "Status: ";STATUS

? "Clipboard contents: ";PLINE$

Note that the above case could be handled much more simply with a single instance of MX_CLIPBOARD.


Change Underline Attribute

? tab(-10, AG_ATTRSUB);"1,2,"; FG'R;","; FG'G;","; FG'B;","; BG'R;","; BG'G; ","; BG'B; chr(127);

AG_ATTRSUB (68) allows for changing the underline attribute to an arbitrary fg/bg color combination. It is useful for slight aesthetic improvement to legacy text-mode programs which use underline, since underline has a rather old-fashioned look.

where FG'R, FG'G, FG'B are the RGB values (0-255) for the foreground color, and BG'R, BG'G, BG'B are the RGB values (0-255) for the background color.


Set/retrieve OPTIONS for ATE

? tab(-10, AG_OPTIONS);"opcode, options1, options2"; chr(127);

AG_OPTIONS (69) allows you to set or retrieve OPTIONS values from the ATE client. It is similar to MX_GETOPTIONS and MX_SETOPTIONS, but works for the ATE client.

Value | Description
0 | Get current options. These are returned in the keyboard buffer in the format options1,options2. For example: ? tab(-10,AG_OPTIONS);"0";chr(127); input "",OPT1,OPT2
1 | Set values (using passed options1, and if specified, options2)
2 | Set only the option2 value
4 | OR (set) individual bits from options1 and options2. This allows you to set one or more bits without having to first retrieve the current settings (in order to avoid changing existing flags). Note that you can specify options1 or option2 = 0 to avoid changing it.
8 | Clear individual bits. In this case, any bit that you specify in options1 or options2 will be cleared from the current settings. Again, you can specify 0 to avoid changing one set of flags or the other.

Comments

Only opcode zero generates a response. The other opcodes generate no response and should not be followed by an input operations.

The symbols in the examples (e.g. GOP_EXTFIO) are defined in ashell.def; note that it is the symbol value (e.g. the value of symbol GOP_SBX_RUNDIR is &h2000 or 8192), not its name, that needs to be transmitted. If you fail to include the ashell.def file and compile without the /M option, your symbols will evaluate to 0 and won't work as intended.

Examples

Value

Example

1

? tab(-10,AG_OPTIONS);"1,"; options1; chr(127); ! set options1

? tab(-10,AG_OPTIONS);"1,"; options1; ","; options2; chr(127); ! set options1,options2

2

? tab(-10,AG_OPTIONS);"2,"; options2; chr(127); ! set options2

4

? tab(-10,AG_OPTIONS);"4,"; GOP_EXTFIO; chr(127); ! set GOP_EXTFIO flag in options1

? tab(-10,AG_OPTIONS);"4,0,"; GOP2_GUISPCINDENT; chr(127); ! set GOP2_GUISPCINDENT flag in options2

8

? tab(-10,AG_OPTIONS);"8,"; GOP_EXTFIO; chr(127); ! clear GOP_EXTFIO flag in options1

? tab(-10,AG_OPTIONS);"8,0"; GOP2_SBX_RUNDIR; chr(127); ! clear GOP2_SBX_RUNDIR flag in options2


Select Windows Folder

? tab(-10, AG_BROWSEFOLDER); folder, rootID, title, flags; chr(127);

input line "", Folder

AG_BROWSEFOLDER (70) invokes a standard Windows dialog allowing the user to browse for and select a folder or other non-file resource (such as a computer or device). For parameter descriptions and other information, see MX_BROWSEFOLDER and MX_AGWRAPPER.


Retrieve Windows Path

Updated and reviewed July 2011

? tab(-10, AG_GETSHELLPATH); csidl; chr(127);

input line "", Folder

AG_GETSHELLPATH (71) retrieves the physical directory path corresponding to a logical Windows directory identified by its CSIDL identifier. It is mainly used internally by the MX_GETSHELLPATH function, which is generally preferred.


Create A Shortcut

? tab(-10, AG_SHORTCUT); target; ","; lnkspec; ","; descr; ","; workdir;","; icon;","; iconidx; chr(127);

input "",STATUS

AG_SHORTCUT (72), the command version of MX_SHORTCUT, is used to create a shortcut.

Note, however, that there is no particular need to use this form of the command (except under non-A-Shell servers) since MX_SHORTCUT will automatically issue it as needed for ATE support.

Also note that this version does not support expansion of %ENV% variables (another reason to use the MX_SHORTCUT instead).


Get / Set / Load / Save Settings

To retrieve (get) a specific value:

? tab(-10, AG_WINSETTINGS); "0,"; id;", ,1"; chr(127);

input "",VALUE

To update (set) a specific value:

? tab(-10, AG_WINSETTINGS); "1,"; id;",value"; chr(127);

To save all current settings to the specified fspec:

? tab(-10, AG_WINSETTINGS); "2,"; fspec; ",1"; chr(127);

input "", STATUS

To load all settings from a settings file:

? tab(-10, AG_WINSETTINGS); "3,"; fspec; ",1"; chr(127);

input "", FSPEC

AG_WINSETTINGS (46) retrieves or updates individual configuration settings (the types of settings that may be set in the Settings menu dialogs and saved or loaded from the File menu options), as well as saving or loading the entire set of values. Because the syntax is a bit tricky, in most cases it will be preferable to use MX_WINSETTINGS, which works in both local Windows and ATE environments.

id

identifies the individual settings parameter to retrieve or update; see the table of ids in MX_WINSETTINGS.

value

specifies the string or numeric value to set for the specified parameter.

fspec

specifies the file to load from or save to. If left blank, the current settings file will be used.


Check ATE network state

? tab(-10, AG_CHKPCNET); chr(127)

input "",FLAGS

STATUS = FLAGS / 65536 ! STATUS in upper word

FLAGS = FLAGS and &hFFFF ! FLAGS in lower word

AG_CHKPCNET (74) allows you to detect the state of the ATE-connected PC'S internet connectivity from the server. It is equivalent to the subroutine MX_CHKPCNET.

STATUS and FLAGS have the same meaning as in MX_CHKPCNET, but are returned combined into a single 4 byte variable in order to minimize complications if the function times out or is not available.

Comments

MX_CHKPCNET can be called directly even on A-Shell/UNIX (1138.3 or higher), so there is no particular need to use the AG_CHKPCNET protocol except where the server side is too old (or isn't A-Shell).

If the ATE client is prior to 1138.3, this function will just hang (until the user hits ENTER), so you would do well to check the version of the ATE client (see MX_GETVER) before calling it. That's another reason to just use MX_CHKPCNET, since it performs that check for you, returning -1.


Clear/Set/Query ATE Trace Flags

? tab(-10, AG_TRACE);" op, {trflags}; chr(127);

AG_TRACE (76) allows the application on the server to clear, set, or query the trace flags on the ATE client in real time. This is mainly useful for debugging, but in such a case, can be very handy since it is not often practical to arrange for users to change the trace flags on individual copies of ATE.

MAP1 OPCODE,B,1 ! 0=clear, 1=set, 2=query

MAP1 TRFLAGS,B,4 ! Flags to clear, set or query

In all cases, start by setting TRFLAGS to be the combination of one or more flags that you are interesting in clearing, setting, or querying. You can also specify them directly, using the TROP_xxxx symbols from the ashell.def file. For example, to set the XTREE and XDEBUG flags:

? TAB(-10,AG_TRACE);"1,";(TROP_XTREE or XTROP_XDEBUG);chr(127);

To specify all flags, you can use the shorthand -1:

? TAB(-10,AG_TRACE);"2,-1";chr(127); ! query all flags

input "",TRFLAGS ! for query, retrieve results

? "Current ATE trace flags: ";Fn'Dec2Hex$(TRFLAGS); ! display in hex

if (TRFLAGS and TROP_ATE) then "ATE trace set"

if (TRFLAGS and TROP_XTREE) then "XTREE trace set"

etc.


Set Environment Variable

? tab(-10, AG_SETENV);"<var>=<value>"; chr(127);

AG_SETENV (77) is used to set an environment variable.

Example

? TAB(-10,AG_SETENV);"APEX=%MIAME%\cache";chr(127);

This defines (or redefines) the environment variable APEX to equal the specified directory, after first expanding the environment variable MIAME. Note that the APEX environment variable determines where ATE puts the print files captured for local print or preview operations.

See MX_SETENV for setting an environment variable on the application server (as opposed to client) machine.


Set/Retrieve Timeout Period

? tab(-10, AG_IATIMEOUT); opcode;","; timesecs; chr(127);

AG_IATIMEOUT (79) retrieves or sets the inactivity timeout period. Same idea as MX_IATIMEOUT but for the Windows or ATE client.

opcode should be "1" to set the timeout, and "0" to retrieve it (in seconds). (Since the default opcode is "0" and the timesecs argument is ignored in the case of the retrieve operation, both arguments can be eliminated when retrieving the timeout.)

timesecs is the new timeout value in seconds. (Note that this differs IATIMEOUT parameter in the system INI file, which uses units of minutes.)

Retrieve:

? tab(-10,AG_IATIMEOUT);chr(127);

input "",timeout'seconds

Set:

? tab(-10,AG_TIMEOUT);"1,";timeout'seconds;chr(127);

Comments

Also see IATIMEOUT in the system ini file and MX_IATIMEOUT. Note that in the case of ATE, if the server-side timeout expires, the job will receive error 254, whereas if the client-side timeout expires, the job will experience this as a hang-up (error 250). See Job Terminations for more details on how hang-ups are handled.

History

2011 June, A-Shell 5.1.1221: Command added to A-Shell


Send Keyboard Characters

? tab(-10, AG_SENDKBD); text; chr(127);

AG_SENDKBD (82) is used to send keyboard characters (literal text, virtual function key sequences, control characters using ^ notation). This is mainly useful for sending key clicks to another A-Shell/Windows instance, or from a server to ATE.

History

2010 July, A-Shell 5.1.1187: Command added to A-Shell


Test for Foreground Status

? tab(-10,AG_ISFOREGROUND);chr(127);

input "",FG

AG_ISFOREGROUND (78) tests whether the current instance of A-Shell (or the ATE client) has foreground status (i.e. is the active app). It returns 1 if in foreground, else 0.

Note that as a practical matter (to eliminate the need for an INPUT statement), you'll probably want to call this via the MX_AGWRAPPER command:

MAP1 IS'FG,B,1

xcall MIAMEX, MX_AGWRAPPER, AG_ISFOREGROUND, "", IS'FG


Set / Retrieve SBR Flags

Added December 2012

To retrieve the current flags:

? tab(-10, AG_SBRFLAGS); chr(127);

input "",flags1,flags2

To update flags:

? tab(-10, AG_SBRFLAGS); opcode; flags1; ","; flags2; chr(127);

AG_SBRFLAGS (102) allows dynamic retrieval and updating of SBR= flags from the client workstation (e.g. ATE).

opcode

indicates the operation:

Value | Action
1 | replace existing flags with new flags1 and flags2
2 | ignore flags1; replace flags2 with new values
+4 | Set the specified bits of flags1 and flags2
+8 | Clear the specified bits of flags1 and flags2

flags1, flags2 (b,4)

made up of bits as defined in ashell.def in the SBRF_xxx and SBRF2_xxx symbols.

Note that this command is the ? Tab equivalent of MX_SBRFLG, which see for additional information.

History

2012 December, A-Shell 6.1.1328: Command added to A-Shell


Set ATE Keyboard Hold

Updated July 2015

? tab(-10, AG_HOLDKBD); opcode; chr(127);

AG_HOLDKBD (36) puts the ATE client into "keyboard hold" (aka "local keyboard") mode. For example:

? tab(-10, AG_HOLDKBD); "2"; chr(127);

Opcode 2

opcode "2" locks ATE into the local/hold mode, where it will stay until explicitly released.

Once locked into this mode, no keyboard characters will be transmitted to the server except indirectly via ATE command/response packets. Normally, the server and ATE determine between themselves when ATE should act like a dumb terminal (transmitting all keyboard characters) and when it should act like a client GUI workstation (sending keyboard input to local edit controls only), based on contextual clues.

The lock feature is mainly intended for AMOS and other non-A-Shell servers which cannot detect or communicate such clues. Locking the ATE client into local keyboard mode eliminates problems with type ahead being sent inappropriately to the server, or worse, interrupting/confusing commands sent between the server and client via the keyboard channel.

To remove the lock, use:

? tab(-10,AG_RELEASEKBD);"2";chr(127);

Or, you can also clear it via the Settings menu to clear the Local Kbd Mode checkmark.

Note that once set, the local lock remains set until cleared by one of the above methods, even at the dot prompt. So while the feature may be thus turned on globally in a startup command file, you must be sure to turn it off before exiting to the dot or before performing any non-GUI input operations, including subroutines GET, TINKEY, ACCEPT, the INPUT statement, etc.

Opcode 4

opcode 4 activates a timer in ATE that after 15 seconds of no activity from host (when not otherwise waiting on user actions, such as within INFLD, XTREE, XTEXT, EVENTWAIT, etc.), a message box is displayed warning the user that communication with host appears to be broken, and giving the option to continue waiting or send a cancel (^C).

This can help mitigate a situation where the host application has crashed, leaving ATE in a state which appears to the user to be hung but actually isn't. To activate/deactivate the feature:

? tab(-10,AG_HOLDKBD);"4";chr(127); ! activate

? tab(-10,AG_RELEASEKBD);"4";chr(127); ! deactivate

Timeout monitor is only active when the ATE workstation is in "hold-kbd mode"—i.e. when the AG_HOLDKBD "2" option has been activated or when currently processing an ATE command from the host.

There are situations where it may be normal for ATE to be left waiting for something from the host for longer than 15 seconds. For example, if the host uses XCALL HOSTEX to launch a child task, it could be left waiting indefinitely for a response, leaving ATE in a waiting state. It is the responsibility of the host application to identify such situations and disable the appropriate AG_HOLDKBD mode(s).

When opcode 4 is set, ATE will display a "waiting for <host address>..." message on the session status line (if visible), when appropriate. Even if not visible, the cursor will be change to the wait cursor while in this state. The idea is to give the user some indication of what is going on when output is delayed due be network, application, or server problems, and is somewhat analogous to the similar message displayed by most browsers when waiting on a server response.

The display is updated every one second by adding a dot, and after fifteen seconds, a modeless dialog appears that says:

Server/network not responding. Click CANCEL to send abort request. Or just wait to see if it recovers. [Cancel]

Clicking Cancel sends a Ctrl+C to the host, which may or may not be useful, depending on the situation and how the application responds to Ctrl+C.

As soon as any characters arrive from the server, the dialog is removed and the cursor is restored the normal arrow or I-beam.

History

2015 January, A-Shell 6.1.1399: Add opcode 4.

2013 October, A-Shell 6.1.1364: When the keyboard is locked into local mode with argument "2", ^C no longer clears the local hold. It is simply queued up as would be the case for other keyboard characters, either to be consumed by a local input operation or eventually forwarded to the host when the hold is removed.

2013 May, A-Shell 6.1.1352: Add option "2" to lock ATE into local keyboard mode.


Release ATE Keyboard Release

Updated July 2015

? tab(-10, AG_RELEASEKBD); opcode; chr(127);

AG_RELEASEKBD (49) releases the ATE "keyboard hold" so that it can be used as a dumb terminal again—i.e. so that keyboard characters are transmitted immediately to the server.

The opcode parameter is optional and is normally omitted, in which case the keyboard hold is released, provided it hasn't been locked (via AG_HOLDKBD opcode 2). This command is normally used only internally by A-Shell, as part of the ATE command protocol, although it may be used in situations where the ATE command protocol would normally leave the keyboard in local hold mode but you need to temporarily revert to dumb terminal mode.

In order to remove the locked hold, you must specify opcode "2", e.g. ? tab(-10,AG_RELEASEKBD);"2";chr(127);

See the discussion under Set ATE Keyboard Hold for information on opcode 4.

History

2015 January, A-Shell 6.1.1399: Add opcode 4.


Run Delayed Operation in Background

Added May 2015

? tab(-10, AG_DELAYOP); opcode, delayms, ctlid; tab(-1,127);

AG_DELAYOP (107) allows application to request a delayed operation to be performed in background. Currently this only works for deleting a control, but the range of possibilities may be expanded later.

Parameters

opcode

is the operation code. Currently only CTLOP_DEL (3) is supported.

delayms

is the number of milliseconds to wait before performing the operation.

ctlid

is the id (name or number) of the control to delete.

Comments

If delayms and ctlid are omitted, and a prior delayed operation request is still pending, it will force the operation to take place immediately.

The motivation behind providing this command was mainly to allow applications to create status message panels that go away by themselves after the specified interval. This provides more feedback to the user, without requiring any action on the user's part to acknowledge it, or on the application's part to remove it, or forcing the application to pause to allow the user to read it.

For example, if the user gives the command to post some transactions, the application may want to display a confirmation message "Posting..." that appears for just a couple of seconds and then goes away.

In addition to the command, a wrapper procedure, StsMsgBox() is included in the [907,12] directory of the SOSLIB which facilitates such messages, capitalizing on the new capability if available, and simulating it earlier versions.

History

2015 May, A-Shell 6.1.1411: Function added to A-Shell.


Set / Restore AutoMouse

? tab(-10,AG_MOUSE);"opcode {,flags}";chr(127);

Set or restore the AutoMouse setting.

Parameters

opcode

choices are 7 to set flags or 8 to restore flags.

flags

values from the following table may be combined

Value | Action
&h0001 | Automouse disabled (default is enabled)
&h0002 | Double click sends string only (no CR)
&h0008 | Single click sends string only (no CR)
&h0010 | Singleclick sends string+CR
&h0020 | No single click auto col adjustment
&h0040 | No single click auto row adjustment
&h0080 | Doubleclick sends CR only
&h0100 | tab(-1,158) cursor reporting
&h0200 | Doubleclick sends ESC only
&h0400 | Doubleclick sends string+CR
&h0800 | Don't consider slash a token delimiter


Output Debug Message

? tab(-10, AG_EVTMSG); "opflags, msg"; chr(127);

AG_EVTMSG (57) may be used to send a message to the debug message window on the client workstation. In the TELNET/SSH environment, the workstation must be running ATE.

Parameters

opcode

one of the following:

Value | Action
1 | open the debug message window
2 | msg; opens debug message window if necessary
3 | close the debug message window
514 | output msg, followed by "application paused - doubleclick to resume" and wait for doubleclick

msg

Message to output. Ignored for op 1 and 3.

Comments

The AG_EVTMSG command underlies the implementation of the TRACE and DEBUG Statements.


Get/Set WEBCACHE Options

Added October 2016

? tab(-10, AG_WEBCACHE); op {,flags {,url}}; chr(127);

AG_WEBCACHE (108) gets/sets webcache options from host.

Parameters

op

0 to retrieve and 1 to set. On retrieval, the returned string will contain "flags,url" (current webcache flags and repo url).

flags

is a decimal number containing the WCDF_xxx flags

url

if specified, is the web directory for the repository.

Example

? tab(-10,AG_WEBCACHE);"1,";(WCDF_ENABLE or WCDF_ALL); ",http://www.myrepo.com/app1";chr(127); ! enable; set repo

? tab(-10,AG_WEBCACHE);"1,0";chr(127); ! disable

? tab(-10,AG_WEBCACHE);"0";chr(127); ! retrieve

? tab(-10,AG_WEBCACHE);chr(127); ! same (retrieve)

input line, response$ ! input flags,url

History

2016 October, A-Shell 6.3.1529 and 1531: WEBCACHE function added to A-Shell. The module includes a basic description, the SET.LIT options for WEBCACHE , new functions WEBRUN.LIT, MX_WEBCACHE.SBR and ? tab(-10, AG_WEBCACHE).


Introduction

This document is written and intended for A-Shell developers seeking to take advantage of A-Shell capabilities to create or enhance existing applications. Most of the topics in this document are what we call A-Shell "extensions," which are capabilities or functions or processes that "extend" A-Shell beyond its original AMOS roots. Although using these extensions may increase the difficulty of maintaining backward-AMOS compatibility, there are at least three reasons why you might want to do so anyway.

• Some of A-Shell’s extensions, such as the expanding library of subroutines written in BASIC, provide you the tools to be more productive as a programmer.

• Some extensions, like memory mapping, may help you significantly improve your application’s performance.

• Probably the most powerful reason is that once applications have been moved to the Windows or UNIX/Linux environments, they will start to encounter users who don’t know AMOS, but who expect certain things out of applications that were not commonly available under AMOS. This is especially true under Windows, where users expect applications to support the mouse, graphics, GDI printing, message boxes, etc., but is also true under UNIX/Linux where applications are expected to be able to handle signals, spawn background tasks, interface with the web and other services using socket-based protocols or FIFOs, understand native directories, etc.

To accommodate these needs and interests, A-Shell has built up a variety of tools and other capabilities over the years, and the list is constantly growing. Many of A-Shell's expanded capabilities are in the form of subroutines or system configuration parameters. The information in this section overlaps those topics, and frequently references them, but is organized differently and presented with an emphasis on discussion and examples.

There is no perfect way to organize these topics, and it is doubtful that you would want to read it from front to back, so you may need to rely on a combination of the table of contents, the index, and general browsing to find what you are looking for.


Webcaching

Added October 2016

WEBCACHE is an A-Shell module that auto caches/downloads files from a web directory if not found in the local search path. Downloaded files are cached in the directory %MIAME%/webcache, which is checked first—as in a web browser—to avoid the overhead of unnecessary web accesses.

The feature is referred to under the generic umbrella of "WEBCACHE" and may be enabled and configured via a new SET.LIT option and/or a new MIAMEX function (both described below).

Option flags determine which types of files are subject to the feature. By default it applies to images and any other kind of file operation that currently supports automatic lookup in the cache and permcache directories. Additional file/type options:

Option | Description
PROG | programs (RUN, LIT, SBX)
OPENI | files being opened for sequential input
LOOKUP | files reference by LOOKUP statement or XCALL SIZE

Currently only a single web directory at a time is supported, although it is conceivable that multiple directories and/or trees may be implemented in the future.

The webcache directory, like the permcache directory, is not auto-cleared at the end of the session. But like a typical web browser cache, it can be cleared with a command. Individual files or files matching a pattern can also be cleared. Also, as with a typical web browser, the existence of a file in the cache short-circuits any web lookup for that file; there is no automatic comparison of file sizes or dates between the cached copy and the web copy (because this would completely undermine the performance benefit of the cache). So you have to clear the cache in order to get a refreshed copy from the web repository.

History

2016 October, A-Shell 6.3.1529 and 1531: WEBCACHE function added to A-Shell. The module includes a basic description, the SET.LIT options for WEBCACHE , new functions WEBRUN.LIT, MX_WEBCACHE.SBR and ? tab(-10, AG_WEBCACHE).


Spreadsheet Interface

In A-Shell 6.3.1500, the module AXL ("axle") was added to A-Shell. AXL ("A" from A-Shell and "XL" from Excel or XLS file format) is the licensing and and incorporatation of a third-party library of spreadsheet functions called "LibXL." The purpose of including this library and its extensive tools for spreadsheet generation and manipulation is to make it easier—and in some cases, possible at all—for developers to produce user-friendly spreadsheets for use outside of A-Shell. Spreadsheets may be created by two different means:

CSV2XL: This is a modestly capable implementation of LibXL which allows developers to take existing CSV files—i.e., those they have already been creating using A-Shell—and convert them into full-blown spreadsheets using fonts, colors, headings, number formats, etc. Since probably 90% of users and 90% of spreadsheets use a fairly small set of spreadsheet functions and capabilities, CSV2XL presents a simple means to generate basic spreadsheets. It incorporates seven important functions, and ignores the rest of the library. The idea behind CSV2XL is to provide a tool that is limited in scope—i.e., simple to use and master—which meets most of the needs of most of the users most of the time.

AXL: This is the full spreadsheet function library, packaged appropriately and incorporated into A-Shell. Developers can use LibXL to build spreadsheets with virtually any degree of complexity and using any/all of Excel's vast functionality, and can also read and modify existing spreadsheets. It consists of approximately 125 functions with which developers can specify or change every aspect of a spreadsheet.

Installation Notes

The main requirement for use of the LibXL spreadsheet interface, aside from A-Shell 6.3+, is that the LibXL library be present so that it can be dynamically loaded when needed. The easiest and preferred way to accomplish this is to put the dynamic library in the same directory as the A-Shell executable. Typically this will be handled by the installer, but if you are installing it manually or piecemeal, or trying to debug it, here are the details for each platform:

• Windows and ATE: The library file is libxl.dll, which just has to be present in A-Shell's bin directory. No registration or other explicit initialization or configuration required.

• Linux: The library file name is libxl.so.1, but this is typically a link to the real library file, which is named libxl.so.w.x.y-zzz, where w, x and y identify the library version, e.g. 3.6.5, and -zzz identifies the minimum Linux kernel version for compatibility, e.g. -el4 indicates that it will work with CentOS/RHEL 4 and above. A typical ls -l listing of your libxl files will look something like this:

$ ls -l libxl*

lrwxrwxrwx 1 jack ashell 18 Feb 17 11:20 libxl.so.1 -> libxl.so.3.6.5.el4

-r-xr-xr-x 1 jack ashell 31996112 Feb 16 09:15 libxl.so.3.6.5.el4

Note that the x (executable) flag must be set. If you have only the libxl.so.w.x.y-zzz file, you can create the libxl.so.1 link as follows:

$ ln -s libxl.so.3.6.5.el4 libxl.so.1

For unrestricted operation, you may also need to update your A-Shell license to add the APEX or LIBXL options.


CSV2XL

COMMAND=SBX:CSV2XL{,inifile}

xcall CSV2XL, sts, fspec {, printer, switches, copies, form, inifile }

CSV2XL.SBX converts CSV files to XLS format. It is packaged as a print filter, which means that it can be called automatically via the printer init file COMMAND=SBX:CSV2XL interface, but, like all print filters, can also be called directly from an application. In addition to the calling parameters specified below, the operation of CSV2XL is controlled by the CSV2XL Initialization File and the CSV2XL Directives.

The first syntax above shows CSV2XL being used as a print filter—i.e., within a printer init file. The second shows it being used as an ordinary SBX—i.e., from an application.

For more information on the benefits of creating XLS as opposed to CSV files, and some of the features of CSV2XL, see Benefits of XLS Files and CSV2XL.

Parameters

Parameter | Type | I/O | Description
sts | B,1 | Out | Normally used to signal to the caller whether to it should print the file after processing by the filter. Currently not used since XLS files are generally not printed directly.
fspec | String | In | The source file spec, e.g. xxx.csv
printer | String | In | Not applicable here.
switches | Num | In | Not applicable here.
copies | Num | In | Not applicable here.
form | String | In | Not applicable here.
inifile | String | In | Specifies the INI file to use; default is BAS:CSV2XL.INI.

Subtopics

CSV2XL Initialization File

CSV2XL Directives

Notes on Syntax

Common //XL Parameters

Masks

Examples

Benefits of XLS Files and CSV2XL

Number Formats


CSV2XL Initialization File

Many of CSV2XL's options are configurable via an initialization file, either the default BAS:CSV2XL.INI or another file specified in the calling interface. The options are mostly either self-explanatory or explained by way of comments in the sample CSV2XL.INI file included with the release, reproduced below:

;CSV2XL.INI - Config file for CSV2XL.SBX

[FORMAT]

;OutputFormat choices: XLS (default), XLSX

OutputFormat=XLS

;Headers Text color (Use COLOR_xxx from libxl:libxl.def; default=COLOR_BLACK)

HeadersFG=COLOR_BLACK

;Headers background color (default=COLOR_GRAY25)

HeadersBG=COLOR_WHITE

;Headers alignment (default=ALIGNH_CENTER)

HeadersAlignH=ALIGNH_LEFT

;Headers bold option (default=1)

HeadersBold=0

;Headers font size option (default=DefaultFontSize)

HeadersFontSize=10

;Headers font (default=DefaultFont)

HeadersFont=Broadway;bg color for totals (if AddTotals; default=COLOR_GRAY25)

TotalsBG=COLOR_GRAY25

;regex pattern applied to col titles to force the column to be treated as text (zip, part #, etc.)

;Example: zip|(part *(no|num|#))|phone

; matches any title containing "zip", "phone", or "part" followed by optional space and then "no","num", or "#"

; matching is case insensitive, not anchored (use ^ and $ for start/end anchoring)

ColTitleTextRegex=zip|(part *(no|num|#))|phone|sku

;Headers horizontal alignment (default = ALIGNH_CENTER)

HeadersAlignH=ALIGNH_LEFT

;Headers bold option (default=1)

HeadersBold=0

;Headers font size option (default=DefaultFontSize)

HeadersFontSize=9

;Headers font (default=DefaultFont)

HeadersFont=Garamond

[DATA]

;AddTotals: 1=yes (add line and auto-total any numeric col)

AddTotals=1

;Headers=0 (treat first line as data); =1 (treat as headers) (default=1)

Headers=1

[POST]

Overwrite=0

SendToDir=

AppendSeqno=1

SaveToDir=

SendToPC=0

Launch=1


CSV2XL Directives

To assert greater control over details of the output file formatting, you may optionally insert //XL directives into the CSV file. These should be at the top, before any data lines, except in the case of the //XL,SetRow directive, which may be inserted anywhere above the affected row(s).

The syntax for the //XL directives is a bit tricky, and differs from normal A-Shell conventions. See Notes on Syntax.

//XL,SetDefaultFont{,fontname=<fontface>}{,fontsize=<pointsize>}

Establish the default font face and name to be used by the spreadsheet app.

Example:

//XL,SetDefaultFont,fontname=Courier New,fontsize=12

//XL,DefineFont {fontid=}<fontid>, {name=<name>} {,size=<pointsize>} {,color=COLOR_xxx}, {Common //XL Parameters}

Define a font and give it an identifier which can then be used in a subsequent DefineFormat directive. This is only necessary when you want to use the same font in multiple formats, columns or rows. Otherwise, you can specify the font attributes directly when defining the format or setting the column or row attributes.

Examples:

//;Define bold green font, assign fontid “bold_green”

//XL,DefineFont,fontid=bold_green,bold,COLOR_GREEN

//;Define 14 Courier font, name it “courier14”

//XL,DefineFont,fontid=courier14,fontsize=14, fontname=Courier New

//XL,DefineFormat, {formatid=}<formatid>, {Common //XL Parameters}

Define a format and give it an identifier which can then be used in a subsequent SetCol and SetRow directives. This is only necessary when you want to use the same format in multiple columns or rows. Otherwise, you can specify the format attributes directly in the SetCol and/or SetRow directives.

Examples:

//;Define format named “fmtx” using bold_green font

//XL,DefineFormat,formatid=fmtx,fontid=bold_green,ALIGNH_CENTER

//;Define format named “fmtpink” with pink bg, bold violet text

//XL,DefineFont,formatid=fmtpink, FILLPATTERN_SOLID, patternfgc=COLOR_PINK, bold, fontcolor=COLOR_VIOLET

//XL,SetCol, {colfirst=}<##>, {collast=<##>}, {width}, {Common //XL Parameters}

Set attributes for a column or set of columns. Note that you have the option of referencing a previously defined format via the formatid=<formatid> parameter, in which case you should not specify any of the other font or format-related parameters. (A format includes a font.) Otherwise, you can specify any of the individual font and/or format parameters to effectively define the font and format on the fly.

Note that if the collast parameter is omitted, it is assumed to be the same as colfirst. If the first parameter is not named, it is assumed to be colfirst.

The SetCol directive(s) should be specified at the top of the file, before any data.

Examples:

//;Set column 3 to bold

//XL,SetCol,3,bold

//;Set columns 4-6 to have yellow background

//XL,SetCol,colfirst=4,collast=6,FILLPATTERN_SOLID, patternfgc=COLOR_YELLOW

//;Set column 7 to use predefined format name fmtspecial

//XL,SetCol,colfirst=7,formatid=fmtspecial

//XL,SetRow, {row = ##}, {height = ##}, {Common //XL Parameters}

Set attributes for a row. You may specify a row by number using the row=## parameter; the first row of the spreadsheet is considered row 1, whether it contains headings or data. It should be specified before the affected data rows. If the row parameter is omitted, the directive affects the next row to be output. Height is set in typographical points.

//XL,SetINI,<inifile>

Establishes the INI file, overriding the one specified in the printer initialization file or XCALL. For example:

//XL,SetINI,BAS:CUSXLS.INI

//XL,AddSheet {,srcbook=xxx.xls} {,dstbook=yyy.xls} {,sheetname=zzz}{,index=1}

Allows you to define the name of the sheet, and/or add it to an existing workbook, and/or change the name of the output workbook. All four parameters are optional, but you need at least one to make any sense:

Parameter | Description
srcbook= | Specifies the source workbook to which you are appending the sheet, e.g. srcbook=mybook.xls Default is to create a new book.
dstbook= | Specifies the destination workbook to save the result as. Can be same as srcbook. Default is the original CSV file (with .xls extension, and optionally with a -# sequence number appended to the name – see AppendSeqno in [Post] section of the INI file.))
sheetname= | Specifies the name you want to assign to the sheet. Default is "sheet1". Note: must be unique within the workbook!
index=# | Causes the new sheet to be inserted at position #. Default is to append to the end.


Notes on Syntax

Here are some notes on the somewhat exotic argument syntax of the /XL directives in CSV2XL.

• To insert a comment in the CSV file, start the line with //; (two slashes followed by a semicolon). This is consistent with the syntax for comments with normal GDI directives, e.g.:

//; This is a comment

• Because there are so many potential parameters and most of them are optional, they have been assigned names. This allows you to specify only the ones you are interested in setting, and in any order. So for example, here we define a font by specifying the fontname and color, but not the size or any other attributes:

//XL,DefineFont,fontid=myfont,fontname=Courier New,fontcolor=COLOR_BLUE

• Because some of the attribute values have symbolic names (e.g. COLOR_BLUE) which are more descriptive than the numeric values, you can use the symbolic names—as in the example above—or the corresponding numeric values (defined in libxl.def).

• Because many of those attribute value symbolic names only apply to a single attribute type, e.g. NUMFMT_xxx only applies to the format parameter numfmtid, you can leave off the name= part of the name=value pair, e.g.

//XL,DefineFormat,formatid=fmt_pct,NUMFMT_PERCENT,fontid=myfont

is equivalent to

//XL,DefineFormat,formatid=fmt_pct,numfmtid=NUMFMT_PERCENT,fontid=myfont

• Parameters with Boolean attributes like bold, italic, etc., are all assumed FALSE (0) unless specified. Also, so there is no real need to say "wrap=1". Just say "wrap".

• Fonts and formats both have internal identifiers or handles, which can be shared between cells. To be more precise, fonts may be shared by formats, and formats may be shared by columns or rows. Thus the DefineFont directive assigns the resulting font to the fontid specified in the fontid= clause, which may then be referenced in a subsequent DefineFormat statement (as in the above example). The DefineFormat directive assigns the resulting format handle to the formatid specified in the formatid= clause (fmt_pct in the above example), which can then be used to assign it to one or more columns, e.g.

• The three part process described in the previous point—define a font, define a format using the font, then associate the format with columns—is logical but tedious and verbose in the simple case where you just want to apply some kind of formatting to a single column, or different formatting to different columns, where there is little or no opportunity to share formats or fonts. In that case, you can just do it all in the SetCol (or SetRow) directive, e.g.:

//XL,SetCol,9,mask="###,###.00",fontcolor=COLOR_VIOLET,italic

The above example creates a numeric format using the specified mask and assigns column 9 to use it and to also use violet colored italic text. Internally this generates DefineFont and DefineFormat directives, but the handles are lost, so you can't re-use them in subsequent directives. But there is nothing stopping you from specifying the same attributes in additional SetCol or SetRow directives.

• Some directives have an obvious or natural first parameter whose name can therefore be omitted. For example, the obvious/natural first parameter to the Setrow directive is the row number. The obvious/natural first parameter to the DefineFont and DefineFormat directives are the fontid and formatid to be assigned. In the case of the SetINI directive, the only parameter is the ini file spec, so there is no point in even defining a name for that parameter. For example:

//; following two are equivalent

//XL,DefineFont,fontid=hdrfont,name=Broadway

//XL,DefineFont,hdrfont,name=Broadway

//; following two are equivalent

//XL,SetCol,6,formatid=fmt_pct

//XL,SetCol,colfirst=6,formatid=fmt_pct


Common //XL Parameters

The following table lists the parameters that can be used with several of the //XL directives. Note that

• You must list only the parameters you want to use. Simply omit those you don't wish to set.

• See Notes on Syntax.

• Some of the links below connect to external webpages that contain definitions for multiple parameters. Scroll down the page as needed.

• Numbers in parentheses (3) refer to the notes which immediately follow the table

 |  | Available For Use In
Name | Value | SetRow | SetCol | DefineFormat | DefineFont
alignh (1) | ALIGNH_xxx | x | x | x |
alignv (1) | ALIGNV_xxx | x | x | x |
bold | Boolean | x | x | x | x
bordercolor | COLOR_xxx | x | x | x |
borderstyle (1) | BORDERSTYLE_xxx | x | x | x |
fillpattern (1) | FILLPATTERN_xxx | x | x | x |
fontid | Alphanumeric name you assign so you can refer to it later | x | x | x | x
fontcolor | COLOR_xxx | x | x | x | x
fontname | Font name; eg "Arial", "Courier New" | x | x | x | x
fontsize | Integer number of points | x | x | x | x
formatid | Alphanumeric name you assign so you can refer to it later | x | x | x |
hidden | Boolean | x | x | x |
indent | Integer 0 - 15 | x | x | x |
italic | Boolean (3) | x | x | x | x
locked | Boolean (3) | x | x | x |
mask | mask | x | x | x |
numfmtid (1) | NUMFMT_xxx | x | x | x |
patternbgc (2) | COLOR_xxx | x | x | x |
patternfgc (2) | COLOR_xxx | x | x | x |
rotation | degrees (4) | x | x | x |
shrinkfit | Boolean (3) | x | x | x |
strikeout | Boolean (3) | x | x | x | x
underline | Boolean (3) | x | x | x | x
wrap | Boolean (3) | x | x | x |

Notes

1 Because the values for these parameters are uniquely associated with a specific parameter ("ALIGNH_LEFT" or "BORDERSTYLE_THICK" or "FILLPATTERN_GRAY25"), it is not necessary to name the parameter. In other words, ALIGNH_LEFT by itself on the syntax line is equivalent to ALIGNH=ALIGNH_LEFT.

2 Counter-intuitive setting: To set the "normal" background color of a cell, set fillpattern to FILLPATTERN_SOLID and patternfgc to the color. The patternbgc parameter applies only to complex (non-solid) fill patterns.

3 All parameters Boolean values (a) default to no and therefore (b) do not need to be mentioned except to turn on, and (c) do not require a value (Y or 1) to turn on; just naming the parameter on the syntax line ("Italic") turns it on.

4. Rotation values 0-90 specify counterclockwise rotation in degrees. Values 91-180 specify 1-90 degree rotation clockwise. 255 indicates vertical.


Masks

Custom format string guidelines

Up to four sections of format codes can be specified. The format codes, separated by semicolons, define the formats for positive numbers, negative numbers, zero values, and text, in that order. If only two sections are specified, the first is used for positive numbers and zeros, and the second is used for negative numbers. If only one section is specified, it is used for all numbers. Four sections example:

#,###.00_);[Red](#,###.00);0.00;"sales "@

The following table describes the different symbols that are available for use in custom number formats.

Symbol | Description and result
0 | Digit placeholder. For example, if the value 8.9 is to be displayed as 8.90, use the format #.00
# | Digit placeholder. This symbol follows the same rules as the 0 symbol. However, the application shall not display extra zeros when the number typed has fewer digits on either side of the decimal than there are # symbols in the format. For example, if the custom format is #.##, and 8.9 is in the cell, the number 8.9 is displayed.
? | Digit placeholder. This symbol follows the same rules as the 0 symbol. However, the application shall put a space for insignificant zeros on either side of the decimal point so that decimal points are aligned in the column. For example, the custom format 0.0? aligns the decimal points for the numbers 8.9 and 88.99 in a column.
. (period) | Decimal point.
% | Percentage. If the cell contains a number between 0 and 1, and the custom format 0% is used, the application shall multiply the number by 100 and adds the percentage symbol in the cell.
, (comma) | Thousands separator. The application shall separate thousands by commas if the format contains a comma that is enclosed by number signs (#) or by zeros. A comma that follows a placeholder scales the number by one thousand. For example, if the format is #.0,, and the cell value is 12,200,000 then the number 12.2 is displayed.
E- E+ e- e+ | Scientific format. The application shall display a number to the right of the "E" symbol that corresponds to the number of places that the decimal point was moved. For example, if the format is 0.00E+00, and the value 12,200,000 is in the cell, the number 1.22E+07 is displayed. If the number format is #0.0E+0, then the number 12.2E+6 is displayed.
$-+/():space | Displays the symbol. If it is desired to display a character that differs from one of these symbols, precede the character with a backslash (\). Alternatively, enclose the character in quotation marks. For example, if the number format is (000), and the value 12 is in the cell, the number (012) is displayed.
\ | Display the next character in the format. The application shall not display the backslash. For example, if the number format is 0\!, and the value 3 is in the cell, the value 3! is displayed.
* | Repeat the next character in the format enough times to fill the column to its current width. There shall not be more than one asterisk in one section of the format. If more than one asterisk appears in one section of the format, all but the last asterisk shall be ignored. For example, if the number format is 0*x, and the value 3 is in the cell, the value 3xxxxxx is displayed. The number of x characters that are displayed in the cell varies based on the width of the column.
_ (underline) | Skip the width of the next character. This is useful for lining up negative and positive values in different cells of the same column. For example, the number format _(0.0_);(0.0) aligns the numbers 2.3 and -4.5 in the column even though the negative number is enclosed by parentheses.
"text" | Display whatever text is inside the quotation marks. For example, the format 0.00 "dollars" displays 1.23 dollars when the value 1.23 is in the cell.
@ | Text placeholder. If text is typed in the cell, the text from the cell is placed in the format where the at symbol (@) appears. For example, if the number format is "Bob "@" Smith" (including quotation marks), and the value "John" is in the cell, the value Bob John Smith is displayed.
0 | Digit placeholder. For example, if the value 8.9 is to be displayed as 8.90, use the format #.00

Specify colors

To set the text color for a section of the format, type the name of one of the following eight colors in square brackets in the section. The color code must be the first item in the section.

[Black]

[Green]

[White]

[Blue]

[Magenta]

[Yellow]

[Cyan]

[Red]

Instead of using the name of the color, the color index can be used, like this [Color3] for Red. Valid numeric indexes for color range from 1 to 56, which reference by index to the legacy color palette.

Specify conditions

To set number formats that will be applied only if a number meets a specified condition, enclose the condition in square brackets. The condition consists of a comparison operator and a value. Comparison operators include: = Equal to; > Greater than; < Less than; >= Greater than or equal to, <= Less than or equal to, and <> Not equal to. For example, the following format displays numbers that are less than or equal to 100 in a red font and numbers that are greater than 100 in a blue font.

[Red][<=100];[Blue][>100]

If the cell value does not meet any of the criteria, then pound signs ("#") are displayed across the width of the cell.

Dates and times

To Display | As | Use This Code
Months | 1-12 | m
Months | 01-12 | mm
Months | Jan-Dec | mmm
Months | January-December | mmmm
Months | J-D | mmmmm
Days | 1-31 | d
Days | 01-31 | dd
Days | Sun-Sat | ddd
Days | Sunday-Saturday | dddd
Years | 00-99 | yy
Years | 1900-9999 | yyyy
Hours | 0-23 | h
Hours | 00-23 | hh
Minutes | 0-59 | m
Minutes | 00-59 | mm
Seconds | 0-59 | s
Seconds | 00-59 | ss
Time | 4 AM | h AM/PM
Time | 4:36 PM | h:mm AM/PM
Time | 4:36:03 P | h:mm:ss A/P
Time | 4:36:03.75 | h:mm:ss.00
Elapsed time | 1:02 | [h]:mm
Elapsed time | 62:16 | [mm]:ss
Elapsed time | 3735.80 | [ss].00

Examples

To Display | As | Use This Code
1234.59 | 1234.6 | ####.#
8.9 | 8.900 | #.000
.631 | 0.6 | 0.#
12 1234.568 | 12.0 1234.57 | #.0#
44.398 102.65 2.8 | 44.398 102.65 2.8 | ???.???
5.25 5.3 | 5 1/4 5 3/10 | # ??/??
12000 | 12,000 | #,###
12000 | 12 | #,
12400000 | 12.4 | 0.0,,


Examples

AddSheet

Assume these two files:

File1.csv:

//XL,AddSheet,dstbook=test.xls,sheetname=test sheet1

Name,Age,Sex,...

<data>

File2.csv:

//XL,AddSheet,srcbook=test.xls,dstbook=test.xls,sheetname=test sheet2

Account#,Address,Amount...

<data>

Execution:

.PRINT CSV2XL=FILE1.CSV ! creates TEST.XLS with sheet named "test sheet1"

.PRINT CSV2XL=FILE2.CSV ! loads TEST.XLS, adds new sheet "test sheet2", saves it as TEST.XLS

The specified new sheet will be appended to the end of the workbook, and the existing file will be overwritten.


Benefits of XLS Files and CSV2XL

Although most spreadsheet applications can open CSV files directly, there are a number of advantages to using CSV2XL to create an XLS file. These include:

• XLS is easier to use for the file recipient. By creating the XLS file under application control, you eliminate the uncertainties and the possible need to answer questions that may arise when the recipient of the file imports it into a spreadsheet application.

• CSV files cannot contain any formatting whereas XLS files can, and the CSV2XL routine provides various options for automatic and manual formatting to be applied.

• CSV2XL can automatically highlight the column headers and add column totals.

• CSV2XL can scroll-lock (aka split) the top line (headers) and/or first column so that they don’t scroll along with the rest of the rows and columns.

• CSV2XL has logic to properly identify columns that should be treated as strings (left justified, leading zeros retained, e.g. zip codes) whereas the typical CSV importer would treat them as numbers.

• CSV2XL recognizes dates and converts them to XLS internal date format.

• CSV2XL automatically sets the column widths appropriately for the data.

• CSV2XL allows you to specify a default font.

• The output file name may be serialized with a numeric suffix (eg. abc-1.xls, abc-2.xls, etc.)

• For more advanced formatting, you can insert //XL directives at the top of the file to specify formats to be applied to individual columns and/or rows.

• Options are provided for post-processing of the XLS file, such as transferring to the local workstation or launching the spreadsheet application.


Number Formats

Symbol | Value | Description | Example
NUMFMT_GENERAL | 0 | general format |
NUMFMT_NUMBER | 1 | general number | 1000
NUMFMT_NUMBER_D2 | 2 | number with decimal point | 1000
NUMFMT_NUMBER_SEP | 3 | number with thousands separator | 100,000
NUMFMT_NUMBER_SEP_D2 | 4 | number with decimal point and thousands separator | 100,000.00
NUMFMT_CURRENCY_NEGBRA | 5 | monetary value, negative in brackets | (1000$)
NUMFMT_CURRENCY_NEGBRARED | 6 | monetary value, negative is red in brackets | (1000$)
NUMFMT_CURRENCY_D2_NEGBRA | 7 | monetary value with decimal point, negative in brackets | ($1,000.00)
NUMFMT_CURRENCY_D2_NEGBRARED | 8 | monetary value with decimal point, negative is red in brackets | ($1,000.00)
NUMFMT_PERCENT | 9 | percent value, multiply the cell value by 100 | 75%
NUMFMT_PERCENT_D2 | 10 | percent value with decimal point, multiply the cell value by 100 | 75.00%
NUMFMT_SCIENTIFIC_D2 | 11 | scientific value with E character and decimal point | 1.00E+02
NUMFMT_FRACTION_ONEDIG | 12 | fraction value, one digit | 10 1/2
NUMFMT_FRACTION_TWODIG | 13 | fraction value, two digits | 10 23/95
NUMFMT_DATE | 14 | date value, depends on OS settings | 3/11/2009
NUMFMT_CUSTOM_D_MON_YY | 15 | custom date value | 11-Mar-09
NUMFMT_CUSTOM_D_MON | 16 | custom date value | 11-Mar
NUMFMT_CUSTOM_MON_YY | 17 | custom date value | 9-Mar
NUMFMT_CUSTOM_HMM_AM | 18 | custom date value | 8:30 AM
NUMFMT_CUSTOM_HMMSS_AM | 19 | custom date value | 8:30:00 AM
NUMFMT_CUSTOM_HMM | 20 | custom date value | 8:30
NUMFMT_CUSTOM_HMMSS | 21 | custom date value | 8:30:00
NUMFMT_CUSTOM_MDYYYY_HMM | 22 | custom datetime value | 3/11/2009 8:30
NUMFMT_NUMBER_SEP_NEGBRA | 37 | number with thousands separator, negative in brackets | -4,000
NUMFMT_NUMBER_SEP_NEGBRARED | 38 | number with thousands separator, negative is red in brackets | -4,000
NUMFMT_NUMBER_D2_SEP_NEGBRA | 39 | number with thousands separator & decimal point, negative in brackets | -4,000.00
NUMFMT_NUMBER_D2_SEP_NEGBRARED | 40 | number with thousands separator & decimal point, negative is red in brackets | -4,000.00
NUMFMT_ACCOUNT | 41 | account value | 5,000
NUMFMT_ACCOUNTCUR | 42 | account value with currency symbol | AA$ 5,000
NUMFMT_ACCOUNT_D2 | 43 | account value with decimal point | 5,000.00
NUMFMT_ACCOUNT_D2_CUR | 43 | account value with currency symbol and decimal point | AA$ 5,000.00
NUMFMT_CUSTOM_MMSS | 44 | custom time value | 30:55:00
NUMFMT_CUSTOM_H0MMSS | 45 | custom time value | 20:30:55
NUMFMT_CUSTOM_MMSS0 | 46 | custom time value | 30:55.0
NUMFMT_CUSTOM_000P0E_PLUS0 | 47 | custom value | 1.52E+04
NUMFMT_TEXT | 48 | text value | any text


AXL

Introduced in A-Shell 6.3, AXL provides a fully-featured application interface for reading and writing Excel spreadsheet (XLS) files. It is packaged as a collection of A-ShellBASIC functions and procedures built around a third-party library called LibXL. Although the individual functions are all relatively straightforward and intuitive, because there are so many of them (125+), rather than redundantly document them all here, instead we’ll focus on providing overview, tutorial, index, examples, etc., and rely on API source code (libxl.bsi) ror the function-level reference documentation.

Subtopics

AXL Introduction

Progamming Notes

Examples

Utilities


Library Class Overview

The underlying library is object-oriented, consisting of four classes:

Class | Description
Book | Each instance represents a workbook; methods including creating a workbook, loading one from a file, saving it to file, adding sheets, defining fonts and formats, etc.
Sheet | Each instance represents a worksheet; methods and properties relating to rows, columns, cells.
Font | Each instance defines an individual font; a font instance may be shared by multiple instances of the Format class.
Format | Each instance defines a combination of all the non-data attributes associated with cells—color, alignment, borders, font, etc.

A-Shell/BASIC is not object-oriented per se, but generally follows the class orientation of the underlying library. You create instances of the various classes, which are identified by handles, which are then passed to the method functions to identify the instance of the class being operated on. Module-level (libxl.bsi) private data is used to keep track internally of the handles and various associated properties.

Creating a spreadsheet from scratch typically involves the following:

• ++include libxl:libxl.bsi

• Map variables for the various Book, Sheet, Format and Font objects you’ll be needing (using the special types BookHandle, SheetHandle, FormatHandle and FontHandle), e.g.

Map1 handles

Map2 book1,BookHandle,

Map2 sheet1,SheetHandle

Map2 fmt’header,FormatHandle

Map2 fmt’total,FormatHandle

Map2 font’bold,FontHandle

• Load the library, e.g.:

Call Fn’LibXL’Load(dlflags)

• Create an instance of the Book class, e.g.:

book1 = Fn’LibXL’CreateBook()

• Create one or more Sheet instances, e.g.:

sheet1 = Fn’LibXL’AddSheet(“Sheet1”, hbook=book1)

• Create zero or more Font instances, assigning attributes such as facename, size, color, e.g.

font’bold = Fn’LibXL’AddFont’SetAttributes(size=16, bold=1)

• Create zero or more Format instances, assigning attributes such as borders, alignment, font, e.g.

fmt’header = Fn’LibXL’AddFormat’SetAttributes(hfont=font’bold, alignh=ALIGNH_CENTER,…)

• Use functions in the Sheet class to set column/row dimensions, add pictures, and write cells. (Formats may be associated with the cells when writing the data or by separate operations.)

Call Fn’LibXL’SheetSetCol(hsheet=sheet1, colfirst=1, width=20)

Call Fn’LibXL’SheetWrite(row=1,col=2,”Hello World”, hformat=fmt’header)

• Save the Book instance as a file, e.g.

Call Fn’LibXL’SaveBook(“hello.xls”, hbook=book1)

• Release the book (frees resources)

call LibXL'ReleaseBook()

• Unload the library

call Fn'LibXL'Unload()


Hello World

Here is spreadsheet version of the venerable Hello World program illustrating an extremely simple but working example. Note that since the example uses only one workbook and one sheet, there is no need to deal with handles for them. And to maximize simplicity, we use the default font and format, so there is no need for any of those handles either.

Program hello,1.0(100) ! hello world spreadsheet example

++include ashinc:ashell.def

++include libxl:libxl.bsi

call Fn'LibXL'Load(dlflags=DLF_STATUS_BASERR or DLF_SYSERR_BASERR)

if Fn'LibXL'CreateBook() then

if Fn'LibXL'AddSheet("Sheet1") then

call Fn'LibXL'Write(1, 1, “Hello World”)

endif

call Fn'LibXL'SaveBook(“hello.xls”)

call LibXL'ReleaseBook()

endif

call Fn'LibXL'Unload()

The program loads the LibXL library, creates an empty book, adds a sheet to it, writes “Hello World” into the first column of the second row (using 0 based counting), then saves the book to the file hello.xls. Finally it cleans up by releasing the resources associated with the book and unloading the library. It doesn’t launch the spreadsheet application but you could do so with MX_SHELLEX or Fn’Shell’Exec() from SOSFUNC:FNSHELLEX.BSI.


Installation

The complete package consists of the following parts, some or all of which may need to be downloaded/installed manually:

External library: The low-level code is packaged as a single external library file, which can be downloaded manually from the MicroSabio LibXL download directory.

For Windows, the file is libxl.dll, and can be just dropping in the A-Shell bin directory (where the ashw32.exe file is).

For Linux, the file is libxl.so.#.#.#.xxx, which can also be dropped into the A-Shell bin directory (where the ashell executable is). Then you must create a symbolic link to it named /usr/lib/libxl.so.1, e.g.:

$ sudo ln -s /vm/miame/bin/libxl.so.3.7.2.lnx /usr/lib/libxl.so.1

You can test that the library itself has all of its prerequisites with the ldd command:

$ ldd /usr/lib/libxl.so.1

linux-gate.so.1 => (0x00818000)

libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00279000)

libm.so.6 => /lib/libm.so.6 (0x00161000)

libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x003c3000)

libc.so.6 => /lib/libc.so.6 (0x00506000)

/lib/ld-linux.so.2 (0x004e9000)

LIBXL: ersatz directory: define an ersatz device LIBXL: which points to the directory where you install the LIBXL API files. This directory is typically [908,68], and is included (as [908,68]) in the MicroSabio EXLIB Repository. (You might was well just download the entire library, updating the existing one you may already have installed.)

SOSFUNC: and ASHINC: Several files in these standard ersatz directories, typically [907,10] and [907,16] are used by the LibXL module and almost certainly require updating. Since they are both part of the MicroSabio SOSLIB Repository, the easiest way to satisfy this requirement is to download/update the entire set of [907,xxx] directories.

A-Shell 6.3.15xx: LibXL absolutely requires 6.3 as a minimum, and for maximum compatibility (as of January 2017) you should have 6.3.1542.

Compiler edit 793: If using APN, you should ideally have the 793 version of the standalone compiler. You’ll also need to update your compil command line in APN to include the -p or -px switch (see next section for details).

Having completed the above, you should be able to compile and run one of the sample programs, e.g.

.LOG LIBXL:

.COMPIL TSTACB/X:2/M/P

.RUN TSTACB


Compiling

The LibXL API wrapper module, LIBXL.BSI, uses named parameters and thus requires the compiler /P switch. Since it contains many functions that may not be used in any particular program, your RUN modules will be much smaller if you use the extended version of the /P switch, /PX. For APN and the standalone external compiler (compil.exe), use the -p or -px switch. Examples:

From the dot prompt:

.COMPIL TSTACB/X:2/M/PX

From within APN:

"c:\vm\APN\compil.exe" -ini c:\vm\miame\miame.ini -w:4000 -x:2 -m -px -lf -lsm -so "C:\vm\miame\exlib63\908068\tstacb.bp"


Return Status

Consistent with the underlying LibXL library, most of the functions return non-zero for success. For functions that return object handles, e.g. book, sheet, etc., the return value is the handle. For "get property" or "get value" functions, the return value is the property or value. For other "set property" or other functions with no inherent return value, the return value is a boolean, i.e.True for success. The actual error/status codes associated with a failed call may be retrieved with Fn'LibXL'Get'Status(), although this is usually not necessary; see ERROR HANDLING.


Error Handling

Three general classes of errors are possible (all of which will result in the function call returning zero) :

• Errors within the DYNLIB interface mechanism, such as failure to load the target library, find the target function, parameter errors, etc. These are recorded in the dlCtl.status member using DYNLIBE_xx values (arbitrary/specific to DYNLIB). Use Fn'libXL'Get'Status() to retrieve/dispay.

• OS-level errors within the target function or library. For example, invalid path, or file protection errors. These errors are defined by the OS/platform (Windows system error codes for Windows, errno values for UNIX). Use Fn'LibXL'Get'Syserr() to retrieve/display.

• Library/logic errors, i.e. functions that fail for reasons that neither DYNLIB nor the OS can detect. These are indicated by returning 0 for the function value (matching the underlying LibXL library behavior). You can use Fn'LibXL'GetErrorMessage() following one of these errors to get further details.

This LibXL library wrapper provides various services/options to simplify error handling to make application level code simpler. These are all set via flags passed to the Fn'LibXL'Load() function, which are defined in ashinc:dynlib.def.

LibXL’Load flags | Description
DLF_STATUS_BASERR | Generate BASIC error 65 on abnormal status conditions within dynamic library interface
DLF_SYSERR_BASERR | Generate BASIC error 65 on OS-related system errors
DLF_LOG_ERRORS | Write status/syserr errors to ashlog
DLF_PRINT_ERRORS | Print status/syserr errors to screen
DLF_MSGBOX_ERRORS | Report status/syserr errors via MSGBOX

The first two options (triggering a BASIC error 65) are ideal when errors are not expected, since you only have to put your error logic in one place in the error trap. The others relate to how errors are reported, also sparing the application from having to manage that aspect of error reporting.


Strings and Special Characters

A-Shell programs normally use ANSI strings (one byte per character), with the lower 128 characters using the standard ASCII encoding, and the upper 128 characters using the Latin1 encoding. The Excel file format, on the other hand, internally uses the Windows Wide character format (two bytes per character, aka U16). So it has no trouble supporting the accented and other special characters, but they do have to be converted from ANSI format to wide (or U16). The LibXL API will accomplish this for you, but there are variations of how this can work depending on the platform and flags you can set.

In the Windows environment the LibXL API converts the strings you pass it to wide / U16 format and then passes them to the external library using the « W » functions. The conversion is reversed for any return strings.

In the Linux environment, it is more common for applications requiring special characters to use UTF8 representation (one to five bytes per character), even though the spreadsheet internal file format still uses the U16 format. Depending on the DLF_xxx options you set, the LibXL API will either leave your strings alone, passing them as-is, or it will first convert them to UTF8 before passing them to the LibXL library.

In order for these conversions to work properly in each environment, and to allow your compiled programs to run in either environment without recompiling, you must set the DLF_ASCII or DLF_ANSI flag before calling the Fn’Load’LibXL function. (For simplicity, DLF_ANSI is defined as zero and thus is the default.)

LibXL’Load flags | Description
DLF_ANSI | Application strings assumed to be in ANSI format (i.e. Latin1, one byte per character). They will be converted to/from wide format for Windows, and UTF8 for Linux. (Requires A-Shell 6.3.1542+ for Linux)
DLF_ASCII | Application strings are assumed to use only the ASCII values 0-127, and thus require no conversion for special characters. They will still be converted to wide format for Windows, but will be passed as-is in Linux.
DLF_UTF8 | Application strings are assumed to already be in UTF8 format. They will be converted from UTF8 to wide for Windows, and passed as is for Linux.

For example:

dlflags = DLF_STATUS_BASERR or DLF_STATUS_BASERR

dlflags = dlflags or DLF_PRINT_ERRORS

dlflags = dlflags or DLF_ASCII ! app uses only ASCII chars

call Fn'LibXL'Load(dlflags=dlflags)


Handles

The underlying library is divided into these four classes, and for each class instance there is a corresponding handle that must be passed to the class functions. The handles are 32 bit raw address values (B,4 with deftype aliases defined in libxl.def) which must be treated with care, i.e. should never be manipulated directly in BASIC. Although nearly all the functions internally require the corresponding handle to the instance of the class, in many cases it is implicit and the library can supply the handle without the application's help. For example, once you create a workbook, from that point forward that book will be the default for any further operations that require a book handle, so the application doesn't need to redundantly specify it. But if you are working with two books, then you'll need to specify the proper book handle whenever switching the context from one to the other. Likewise for sheets, formats, and fonts. For all functions that take optional handle parameters, the handle parameter will come after the mandatory parameters, and may be specified by name using the standard handle parameter names "hbook", "hsheet", "hformat", "hfont", "hinitsheet", etc. So for example:

hBook1 = Fn'LibXL'CreateBook(type) ! 1st book instance

hBook2 = Fn'LibXL'CreateBook(type) ! 2nd book instance

! add sheet to 2nd book (default)

hSheet2A = Fn'LibXL'AddSheet("sheet1")

! add sheet to 1st book (explicit)

hSheet1A = Fn'LibXL'AddSheet("sheet1",hbook=hBook1)

When the handle is mandatory, it will be the first parameter.


Function Naming

All the routines meant for application use are either functions with Fn'LibXL' prefixes or procedures with LibXL' prefixes. (Hard to type, but in APN, just use the Ctl+Space auto-complete feature, e.g. "SetAttr" followed by Ctrl+space.) Consistent with the underlying library, the functions are divided into Book, Sheet, Format, and Font classes, with the requirements of the object/class orientation of the library satisfied by supplying a handle to the instance of the class whose method/function is being called. The general function naming convention is Fn'LibXL'<class><verb><objects>, e.g. "Fn'LibXL'FontSetAttributes()".

Functions named this way (with one of the class names immediately following the LibXL' prefix) expect the first argument to be the handle to the corresponding class instance, e.g.

Fn'LibXL'FontSetAttributes(hfont, size=16)

HOWEVER, since 90%+ of the applications using this library are likely to use only one book (or one book at a time), it seems excessive to include "Book" in the name of each book function, as well as require that the first argument passed be a handle to that same book object. Instead, we've dropped the leading "Book" from the book class functions and made the book handle be an optional parameter that can be supplied as a trailing named parameter in cases where you have more than one book context at a time. Examples:

! no need to save book handle if dealing with only one book…

call Fn'LibXL'CreateBook(booktype)

! and no need to supply it when referencing the default book…

hSheet1 = Fn'LibXL'GetSheet(idx)

But if you are working with multiple books, then you should save the handle coming back from the CreateBook() function and pass it via the named parameter hbook to the other functions, e.g.

hbook1 = Fn'LibXL'CreateBook()

hbook2 = Fn'LibXL'CreateBook()

! add sheet to 1st book (specifying book handle by named parameter)

hsheetx = Fn'LibXL'AddSheet("sheetname",hbook=hbook1)

! add a format to 2nd book

hformat = Fn'LibXL'AddFormat(hbook=hbook2)

Remember that named parameters have to follow any unnamed (positional) parameters.

In the case of sheets, probably a slight majority of applications will be working on one sheet at a time, but for those that aren’t, most of the Sheet functions take the sheet handle as the first parameter (signaled by the function name starting with "Sheet" after the prefix). A few of the Sheet functions rely on the default (i.e. last accessed) sheet rather than requiring an explicit sheet handle, and thus they drop the "Sheet" from the name. For example:

! requires explicit sheet handle

call Fn'LibXL'SheetWriteNum(hsheet1,row,col,num)

! uses implicit (current) sheet handle

call Fn'LibXL'WriteNum(row,col,num)

Format and Font class functions are normally only needed in the setup of the workbook. The handles to the created objects are then used to associate Fonts with Formats and Formats with cells. So these functions mostly all require the explicit handle. Since Fonts and Formats belong to Books, you typically use Book class functions to create the class instances (e.g. Fn'LibXL'AddFont()) and then Font and Format class functions to assign attributes to them. To simplify coding, there are also some combined functions that combine the separate operations of adding the object and assigning the attributes. These combined functions typically have two parts to the main function name, e.g. "AddFormat'SetAttributes". For example:

! Separate:

! Create empty format object and add it to the default book

hformat = Fn'LibXL'AddFormat()

! Then use the object handle to set attributes to it

call LibXL'FormatSetAttributes(hformat,...)

! Combined:

hformat = Fn'LibXL'AddFormat'SetAttributes(...)

To minimize confusion between the word "format" when referring to the class, and the word "format" when referring to a numeric format specification, we abbreviate all references to the latter as "Fmt", e.g. LibXL'FormatSetNumFmt(hformat,numfmtid) sets the numeric format (fmt) identified by numfmtid for the Format class instance whose handle is hformat. (The underlying libxl library uses "format" for both, which is confusing.)


Other Usage Notes

Formats are associated with cell data at the time the cell is written. Either you specify an explicit format handle at that time, or a default format will be used. The SetCol and SetRow functions establish default formats, but will not change the formats for data already written. The only way to change the format of a cell already written is with the SheetSetCellFormat() function, or by rewriting it.

Since the format information is associated with each cell by means of a handle, changing the attributes of the format itself will affect the cells already written using that format handle.

Setting column widths to automatic (width = -1) appears to work best if done after all the data is written. (It seems to calculate the size at the time of the SetCol function based on the data available.) So you may want to use SetCol to assign a default column format prior to writing column data, and then use it again to set auto-width after writing all the data.

When setting cell colors, note that the text color is an attribute of the font (not of the format), and that a solid background color is set via fillpattern=FILLPATTERN_SOLID and patternfgc=COLOR_XXX. Yes, that's the pattern FOREGROUND color. (Pattennbgc values only apply to striped patterns.)

To add a format attribute, such as a background color, to an existing cell of unknown attributes, use SheetGetCellFormat() to retrieve the existing format, then use AddFormat'SetAttrbutes() to create a new format, specifying the existing format as the hinitformat param, along with any new attributes. Then use SheetSetCellFormat() to update the cell with the new format, e.g.:

hformat = Fn'LibXL'SheetGetCellFormat(sheet1,row,col)

hnewformat = Fn'LibXL'AddFormat'SetAttributes(alignh=ALIGHN_CENTER, hinitformat=hformat)

call LibXL'SheetSetCellFormat(sheet1,row,col,hnewformat)


Function Index

The following tables list and briefly describe all the functions, organized by class. Refer to the libxl.bsi source code for details on the parameters of each function. Refer to Function Naming Convention for notes on why the functions are named as they are.

Subtopics

Book Class

Sheet Class

Other Classes


Book Class

Except for Fn’LibXL’CreateBook, which returns a handle to an instance of the Book class, all the other functions take a Book handle. (However, if the handle is not specified, it defaults to the current workbook, so in the typical single workbook situation, you can effectively ignore the workbook handle and just let the libxl.bsi class wrapper handle it.)

Function / Procedure | Description
Fn'LibXL'CreateBook | Create an instance of the Book class
Fn'LibXL'LoadBook | Load workbook from file
Fn'LibXL'SaveBook | Save workbook to file
Fn'LibXL'AddSheet | Add a sheet to workbook
Fn'LibXL'DelSheet | Delete sheet from workbook
Fn'LibXL'InsertSheet | Insert a sheet
Fn'LibXL'GetSheet | Return handle to sheet by index #
Fn'LibXL'GetActiveSheet | Return handle to active sheet
LibXL'SetActiveSheet | Set active sheet
Fn'LibXL'AddFormat | Add a format instance to the workbook
Fn'LibXL'GetFormatCount | Return number of formats defined
Fn'LibXL'GetFormat | Return handle to format by index #
Fn'LibXL'AddCustomNumFmt | Add a custom format
Fn'LibXL'GetCustomNumFmt$ | Return format handle for custom format by index #
Fn'LibXL'AddFont | Add a font instance to the workbook
Fn'LibXL'GetFontCount | Return number of font instances in workbook
Fn'LibXL'GetFont | Return font handle by index #
Fn'LibXL'GetDefaultFont$ | Return attributes of default font (name, size, …)
LibXL'SetDefaultFont | Establish default font
Fn'LibXL'DatePack | Pack separate date/time fields into internal date format
Fn'LibXL'DateUnpack | Unpack internal date format into separated date/time fields
Fn'LibXL'AddPicture | Add a picture to the workbook
Fn'LibXL'GetPictureCount | Return count of pictures in the workbook
Fn'LibXL'GetErrorMessage$ | Get message associated with error #
Fn'LibXL'GetBiffVersion | Get BIFF version of binary XLS file
Fn'LibXL'GetRC1RefMode | Return TRUE if R1C1 reference mode set
LibXL'SetR1C1RefMode | Set or reset R1C1 reference mode


Sheet Class

These functions all return or require a handle to an instance of the Sheet class. Those whose name contains “LibXL’Sheet” expect the sheet handle as the first parameter, but it can be ignored (in order to use the current default sheet) if you name all of the other parameters. Those whose name does not contain “LibXL’Sheet” move the optional sheet handle to the end of the parameter list, making it easier to omit (without requiring naming of all the other parameters).

Function / Procedure | Description
Fn'LibXL'SheetGetName$ | Return name of sheet by index #
LibXL'SheetSetName | Set sheet name
Fn'LibXL'SheetGetFirstRow | Return first non-blank row index
Fn'LibXL'SheetGetLastRow | Return last non-blank row index
Fn'LibXL'SheetGetFirstCol | Return first non-blank column index
Fn'LibXL'SheetGetLastCol | Return last non-blank column index
Fn'LibXL'SheetGetCellType | Return cell type (CELLTYPE_xxx) of cell
Fn'LibXL'SheetIsFormula | Return TRUE if cell contains a formula
Fn'LibXL'SheetIsDate | Return TRUE if cell contains a date
Fn'LibXL'SheetGetCellFormat | Return handle to format instance for cell
LibXL'SheetSetCellFormat | Set format of cell
Fn'LibXL'SheetWrite | Generic cell write (based on type of value passed)
Fn'LibXL'Write | Variation of SheetWrite which assumes current sheet
Fn'LibXL'SheetWriteNum | Write numeric value to cell
Fn'LibXL'SheetWriteFormula | Write formula to cell
Fn'LibXL'WriteFormula | Variation of SheetWriteFormula which assumes current sheet
Fn'LibXL'SheetWriteComment | Write comment to cell
Fn'LibXL'SheetReadComment$ | Read comment from cell
Fn'LibXL'SheetReadValue$ | Read value from specified sheet, cell
Fn'LibXL'ReadValue$ | Variation of SheetReadValue$ which assumes current sheet
Fn'LibXL'SheetReadStr$ | Read string contents from specified sheet, cell
Fn'LibXL'SheetReadNum | Read numeric contents from specified sheet, cell
Fn'LibXL'SheetReadFormula$ | Read formula from specified sheet, cell
Fn'LibXL'SheetReadBlank | Read blank from specified sheet, cell
Fn'LibXL'SheetReadBool | Read Boolean from specified sheet, cell
Fn'LibXL'SheetSetCol | Set attributes for specified sheet, column
Fn'LibXL'SheetGetColWidth | Get width of specified sheet, column
Fn'LibXL'SheetGetRowHeight | Get row height of specified sheet, row
Fn'LibXL'SheetSetRow | Set row attributes
Fn'LibXL'SheetSetPicture | Set picture on specified sheet, cell
Fn'LibXL'SheetGetPicture | Get picture from specified sheet, cell
Fn'LibXL'SheetSetProtect | Protect sheet
Fn'LibXL'SheetGetProtect | Return TRUE if sheet is protected
Fn'LibXL'SheetGetHidden | Get hidden attribute from specified sheet
LibXL'SheetSetHidden | Hide sheet
Fn'LibXL'SheetGetMergeCount | Return number of merged cells on sheet
Fn'LibXL'SheetGetMergeIdx | Get merged cells by index
Fn’LibXL’SheetGetMergeXY | Get merged cells at row, col
Fn'LibXL'SheetSetMerge | Merge specified cells
Fn'LibXL'SheetDelMergeXY | Remove specified cell merge at row,col
Fn'LibXL'SheetDelMergeIdx | Remove cell merge by index
LibXL'SheetSetDisplayGridlines | Set gridlines display option
Fn'LibXL'SheetGetDisplayGridlines | Get gridlines display option
LibXL'SheetSetPrintGridlines | Set gridlines print option
Fn'LibXL'SheetGetPrintGridlines | Get gridlines print option
Fn'LibXL'SheetGroupRows | Group rows
Fn'LibXL'SheetGroupCols | Group columns
Fn'LibXL'SheetGetSplitInfo | Get vertical and horizontal split locations
LibXL'SheetSetSplit | Set vertical and horizontal split locations
Fn'LibXL'SheetCopyCell | Copy a cell (data and format) to another cell on same sheet
Fn'LibXL'SheetGetHyperlinkCount | Return # of hyperlinks on sheet
Fn'LibXL'SheetGetHyperlink$ | Get hyperlink info by index
LibXL'SheetAddHyperlink | Add hyperlink
LibXL'SheetAddrToRowCol | Convert A1 or $A$1 type address to row,col
Fn'LibXL'SheetRowColToAddr$ | Convert row,col to A1 or $A$1 type address
Printing-Related routines |
LibXL'SetLandscape | Set orientation for printing (TRUE=landscape, FALSE=portrait)
Fn'LibXL'GetLandscape | Get orientation for printing
LibXL'SetPrintFit | Fit sheet to x pages wide by y pages high
Fn'LibXL'GetPrintFit | Get fit info
Fn'LibXL'SetHeader | Set header and margin
Fn'LibXL'GetHeader$ | Get header and margin
Fn'LibXL'SetFooter | Set footer and margin
Fn'LibXL'GetFooter$ | Get footer and margin


Other Classes

Font Class. Font instances belong to the workbook (see Fn'LibXL'GetFontCount and Fn'LibXL'GetFont in the Book Class functions). Each Font instance may be shared by any number of Format instances (which is how they get associated with cells). So the standard procedure for defining fonts involves using the Book class function Fn’LibXL’AddFont to create a font instance and add it to the book, then using the Font class function LibXL’FontSetAttributes to assign attributes to it. Or, you can combine these two steps using the Fn’LibXL’AddFont’SetAttributes function.

Function / Procedure | Description
LibXL'FontSetAttributes | Set attributes for specified instance of font class
Fn'LibXL'AddFont’SetAttributes | Create font instance, add to book, set attributes for it
Fn'LibXL'FontGetAttributes | Get attributes of specified font instance.

Format Class. Each cell (individually, or in rows or columns) is associated with a single instance of the Format class, which determines the non-data attributes for the cell (alignment, color, font, numeric format or mask, etc.). As with Fonts, the Format instances belong to the Book class, so the standard procedure for defining a Format would be to use the Book class function Fn’LibXL’AddFormat, and then pass the returned Format instance handle to the Format class procedure LibXL’FormatSetAttributes to assign the attributes of the format. Or, you can combine those two steps with the Fn’LibXL’AddFormat’SetAttributes function.

Also note the overuse of the word “format” to refer both to the Format class, as well as to number formats, either the standard built-in ones identified by NUMFMT_xxx identifiers, or custom ones you define via a mask. (We try to minimize the confusion by using the abbreviation “Fmt” when referring to the number formats, reserving “Format” to refer to the Format class.)

Custom numeric formats are also owned by the Book, and have to be created and added to the book before they can be associated with an instance of the Format class. Again you can perform those steps separately, starting with the Book class function Fn'LibXL'AddCustomNumFmt and Format class function Fn’LibXL’FormatSetNumFmt, or use the combined function Fn’LibXL’Format’AddSetCustomNumFmt.

Function / Procedure | Description
Fn'LibXL'FormatGetFont | Return handle of font associated with specified format instance
Fn'LibXL'FormatSetFont | Set font for specified format instance
Fn'LibXL'FormatGetNumFmtId | Return numeric format id for specified format instance
LibXL'FormatSetNumFmt | Set numeric format for specified instance of format class
Fn'LibXL'AddFormat'SetNumFmt | Create format instance, add to book set numeric format for it
Fn'LibXL'Format'AddSetCustomNumFmt | Create custom numeric format, add to book, set specified format instance to use it
LibXL'FormatSetAttributes | Set attributes of specified format instance
Fn'LibXL'AddFormat'SetAttributes | Create format instance, add to book, set attributes for it
LibXL'FormatGetAttributes | Get attributes of specified format instance
Fn'LibXL'FormatSetBorders | Set borders for specified format instance
Fn'LibXL'FormatGetBorders | Get borders for specified format instance

Misc Routines (not associated with a class):

Function / Procedure | Description
Fn'LibXL'Load | Load the LibXL library
Fn'LibXL'Unload | Unload the library
Fn'LibXL'Handle'DynLib'Errors | Handle library errors related to the Dynamic library interface
LibXL'Error | Force/report a library logic error
Fn'LibXL'Get'DLCTL$ | Return the dynamic library control structure
Fn'LibXL'Set'Flags | Set overall library interface flags


Examples

This section contains a set of complete example programs illustrating different features. The program source code for each program is included in the LIBXL: ersatz directory, and a link to the online source code is also provided.

Note that most of these are direct translations from C++ to A-Shell/BASIC of the example programs packaged with the LibXL library. In many cases, the original C++ code is shown as comments.

Subtopics

Sample Invoice

Alignment, Colors, Borders

Formulas

Groups

Numeric Formats, Masks


Sample Invoice

The sample program SAMXLINV (source online here) illustrates inserting a graphic, merging two cells, and several fonts and formats.

 | A | B | C
1 |  |  |
2 | 3 | Invoice No. 1234
3 |  |  |
4 |  | Name: MicroSabio |
5 |  | Address: West Hills CA 91307 |
6 |  |  |
7 |  | Description | Amount
8 |  | A-Shell | $999
9 |  | ATE | $100
10 |  | Maintenance | $250
11 |  | Total: | $1,349
12 |  |  |
13 |  |  |
14 |  |  | Signature
15 |  |  |


Alignment, Colors, Borders

The sample program TSTACB (source online here) illustrates the various permutations of cell alignment, plus border styles, fill and font colors.


Formulas

The sample program TSTFORMULA (source online here)illustrates the use of formulas, with the formula showing in the first column and the result in the second.


Groups

Sample program TSTGROUP (source online here) illustrates the row grouping. Note the plus and minus buttons in the left margin. Rows 3-7 are in a collapsed group, as 14-17 and 19-22. Rows 11-26 are in a group shown expanded.


Numeric Formats, Masks

Sample program TSTNUMFOR (source online here) illustrates the use of built-in numeric formats (NUMFMT_xxx) and also custom masks. The raw value is shown in the first column, the format code or mask in the center, and the formatted value on the right.


Utilities

This section contains a set of utility programs which may be helpful during development. They may also serve as samples of LibXL interface programming, but unlike the samples in the previous section, these programs are more interesting for their output than for their source code.

Subtopics

Format Viewer

Interactive Read Utility


Format Viewer

Utility program LIBXLVIEW (source online here) reads an existing XLS file and creates a new one illustrating the use of fonts and formats within the original. This may be useful when trying to match the structure of an existing model spreadsheet file. To illustrate, here is the output of RUN LIBXLVIEW on the Sample Invoice shown in the previous section:

It creates a new XLS file illustrating the use of fonts and formats in the first sheet of the source XLS file:

The first sheet (above) lists all the fonts defined in the original. One anomaly you'll note is that XLS files often contain many fonts that either aren't used or which are effectively duplicates. (This is particularly noticeable when creating an empty spreadsheet file using Excel.) In the example above, the samxlinv.bp program explicitly created only the last three fonts; the others were created by default (and can probably be ignored for our purposes.)

The second sheet (above) lists all the formats defined in the original. As with the fonts, you may find that there are many formats defined by default. In this example, only the last 8 were explicitly defined by the samxlinv.bp program.

The final sheet (above) represents the first sheet of the original/source XLS file, with each cell's contents replaced by the handle of the associated format. The colors are simply added to make it easier to identify cells with the same format. For comparison, here is the original again:

Column A of the diagnostic sheet shows that all of the cells in column A of the original have the same format. This includes the cell containing the image. (The image is independent of the cell's format.)

Looking at the original invoice sheet, if you are wondering about the format used for row 7 (the Description and Amount header), you can look in the corresponding cells of the diagnostic sheet (colored yellow in this case), which indicates the format handle 650A180. For details on that format, you can then go back to the Format sheet and locate that handle in column A.

The matching row (26) is show below (wrapped):

The above indicates, for example, that the tan background color is achieved by setting the FillPattern to FILLPATTERN_SOLID, the PatternFGC to COLOR_TAN, and the PatternBGC to the default.


Interactive Read Utility

Utility program LIBXLIRU (source online here) prompts you to load an XLS and then queries it, displaying various details about the workbook such as the number of sheets, rows, cols, pictures, etc. It then prompts you for individual cells to query. You may find it useful both in the same vein as the previous utility—i.e. for examining the contents of spreadsheets that you created or received from others—as well as an example of the use of several LibXL functions related to querying.

As an example, using the same sample invoice referenced previously, here is a query of the contents of cell 7,2 …


A-Shell as a CGI Engine

A-Shell can be launched from a web page to retrieve information from your AlphaBASIC application and create a new web page using that information. Web programming is an involved topic and exceeds the scope of this guide, but perhaps the following overview of how this can work may help you get started.

The only real requirement of a CGI engine is that it receive the information fed to it by the web page (generally as "standard input" but also possibly as an environment variable), parse it out to determine which variables are being passed and what their values are, and then, after operating on the data, it must create a new web page on its "standard output". Typically, the process is started when the user clicks on a "SUBMIT" button on a page containing some sort of a form that has been filled in. The FORM ACTION tag within the form will reference the name of the CGI command to execute when the SUBMIT button is pressed. So as an example, consider the following simple HTML form:

<HTML>

<HEAD>

<TITLE> Sample Form Using A-Shell as a CGI Engine </TITLE>

</HEAD>

<BODY>

<CENTER>

<H1> Sample HTML Form Using A-Shell as a CGI Engine </H1>

</CENTER>

<P>

<H2> Welcome to our sample form </H2>

This is an example of a typical form that asks some questions, then passes them to a CGI program for some kind of processing, and then displays a new page with the results.

<p>

<FORM ACTION="/cgi-bin/cgitst" METHOD="POST">

<PRE>

Enter your name:<INPUT TYPE="text" NAME="name" SIZE=40>

zip:<INPUT TYPE="text" NAME="zip" SIZE=6>

<HR>

What is your age?

<INPUT TYPE="radio" NAME="age" VALUE="1-10">1-10

<INPUT TYPE="radio" NAME="age" VALUE="11-30">11-30

<INPUT TYPE="radio" NAME="age" VALUE="31-60">31-60

<INPUT TYPE="radio" NAME="age" VALUE="61-112">61=112
<P>

<TEXTAREA NAME="comments" ROWS=5 COLS=60>

This comment will appear in the comment box, but you can erase it or add to it.

</TEXTAREA>

</PRE>

<HR>

<INPUT TYPE="submit" VALUE="SEND FORM"><BR>

<INPUT TYPE="reset" VALUE="Clear form">

</FORM>

</BODY>

The above HTML displays a simple form that looks like this:

The most important line in the HTML for the purposes of this example is the one starting with "<FORM ACTION". The form of this, and the contents of the referenced script will be slightly different between UNIX and Windows, so they are discussed separately in the following topics.

Subtopics

UNIX Version

Windows Version

A-Shell CGI Command Line

Testing / Debugging CGI

Web Servers


UNIX Version

The UNIX version of the FORM ACTION command will most likely reference a UNIX shell script, using syntax similar to this:

<FORM ACTION="/cgi-bin/cgitst" METHOD="POST">

This causes the command /cgi-bin/cgitst to be executed, using the "POST" method of parameter passing, when the "SUBMIT" or "SEND FORM" button is pressed. We could have given an A-Shell command line but have chosen to use an intermediate script called cgitst as it will provide us a lot of additional flexibility. Our cgitst script (for UNIX) is as follows:

#!/bin/ksh

exec /vm/miame/bin/ashell -i /vm/miame/miame.ini –cgi –e cgicmd \ 2>/tmp/cgi.err

The above shell script starts by specifying that it is to run under the Korn shell. Actually, it makes little or difference which shell it runs under, since we aren’t doing anything fancy, but it is still a good idea to standardize on a particular shell, in case you want to take advantage of certain capabilities or environment settings specific to a particular shell. (If running under Linux, and didn’t have the Korn shell installed, you might want to specify the /bin/bash shell instead.)


Windows Version

The Windows version of the FORM ACTION command is nearly identical, except that it will most like reference a BAT file, using syntax similar to this:

<FORM ACTION="/cgi-bin/cgitst.bat" METHOD="POST">

The referenced cgitst.bat, if equivalent to the UNIX shell script described above, would be:

@c:\vm\miame\vc49\release\ashw32.exe -i c:\vm\miame\miame.ini –cgi –e –z tstcgi


A-Shell CGI Command Line

The main action of the shell script or BAT file is to launch A-Shell with a specific set of command line arguments. (The main reason we couldn’t do this directly from the HTML page is that the FORM ACTION statement doesn’t permit command line arguments.) The –cgi switch tells A-Shell to operate in "CGI mode". The –e switch tells A-Shell to exit as soon as it returns to the dot prompt after executing the command. (This would not be necessary if we make sure to execute HOST.LIT after completing the CGI process.) In the Windows version of the command line, we also need the –z switch to prevent A-Shell from displaying a window on the web-server (where no one could see it, and where it might cause the process to abort with an error). After the switches we pass the startup command cgicmd which in this case refers to a CMD file (CMD:CGICMD.CMD).

The windows version of the command requires the @ in front to prevent the BAT file processor from echoing the command line to stdout, which would cause it to appear in the web page (or cause the web page to be rejected).

Under UNIX, we recommend redirecting stderr (built-in file descriptor 2) to a file, which is accomplished via the 2>/tmp/cgi.err Since the –cgi switch causes ordinary PRINT statements to be sent to stderr instead of stdout, this will not only allow for easy debugging but also prevent inadvertent PRINT statements from corrupting the web page that the CGI process is supposed to create on the stdout stream.

Under Windows, the redirection of stderr to a file is harmless, but also useless and unnecessary, since in Windows, PRINT statements do not generate stream output. Instead, they get rendered graphically in the window, which was made invisible by the –z switch. If you want to output debugging messages, you'll have to explicitly write them to a file.

Subtopics

A-Shell CMD / RUN


A-Shell CMD / RUN

When A-Shell launches, it executes the command line "cgicmd" which might be implemented something like the following:

:R

log bas:

run cgitst

$0

Finally, our program CGITST.BAS might look something like this:

program CGITST,1.0(100)

!---------------------------------------------------------------------

! Sample AlphaBASIC program used within a CGI script

! Note that we are expecting the form parameters to have been passed

! to us in stdin (using the POST method). We'll pick them up with

! cgiutl.sbr. The output page is stored in cgitst.htm in the current

! directory; it contains "variables" for the form parameters, which we

! substitute in using cgiutl.sbr.

!---------------------------------------------------------------------

map1 PARAMETERS ! parameters we expect to be passed by form

map2 NAME,S,60

map2 ZIP,S,5

map2 AGE,S,10 ! e.g. "11-30"

map2 COMMENTS,S,500

map1 CGIUTL'PARMS

map2 STATUS,F

! test if we are in cgi mode (-cgi switch used)

xcall CGIUTL,0,STATUS

if STATUS = 0 print "Not running in CGI mode" : end

! retrieve parameters

xcall CGIUTL,2,"name",NAME,STATUS

xcall CGIUTL,2,"zip",ZIP,STATUS

xcall CGIUTL,2,"age",AGE,STATUS

xcall CGIUTL,2,"comments",COMMENTS,STATUS

! now build new web page just displaying these parameters

! (using the template file CGITST.HTM)

xcall cgiutl,3,"cgitst.htm", STATUS, &

"$NAME="+NAME, &

"$ZIP="+ZIP, &

"$AGE="+AGE, &

"$COMMENTS="+COMMENTS

! finally, just end

end

The template file for the output web page might look like the following. Note that we don’t have to use this template approach. We can also use the CGIUTL opcode 4 to build the web page from scratch. But this approach allows you to design your web page in another tool, then just modify it to specify suitable fill-in variable names for the data you want to merge in.

content-type: text/html

<HTML>

<HEAD>

<TITLE> Sample CGI-generated web page </TITLE>

</HEAD>

<BODY>

<H1> Here is the information you passed in the previous form: </H1>

<P></P>

<P>Name = $NAME</P>

<P>Zip = $ZIP</P>

<P>Age = $AGE</P>

<P>Comments = $COMMENTS</P>

</BODY>

</HTML>

The above sample program doesn’t do anything useful, other than just read in the data input into the form, parse it out, and then display that data on a new web page. However, it should be easy to extend this technique to do something useful.


Testing / Debugging CGI

One way to test whether your BASIC program and A-Shell are performing properly is to create a file that contains the expected stdin string, then just open a Command Prompt window and execute a command line which launches A-Shell with the redirected stdin file, and redirects output to another file. You can then examine the output file to see if it looks like a valid web page.

For testing purposes, stdin format input format can be simplified to a list of "VARNAME=value&" pairs, e.g.:

NAME=Bertrand Russsel&GAME=philosophy&

(The above example simulates a form with two variables, NAME and GAME.) Assuming this meets the requirements of your CGI program, and you stored it in a file called cgitst.in, you could test it with something like the following:

c:\vm\miame\bin\ashw32.exe -z -cgi -i c:\vm\miame\miame.ini cgicmd < ./cgitst.in > ./cgitst.out

Naturally you would adjust the paths, cmdfile name, and names of the input and output files as per your situation. If the process works, you should see no action whatsoever, but when you TYPE the cgitst.out file you should see a valid web page. Better yet, try to load it with a browser to verify that it is in a valid format. If this test works, then the only remaining issues would relate to the configuration of the web server.


Web Servers

As of March 2005, the sample above has been tested on the Netscape Fasttrack web server under SCO OpenServer, as well as the Apache 2.0 web-server under Red Hat 8.0 and under Windows XP. It has not been tested under the Windows IIS web server. In theory, all web servers should support the basic CGI functionality (which has been around for a long time), but the configuration details will vary between web servers and platforms. In particular, it may be necessary to specifically enabled the ability to execute CGI scripts, as this may not be turned on, or may be limited, by default. (See the ExecCGI option on the Options directive in the httpd.conf file for Apache.)

As of this writing, the Apache web server is probably the best choice, as it is by far the most commonly used on the Internet. Besides popularity, some of the other advantages of Apache are:

• It works on several platforms, including Linux and Windows

• It is well documented (both directly by the developers and by third-party book publishers)

• Source code is freely available

• It is free to download and use

Subtopics

Apache on Windows Example


Apache on Windows Example

Using a default "typical" installation of Apache 2.0 under Windows XP, we were able to implement the example form and CGI script described in the previous topics with only the following changes:

• Add "ExecCGI" to the Options line in httpd.conf:

Options Indexes FollowSymLinks ExecCGI

• Add ".bat" to the name of the script in the FORM ACTION line of the form:

<FORM ACTION="/cgi-bin/cgitst.bat" METHOD="POST">

• My cgitst.bat script was placed in the cgi-bin directory of Apache, and contained the following (all on one line):

@c:\vm\miame\vc49\release\ashw32.exe -cgi -z -e -i c:\vm\miame\miame.ini tstcgi


A-Shell/FAX

A-Shell/FAX is an application programming interface (API) which enables applications running under A-Shell/Windows to send faxes via the Windows 2000 / XP Fax Service. While faxing has always been possible under A-Shell/Windows by the simple fact that most fax packages emulate a standard Windows printer, A-Shell/FAX allows the application to pass all of the necessary addressing information (fax number, to/from names, cover page info, etc.) directly to the Fax Service, eliminating the need for the user to respond to the dialog boxes which would otherwise pop up to request this information.

Note that A-Shell/FAX requires Windows 2000, XP or higher, although it can be made available to A-Shell/UNIX via ATE and the GDIPRT printing subroutine.

The mechanism for passing this information from the application to the Fax Service consists of a set of commands or directives that can be embedded at the start of the print file. The concept is identical to that used for embedding GDI directives for font selection, line drawing, image printing, etc. The actual set of directives overlaps that of the AlphaFAX package available under AMOS. That is to say, most (but not all) AlphaFAX commands are supported by A-Shell/FAX, yet A-Shell/FAX supports a number of additional commands designed to take advantage of features of the Windows 2000 Fax Service that do not exist in AlphaFAX.

We chose to target the Windows 2000 / XP Fax Service for the following reasons:

• We are not aware of any corresponding standardized fax API available under Windows 9x or NT. Many of the existing fax packages, like WinFax Pro, do offer a programming interface, but they typically involve the use of custom DLL or DDE calls, making it very difficult to support a single interface from the BASIC side.

• The documentation and API necessary to use the interface are provided in the standard Microsoft developer tool set, greatly simplifying our task of getting A-Shell to work with it and to keep up with its evolution.

• The technique of embedding logical fax commands within the print file (which are translated by the A-Shell printing interface) isolates the application fax interface from the details of the back-end interface to the fax server, thus allowing for the possibility of supporting other back-end fax services simply by adding additional translation routines to A-Shell. Although the logical commands we implemented were designed with the W2000 Fax Service in mind, they are fairly generic and would most likely work equally well with any fax server API. In fact, they could be easily adapted to a UNIX environment (since most UNIX fax software also relies on the technique of embedded commands in the print file.)

Subtopics

Command Format

Command Listing

Supported AlphaFAX Commands

Additional Informational Commands

Cover Page Commands

Unsupported AlphaFAX Commands

Document Formatting Codes

Sample Document

Defining the Fax Printer


Command Format

All of the A-Shell/FAX commands start with "@@" which must appear in the first two columns of the line. As with the A-Shell GDI printing commands (which start with "//"), you may comment out a line by putting a semicolon in the third column. For example:

@@;This is a comment and will not be printed.

The basic format of all the commands consists of the @@ followed by a keyword. If the command takes any parameters, the keyword is followed immediately by an equal sign, followed by one or more comma-delimited parameters. For example:

@@KEYWORD=param1{,param2}...{,paramN}

The commands are not case sensitive, but there should be no space before or after the equal sign. Since the comma is the parameter delimiter, if a single parameter contains any embedded commas you must enclose the entire parameter in quotes (e.g. "Mr. Scholar, PhD").

All @@commands must appear before any blank or printable lines in the print file. (Scanning for @@commands stops when the first line which does not start with "@@" or "//" is encountered.)


Command Listing

This table lists the A-Shell/FAX and AlphaFAX commands. The names of the table sections correspond to the documentation headings where you will find detailed descriptions of the commands.

@@ Command | Description
Supported AlphaFAX Commands
TELNO | "To" fax number
ID | Identifier for log file
NOTIFY | Email address for delivery report; see warning
PREVIEW | Ignore all other commands and send to printer
PRINTFAX | Printer name
Additional Informational Commands
TO | "To" person name
FROM | "From" person name
FROMCO | "From" company name
FROMDEPT | "From" department name
DOCNAME | Description of faxed document
Cover Page Commands
CPNAME | Filename of cover page
CPTO | "To" person
CPTOADDR | "To" physical address
CPFROM | "From" person
CPFROMADDR | "From" physical address
CPSUBJECT | Subject
CPTOTPAGES | Total pages
CPNOTE | Note
CPRFROMFAX | "From" fax number
Unsupported AlphaFAX Commands
DEFER | Defer until <time>
PRIORITY | Priority
FINE | Sending quality
INCLUDE | File to be included
DISTRIBUTE | Distribution list
NEWDOCUMENT | Begin new fax


Supported AlphaFAX Commands

This first set of commands consists of those that are also supported by AlphaFAX. The first of these, @@TELNO, is the only mandatory command. All the others are optional and mostly serve to provide additional information in the fax log which is kept by the Fax Service (see W2000 Event Viewer, Application Messages.)

@@TELNO=<target fax number>

@@ID=<identifier for log file>

@@NOTIFY=<email address to send delivery report to>

The @@NOTIFY command in AlphaFAX took a jobname as its parameter and caused a screen message to be sent to that job’s terminal when the fax had been sent or aborted. In the A-Shell/FAX version, the Fax Service is requested to send an email delivery (or non-delivery) report to the specified address. However, in order for this to work, the Fax Server must have an email interface configured. This command can also be called @@MAILDR.

Warning: Due to a bug in the Windows XP Fax Server, specifying the @@NOTIFY command may result in no output at all (no fax, no notification).

@@PREVIEW

The @@PREVIEW command causes all of the other @@ commands to be ignored and instead of sending it to the fax printer, it is sent to the printer. If you don’t specify any printer, then the A-Shell default printer is used. Otherwise, you can specify a printer using the following syntax:

@@PREVIEW=<printer name>

For example:

@@PREVIEW=laser

As long as the printer specified is capable of raster graphics, the output should look essentially identically to what the fax would look like. Note that the only statement that is processed from the printer INI for the specified printer is the DEVICE statement. All the other printing parameters of the preview printer’s INI are ignored, and those of the original fax printer INI are used instead. (The idea here is to make the output on the preview printer match that on the fax printer.)

Although this is not specific to faxing, you may find it handy to have a printer called PROMPT whose INI specifies DEVICE = PROMPT: in which case @@PREVIEW=PROMPT would cause A-Shell to prompt you for the preview printer name.

If you want to send the fax AND print it (for example, to keep a hardcopy for yourself) then you can use the following command:

@@PRINTFAX=<printer name>

This is identical in concept to @@PREVIEW except the fax is also sent.

@@PRINTFAX is not part of the AlphaFAX command set.


Additional Informational Commands

The following commands are A-Shell/FAX extensions (i.e. do not exist in AlphaFAX) and serve primarily to cause additional information to be written to the Fax Server log.

@@TO=<recipient name>

@@FROM=<sender name>

@@FROMCO=<sender company>

@@FROMDEPT=<sender dept>

@@DOCNAME=<descriptive name of faxed document>


Cover Page Commands

The following A-Shell/FAX extensions (i.e. which do not exist in AlphaFAX) are solely for the purpose of passing information to a cover page which has been created by the Fax Service Cover Page Editor. The critical command here is @@CPNAME which specifies the name of the cover page. If the command is present, then an attempt will be made to create a cover page. Otherwise, all of the other cover page related commands are ignored and no cover page will be generated.

@@CPNAME=<coverpage filespec>{,serverflag}

As mentioned above, cover pages may be created by the Cover Page Editor, which may be found in the Fax applet of the W2000 Control Panel. The Editor is similar to a text editor (like Word) except that you may insert special fields which will be replaced by values passed from the application at the time the fax is sent. The commands for doing this are given below. (Note that they all start with "@@CP" for Cover Page.) After designing your cover page, you save it in the normal way (with a .COV extension.)

W2000 comes with a few sample cover pages that you may want to use as a basis for yours. To find them, use the Start | Search facility and look for *.COV

There may be some confusion over the placement and specification of the cover page. W2000 allows for both local and server cover pages, but it may not be entirely obvious where to put them or how to reference them other than via a fully qualified filespec. Since the @@CPNAME command supports either AMOS-style or Windows-style filespecs, you may just want to copy your .COV file into an ersatz directory (like LIB: or perhaps create a FAX:) and then just reference it using that ersatz (e.g. @@CPNAME=FAX:COVER1.COV). The optional serverflag argument may be set to 1 if the cover page is on the server; otherwise the cover page is presumed to be on the local workstation. (The point is moot if the filespec is fully qualified.)

If using an AMOS format filespec for the cover page that contains a [p,pn], you must enclose the entire filespec in "quotes". Otherwise the comma in the [p,pn] will be treated as a delimiter.

The rest of the cover page commands are purely for specifying information to be inserted into the cover page.

@@CPTO=<name>{,<title>{,<company>{,<dept>{,<office location>

{,<home phone>{,<office phone>}}}}}}

@@CPTOADDR=<street addr>{,<city>{,<state>{,<zip>{,<country>}}}}

@@CPFROM=<name>{,<title>{,<company>{,<dept>{,<office location>

{,<home phone>{,<office phone>}}}}}}

All @@ fax commands must be contained on a single line in the actual print file, unlike the multi-line formatting above, which was necessary for typesetting purposes.

@@CPFROMADDR=<address>

@@CPSUBJECT=<subject of fax>

@@CPTOTPAGES=<total # pages, including cover>

@@CPNOTE=<misc memo/notes for cover page>

@@CPNOTE is the only command that can appear multiple times, if needed, to specify a longer note. The maximum note size is 2K. To let the cover page formatting logic combine and wrap the lines as it chooses, end each line with a space followed by a backslash. Otherwise, each @@CPNOTE will start on a new line on the printed cover page. Remember to enclose the entire parameter in quotes if it contains any commas. For example:

@@CPNOTE="This is a note which is continued \"

@@CPNOTE="on this line."

@@CPNOTE="This sentence should begin on a new line."

The last @@CPNOTE line should not end with a backslash (or else it will be printed.)

@@CPFROMFAX=<sender fax #>

The number specified in the @@TELNO command will be used for the recipient fax number if such a field exists in the cover page.


Unsupported AlphaFAX Commands

@@DEFER=<time>

@@PRIORITY=<priority>

This ability to submit a document to the fax server now but tell it to wait until later to send it, or to alter the first-come, first-served order of the queue is supported in the more advanced level of the Windows 2000 Fax Server API, but for now, we are using the simpler version of the interface which does not support it. Both commands are simply ignored.

@@FINE

This is also ignored. By default all faxes are sent in the "fine" mode nowadays.

@@INCLUDE=<filespec>

This is not supported but not ignored either. The command itself will appear in the output (which is how all unrecognized commands are handled.) Note that you can get a similar effect using the PREFIX and SUFFIX feature in the A-Shell printer INI files.

@@IMAGE=<filespec>

@@OVERLAY=<filespec>

These commands are not supported because they are superseded by the more powerful A-Shell GDI printing commands //METAFILE and //IMAGE. Note, however, that while the @@IMAGE and @@OVERLAY commands worked only with AMOS BMP and PCX image formats, //METAFILE works only with Enhanced Windows Metafile format and //IMAGE works with Windows BMP, PCX, TIF and JPG. Also note that //IMAGE requires a license for the third-party imaging library.

Another reason for not implementing the @@IMAGE and @@OVERLAY commands is that they were used almost exclusively for creating cover pages. Under the Windows 2000 Fax Service environment, cover pages are created in the Cover Page Editor, which has its own mechanisms for including graphics and images.

@@TELNO=<name>

The ability to define names (which are then translated to actual fax numbers via FAXLST.DAT) is not supported. If this feature is important to you, please let us know as adding it would not be particularly difficult.

@@DISTRIBUTE=<filespec>

Distribution lists are also not currently supported, but could be if demand warrants.

@@NEWDOCUMENT

This is also not supported. If you want to send multiple documents, send them as multiple files and print requests.


Document Formatting Codes

AlphaFAX uses a mechanism of embedded control codes for specifying various kinds of special formatting (fonts, bold, etc.) A-Shell/FAX does not support these, but allows you to use the A-Shell GDI printing commands instead. Since the fax device acts more or less just like a Windows raster printer, virtually all of the GDI commands (except color) are operable (e.g. //SETFONT, //MOVETO, //RECTANGLE, //METAFILE, //IMAGE, etc.).


Sample Document

//;This is a sample print file containing A-Shell/FAX commands.

//;Lines beginning with //; or @@; are comments;

//;Lines beginning with // are GDI commands; with @@ are fax commands.

//;To print this file, just use the PRINT.LIT command, specifying a

//;printer whose INI file specifies DEVICE=FAX:<fax name> and

//; which contains PASSTHROUGH=OFF.

//;

@@TELNO=1-123-456-7890

@@TO=Pancho Villa

@@FROM=Emiliano Zapata

@@FROMCO=Revolutionarios, S.A.

@@FROMDEPT=Provisions

//;Uncomment the @@NOTIFY line below only if certain that the email interface is supported

//;(otherwise you may get no fax at all)

//;@@NOTIFY=email@zapatista.org

@@DOCNAME=Lunch Strategy

@@CPNAME=LIB:SECRET.COV

@@CPTOTPAGES=2

@@CPSUBJECT=Plan for Lunch

@@CPTO=Pancho Villa,General,"Revolutionarios, S.A."

@@CPTOADDR=,"Somewhere in the Sierra Madre",,,MEXICO

@@CPFROMADDR="Somewhere South of Mexico City"

@@CPNOTE="You bring the tortillas and frijoles, \"

@@CPNOTE="and I'll bring the salsa roja and cerveza."

@@CPNOTE="Buen Provecho!"

//;The rest of this document consists of regular text and

//;normal A-Shell GDI printing commands such as //SETFONT,

//;//SETMAPMODE, //TEXTOUT, etc.


Defining the Fax Printer

The fax printer is defined more or less just like any other A-Shell printer (i.e. via a printer INI file in the SYS: directory) with the following two mandatory requirements:

DEVICE = FAX:<fax printer name>

PASSTHROUGH = OFF

The <fax printer name> identifies the particular fax server to use, and can be one of the following:

• A local fax printer name (as it appears in the printer folder.)

• A network printer UNC name, such as "\\servername\printername".

• NULL (nothing following the prefix FAX:) to specify the default local fax printer.

Some examples:

DEVICE = FAX:fax

DEVICE = FAX:\\mainserver\fax1

DEVICE = FAX:

Note that the prefix FAX: must be used in all cases. This is how the A-Shell print spooling routine realizes that you want to use the A-Shell/FAX interface, which requires that it do some preliminary setup work (loading the WINFAX.DLL, dynamically linking the functions needed, allocating temporary memory, pre-scanning the print file to extract the essential header commands, etc.) before doing the normal print processing of the file.


Definition

The A-Shell User Interface (AUI) toolkit encapsulates A-Shell’s user interface functions within a framework that simplifies the addition of a graphic user interface (GUI) to legacy text applications and promotes the separation of business and presentation logic. The functions are accessed from AlphaBASIC via XCALL, XFUNC, and/or AG_xxx statements, but may be conceptually thought of as a series of object classes and methods which can be extended by application programmers through creation of higher level SBX routines.

AUI supports many of the standard GUI objects that Windows programmers are familiar with (buttons, dialogs, list boxes, etc.), but is designed to help bridge the two major gaps that divide legacy AlphaBASIC programs from their modern Windows counterparts:

• Fixed pitch, 24 row by 80/132 column screen vs. proportional font, pixel-level, variable sized windows. AUI deals with this by maintaining two display layers: a text layer (for traditional fixed pitch text) and a GUI layer (for controls), which share a common row/column coordinate system. The GUI layer is transparent, except where controls are placed, and acts as an overlay to the text layer, allowing text and GUI objects to appear to coexist on one screen.

• Procedural vs. event-driven programming model. AUI converts keyboard and mouse events into special keyboard strings that INFLD, AUI_EVENTWAIT and any other input routines can interpret. By selectively defining keyboard strings for individual objects, and choosing which codes your input routine(s) will respond to, you can determine the degree to which each program assumes a traditional linear or more modern event-driven behavior.

Since the AUI toolkit is primarily just a repackaging of existing functions and intrinsic language functions within one or more "wrapper" subroutines, one might wonder what the point is. Although it is true that repackaging doesn’t provide any new functionality, it does provide the following advantages:

• It helps organize the documentation, especially for the GUI functions, since they are now logically grouped together (rather than being all over). (This is especially true for people just getting started.)

• It helps organize any changes to your programs by making it obvious which parts are specifically related to the user interface logic.

• The natural architecture of subroutines is the closest thing to object orientation we have in AlphaBASIC. The are truly modular, they encapsulate details within an explicit interface, they do not support any global variables (which is one of .NET’s requirements), they are extensible (via the SBX mechanism) and they can be substituted (via the ALIAS or VXCALL mechanisms), all of which contributes to good program design.

• By submitting to the discipline of implementing all of your user interface code within a manageable set of routines, you will create a better logical separation between your business logic and interface logic, and will be better positioned to adapt to new interface environments in the future. (Or, for that matter, to support the legacy text interface as a variation of a more object-oriented graphic user interface.)

Although not (yet) fully realized, one of the goals of the AUI concept is to shelter the business logic of applications from the low-level details of the capabilities of the display device. Before adopting any of the functions described herein, check the documentation to determine the extent to which the function requires or assumes particular display environment characteristics.


Overview

The A-Shell User Interface typically takes one of the following forms (generally organized from least to most graphical):

• Dumb monochrome ("green screen") terminals, supporting XY positioning, little or no other features.

• Smarter monochrome terminals or emulators, supporting Wyse50 or AM6x with a range of visual features and attributes accessed through Tab(-1,x) interface, e.g. status lines, box operations, reverse, underline, dim/bright.

• Color terminals and emulators; can select foreground/background colors from a small palette; often color is only used to map onto monochrome attributes)

• Enhanced emulators (ZTERM, AlphaLAN, ATE) which add the ability to access limited Windows functionality via ESC sequences, while still being fundamentally confined to the fixed pitch display environment. (The InSight package extended that somewhat, by replacing certain higher-level display functions with Windows equivalents.)

• ATE provides capabilities which overlap both those of the enhanced emulators and the full Windows environment. At the low end, it provides some tricks for improving the look of text mode applications while remaining a text-mode display device (e.g. beveling effects, mouse support, the ability to tie the colors to Windows colors, access to GDI printing, FTP, etc.) At the high end, it provides nearly all the capabilities of a local Windows GUI environment; the main limitation being that data has to travel between the server and the client display device, sometimes limiting the practicality of certain functions, or at least imposing some constraints on the server in order to achieve good performance.

• Full Windows GUI environment, which comes in various levels of sophistication depending on the version of Windows.

A-Shell has always worked in all of these environments, more or less the same way, by sticking with a limited set of fixed-pitch text mode capabilities. While very practical for portability, this lowest-common-denominator approach has limited the ability to upgrade legacy applications to provide a more Windows-like user interface when in that environment. To partially address this desire, we have historically added miscellaneous Windows functions in a piecemeal fashion so that AlphaBASIC programmers committed to the Windows environment can access isolated GUI features (such as a message box, or image display) to what remained fundamentally text-mode applications.

The piecemeal approach has provided only limited satisfaction to programmers trying to compete against true Windows applications, so beginning with 4.9 and continuing through the 5.1 development cycles, we have extended and rounded out the GUI capabilities of A-Shell/BASIC to the extent that you can now create applications which have a true Windows look-and-feel, and can compete head-to-head with "native Windows" applications created in other languages. While there will always be features that some other language has that are not (yet?) in A-Shell/BASIC, we are now realistically at the point where no one should be able to use that as an excuse for not being able to write or sell a modern, competitive application.

The goal of the AUI Toolkit is to not just to provide modern Windows GUI capabilities, but to do so in a framework that maintains at least some degree of compatibility with the existing legacy text, procedural architecture of AlphaBASIC. Ideally, all of the AUI functions would (or will?) work in a purely text environment as well, but that hasn’t been achieved. What has been achieved is a viable means to migrate in an incremental, evolutionary manner from the legacy text environment to the GUI environment, improving the modularity of your programs in the process.


Planning for GUI

This section provides an overview of some of the issues and application characteristics that will make the conversion process easier or harder.

Subtopics

Text Message Tokenization

Spacious Screen Layouts

Use of INFLD

Upper and Lower Case

Parameterized Templates

Catalog Your Fields

Decide on Environments

Analyze, Organize Display Logic


Text Message Tokenization

One of the most obvious differences between traditional legacy text applications and Windows GUI applications is the use of fixed pitch vs. proportional fonts. The obvious problem with proportional fonts is that they take up variable amounts of space depending on the individual character widths. In order for a screen layout to translate easily from fixed pitch to proportional (and back again), the most important factor is the degree to which the text messages are "tokenized". If each text message (field prompt, column header, advisory tip, etc.) is individually positioned by a Tab(x,y), without relying on spaces for positioning, this will make the conversion much easier. Any use of spaces for positioning (relying on the fact that a space occupies one column just like any other character in a fixed pitch font) will not translate well to proportional fonts (where spaces are about half the width of a typical character.) For example:

PRINT TAB(5,5);"Customer Name"; TAB(5,45);"Home Phone";

PRINT TAB(6,5);"Address"; TAB(6,45);"Bus. Phone";

PRINT TAB(7,5);"City"; TAB(7,45);"Fax";

The example above works well with both fixed pitch and proportional fonts. However, the example below will not work well at all, because the prompts in the right hand column which line up in a fixed pitch will not work at all in a proportional font. Not only won’t the column line up, but it will appear much closer to the first column because proportional font spaces are much slimmer than fixed pitch spaces.

PRINT TAB(5,5);"Customer Name Home Phone";

PRINT TAB(6,5);"Address Bus. Phone";

PRINT TAB(7,5);"City Fax";

With a proportional font, the above statements will appear something like this:

Customer Name Home Phone

Address Bus. Phone

City Fax

Aside from examining your source code, a quick way of sizing up how serious a problem you have in this area would be to use the SET AUTOTPRINT feature, which causes all subsequent PRINT statement output to be rendered in a proportional font.

Subtopics

Using OPTIONS=GUI_SPC_IND


Using OPTIONS=GUI_SPC_IND

Updated February 2008

Turning on OPTIONS=GUI_SPC_IND causes PRINT statements to be "tokenized" so that each token is positioned at the place where it would have been positioned if using fixed pitch. It also converts tokens made of hyphens (---------) or equals signs (=========) to graphic horizontal lines. This is best illustrated with the following examples.

this is a linked file

this is a linked file


Spacious Screen Layouts

Another characteristic of legacy text programs that tends to differ from Windows-style programs is that the former have a tendency to jam a lot more information on the screen. 24 rows by 80 columns doesn’t sound like much compared to 1024 x 768 pixels, but you will not find many Windows program which have more than a dozen or so rows of edit fields on a form. (You may see a lot of rows displayed in a spreadsheet-style grid, but rarely do they try to do normal data entry in such a small space.)

A-Shell/Windows offers a number of configuration adjustments (see the Misc. Settings dialog) to help deal with overcrowded screens, but as a general rule, the more crowded your screens, the more difficult it will be to get a pleasing effect on any but the largest, highest resolution displays. In the worst cases, you might need to consider the use of a Modal Dialog Box or a Tab Control to reduce the number of data entry fields on the screen at one time.


Use of INFLD

INFLD.SBR does a lot of the heavy lifting when converting from text to GUI, much of it without any program changes at all. But this only helps if you actually use INFLD for data entry. The more consistent and systematic use you make of INFLD, the easier the conversion will be. In particular, using INFLD for displaying data as well as just inputting is a big help. Also, the more you have centralized your calls to INFLD and standardized your TYPE codes, the better off you will be. (This applies just as well to the text environment as to the GUI environment, and is a good example of how the effort to convert to a GUI might actually improve the text version of your application.)

Note that not all is lost if you use some other input routine, if you do so consistently, because INFLD is able to act as a wrapper for most other input routines. But the reverse is most definitely not true in the GUI world, so you will want to look at converting to INFLD first.


Upper and Lower Case

Proportional fonts generally do not look right when used to display words in all upper case. If your application tends to use all upper case for prompts and data entry, you might want to look at doing a conversion to standard upper and lower case first. (Again, as with some of the other changes recommended above, this will undoubtedly improve the look of your application even in text mode.) If you have a lot of text messages to convert, you might want to write a conversion utility to process all of your source programs, rather than doing them by hand. The XFOLD subroutine could be very useful for such a project, as it provides a way to deal systematically with exceptions.


Parameterized Templates

If you have developed a parameterized model for data entry (or other types of) programs, or have a generator, then obviously you have a big advantage in any kind of conversion, since you can make adjustments to the template or the generator and then replicate the changes through many programs. Even if you haven’t done so before, this might be an opportunity to look at the similarities and commonalities among your hundreds (thousands?) of programs and think about how you can reduce the redundancies using SBX modules, program parameterization, etc. Again, as with other changes suggested above, this will provide as much long term benefit on the text side as on the GUI side.


Catalog Your Fields

This is related to the parameterization idea, but relates to your actual fields (data fields and the screen messages which accompany them) rather than to program structure per se. Having a catalog (simple data dictionary) of all your fields will be even more valuable when you get around to converting to a database, but it is also quite useful in the GUI conversion because it naturally leads towards better separation of business logic from user interface issues. As an example, if you had a catalog (database or maybe just a spreadsheet) of all the fields used in your application, you could have a non-programmer go through it to add tool tips, assign field id’s for documentation links, correct formatting and other inconsistencies, etc. Meanwhile, by getting these user interface details (like the actual text of the field prompts) out of the programs, you will automatically be that much closer to separating your business and interface logic, while encouraging a discipline of parameterization on your programming efforts.

A-Shell can help you get started with such a field catalog by creating a spreadsheet on demand of all GUI controls currently on the screen, when you Ctrl+Shift+Double-Click. By using SET AUTOTPRINT prior to running the program, then invoking the capture when you have a complete set of prompts and data on the screen, you’ll at least have all of the text messages and their positions and sizes. If you use INFLD for data display, you’ll also have the INFLD parameters associated with the data fields, which will get you well on your way.


Decide on Environments

This is a fairly important first step, since if affects which features you can rely on and the extent to which you need to include conditional logic to support different runtime (or even compile-time) environments. At one extreme, you may want to maintain both compile and runtime compatibility across AMOS, UNIX (including dumb serial terminals), as well as Windows, taking advantage of GUI improvements only where appropriate. In this case you have to avoid using any language statements that won’t compile under AMOS, as well as including "IF TEXT THEN X ELSE Y" or similar conditional logic for runtime decisions on GUI versus text mode functions. You also have to avoid the use of SBX routines, unless you are willing to write AMOS equivalents in assembler.

At the opposite extreme, you may decide you only care about the Windows environment, in which case you can use every GUI enhancement available (and can skip the rest of this topic).

Somewhere in the middle are those that no longer care about AMOS compatibility, or who are willing to compile under A-Shell even run AMOS runtimes. If you don’t need AMOS compatibility even at runtime, then you should probably take advantage of SBX routines as much as possible to encapsulate the details of text vs. GUI methods. If you do need AMOS runtime compatibility, you can’t use SBX routines (unless you are willing to write them in AMOS assembler), but might use a scheme involving different sets of ++INCLUDE modules for different environments. If you don’t mind compiling under A-Shell and moving the RUN files to AMOS, then you can use TPRINT and DPRINT. The following table summarizes some of the compatibility relationships between features and environments.

Technique | AMOS Compile | AMOS Runtime | Dumb CRT | Notes
SBX | Y | ? | Y | Requires equivalent SBR written for AMOS for runtime compatibility
Tab(-10,x) | Y | ? | N | AMOS requires ATE client and AM62CG.TDV terminal driver.
TPRINT DPRINT | N | Y | Y | Can be compiled as if PRINT under A-Shell for AMOS runtime compatibility; automatically treated as PRINT by A-Shell if not a graphic-enabled TDV
INFLD | Y | Y |  | Global TYPE |G can activate GUI mode; auto-reverts to text mode if no GUI avail.
AUI CONTROL AUI IMAGE | Y | ? | N | AMOS compatibility would require ATE client plus creation of AUI.SBR. No chance for dumb CRT; better to use conditional logic for text vs. GUI
AUI MENU | Y | ? | N | <same as for AUI CONTROL>
XTREE | Y | ? | N | AMOS requires ATE client, AM62CG.TDV driver, XTREE.SBR (which supports a limited subset of XTREE functionality). For very simple trees, you can use INMEMO instead.
AUI ENVIROMENT | Y | ? | Y | Use other SBR (such as GETJTB) to determine AMOS environment
AUI CONTROL | Y | ? | N | AMOS requires ATE client, AM62CG.TDV driver; use XCALL MIAMEX,119 (MX_CONTROL) instead of AUI_CONTROL.
AUI IMAGE | Y | Y | N | AMOS requires ATE client, AM62CG.TDV driver; use XCALL MIAMEX,119 (MX_CONTROL) instead of AUI_CONTROL.
MOUSE |  |  |  | See the following section on "Using the Mouse."

Subtopics

Using the Mouse


Using the Mouse

The numbers in the following table refer to the notes following the table.

Technique | AShell/ Windows | ATE > AShell | ZTERM > Ashell | ATE > AMOS | ZTERM > AMOS
SmartMouse / AutoMouse | 1 | 1 | 1 | 1 | 1
Hot Spots: Tab(-1,162) | 2 | 3 | 5 | 4 | 5
Mouse Cursor Reporting Tab(-1,158) | 6 | 7 | 8 | 7 | 9
Mouse Cursor Shapes: Tab(-1,160), AG_SETCURSOR; see note 14 | 10 | 11 | 13 | 12 | 13
Mouse Cursor Positioning | 15 |  |  |  |
Clipboard | 16,18 | 16,17,18 | 16,17 | 16,17 | 16,17
AUI | 19 | 20 |  | 21 |

1. SmartMouse (ZTERM) and AutoMouse (ATE/A-Shell) are similar, although the parsing logic may differ slightly between them. In both cases, they attempt to isolate the "token", strip off obvious formatting characters (like a period following a number), and transmit to the host. There is essentially nothing to configure and no need to modify your programs to support it (except perhaps to format your menu text to be compatible with the concept). Note that because they work entirely on the client side, host differences have no effect.

2. Hot Spots originated with the AM72 terminal and InSight. They have been supported in A-Shell/Windows since 4.8. The application uses TAB(-1,162) to define up to 75 rectangular regions at a time, each which can associate a string of up to 16 characters with a single left-click on the area. Unlike SmartMouse / AutoMouse, or Mouse Cursor Reporting, it requires a fair amount of setup in order to define the hot spots for each screen. But, once defined, they are easy to support (since you can define them to send any arbitrary strings you want, include those that generate exitcode values in INFLD). See the sample program AMOUSE in the EXLIB [908,36] for an example.

3. Hot Spots were not implemented in the ATE environment until 5.1.1192.0 (both on the server and client side). On the server side, the main requirement is simply that the TDV support the TCRT codes 159, 160 and 162. (Support was added to the AM75* and AM62C* drivers in 5.1.1192.0.) You can hard-code the ESC sequences if using an older version of A-Shell or a TDV that doesn't support the codes. You can use XCALL WINFLG to test for support on the server side.

4. The Hot Spot TCRT commands were only implemented under AMOS in the AM72.TDV (which virtually no one uses!) and in the AM62CG.TDV distributed with ATE as of 5.1.1192. However, the ESC sequences can easily be added to any driver.

5. ZTERM does not support Hot Spots.

6. Mouse Cursor Reporting is a protocol whereby the client transmits an application-defined leadin followed by a standard byte sequence identifying the cursor position whenever the mouse is clicked. This is approximately equivalent to defining a separate Hot Spot for every row/col position on the screen, except that the click sequence has to be decoded. So it's easier to set up, but harder to support in your application once activated. Both A-Shell/Windows and ZTERM have supported it for many years. But in the case of ZTERM, you need a terminal driver on the server side that supports TAB(-1,158) and TAB(-1,159) commands; see notes 8 and 9. See the EXLIB program MOUSEC in [908,36] for an example.

7. Mouse Cursor Reporting didn't start working in ATE until 5.1.1192.0

8. Mouse Cursor Reporting (TCRT 158 and 159) were added to most of the A-Shell server-side terminal drivers in 5.0.

9. (AMOS support for Mouse Cursor Reporting) – The only drivers known to support this feature on the AMOS side are ZTERM*.TDV, AM62CG.TDV and AM72.TDV. (Not sure about AlphaLAN drivers.) However, adding support is easy (only two ESC sequences are required, and you can bypass the driver and just send the ESC sequences directly to the client if necessary.)

10. Mouse cursor shapes – TAB(-1,160) - have been supported in A-Shell/Windows since at least 4.8.

11. ATE has supported mouse cursor shapes since 5.0, but it required that the TDV on the server side support the TAB(-1,160), which was not always the case. As of 5.1.1192.0 it should be supported in all A-Shell server-side terminal drivers. Also see note 15.

12. No standard AMOS TDVs support TAB(-1,160), except AM72.TDV, and the ATE-supplied AM62CG.TDV

13. ZTERM does not support mouse cursor shapes.

14. A-Shell and ATE support an alternate TAB protocol, AG_SETCURSOR for changing the mouse cursor shape (which works with any version of a " G" driver, i.e. AM62CG, AM75G etc. under either AMOS or A-Shell servers.).

15. A-Shell/Windows supports a primitive mechanism to position the cursor by clicking on an area of the screen. This only makes sense in an application that can move the cursor via arrow key commands (like VUE). Scrolling with the mouse wheel is similarly supported (translated into up/down arrow keys).

16. A-Shell/Windows, ATE and ZTERM support the ability to mark a rectangular section of the screen and paste it into the clipboard. The also both support pasting text from the clipboard (although they have no control over how the application on the receiving end will handle it.)

17. Both ATE and ZTERM support the ZTERM ESC sequence to paste clipboard text.

18. A-Shell (both standalone Windows and server when the client is ATE) support the MX_CLIPBOARD function.

19. The AUI (A-Shell User Interface) subsystem was added to A-Shell in 5.0, although there are on-going enhancements.

20. Most AUI functions are supported in the ATE environment also, although there may be some limitations – see the documentation for the particular routines of interest.

21. A limited subset of the AUI capabilities is available under AMOS when accessed via ATE. You must install the MIAMEX.SBR, XTREE.SBR, IMAGE.SBR subroutines and AM62CG.TDV on the server (and use the AM62CG emulation). For INFLD GUI features, you need INFLD.SBR 7.0 (latest edit is 387). (Only a subset of GUI features are supported, but programs should be mostly compatible across platforms and between INFLD/text and INFLD/GUI implementations.


Analyze, Organize Display Logic

The idea here is to get a good handle on the kinds of screen layouts you use, and how individual layouts break down into categories such as data fields, prompts or labels, headers, background, status messages, etc. You may find that most of your programs have a somewhat consistent 1 or 2 line header display (program title, date, operational mode, etc.). You may also have a status message area, perhaps occupying the bottom 2 lines of every screen. The more you can encapsulate these different display areas into common parameterized routines (ideally, SBX routines), the more flexibility you will have in adapting the design to a GUI environment. (And again, the more separation you will have between your logic and your data.)

As an example, let’s assume you find that you do use a somewhat consistent 2-line screen header, and most programs have a GOSUB HEADER to display it. While you can leave the header alone, or translate it directly into proportional fonts, you will probably find that the kinds of headers that look good in a green-screen layout don’t look so natural in a Window. As a first step in figuring out how to adapt your text screen headers to Windows, it would be very helpful to turn your internal HEADER routine into a HEADER.SBX, which takes parameters such as Program Title, Subtitle, Mode, etc. You will probably also need an Opcode parameter, to distinguish between clearing the entire header area and redrawing it entirely, vs. just updating the Mode or Subtitle field. Some parts of the header, such as the company name, date, time, user, etc., the HEADER.SBX (or BSI) routine can fetch for itself without needing to be passed those parameters.

Once you have a feeling for the GUI environment, you can design a suitable equivalent version of the header. It might be very similar, perhaps just employing a larger font to make it stand out, or you might break it up, putting the title on the Window title bar, eliminating the date and time (already on the Windows task bar), etc.

For the portion of your display devoted to data fields and associated prompts, a fundamental decision to be made is whether to treat the prompts which make up a screen layout as a single entity which must be displayed in its entirety in one operation. Or, you may decide that you can tie each prompt individually to a data field. In the former case, the goal would be to develop a generic "display background screen" routine which you passed a screen identifier to and it fetched the screen form from some external source. In the latter case, the ideal would be to include the prompts as part of your catalog of fields, and develop a generic routine that given a set of fields, is able to draw all the prompts, or all the data. Again, none of this is absolutely required for the GUI conversion, but thinking about it (or better yet doing it) in advance will both simplify the GUI conversion and improve your logic/presentation separation.


GUI Extensions

A desire commonly expressed by A-Shell developers, especially those deploying in Windows environments, is for tools to give existing applications more of a Windows-like GUI (Graphic User Interface). This section provides a handy index to many of the currently available tools and extensions. The table below shows links to topics found elsewhere in the documentation, and following that are discussions on other relevant topics.

Description | Link
Display a File Open / Save Dialog. | Displaying a File Open/Save Dialog
Cut-and paste operations by user, and a subroutine interface to allow applications to copy-to and paste-from the clipboard under program control. | Get/Set Clipboard Text
Saving information to and retrieving it from Windows' Registry. | Registry Operations
Although you can use HOSTEX.SBR to launch any native application, it is sometimes useful to be able to launch the application associated with a particular file type or URL, without knowing exactly what the application is called or where it is. For example, when you click on a URL link inside of an email message, the email application does not need to know which web browser you use or how to launch it; it simply tells Windows to launch the application that goes with this URL. | Shell Execute
Play a sound file. | Play Sound
A-Shell 4.9 introduced the ability to dynamically create real Windows controls in A-Shell. These include dialogs, buttons, checkboxes, radio buttons, group boxes, listboxes, combo boxes, edit controls, tab controls, static text controls, tree controls, etc. Using this technique, you can now using traditional Alpha Basic screen drawing techniques (print commands, tab functions, and subroutines) to create Windows "forms" and dialogs that are nearly indistinguishable from Windows programs created in Visual Basic. | AUI.SBR
Display Windows printer selection | Prompt for Windows Printer
Browse / select directories | Select Windows Folder
Retrieve a Windows directory by its alias/ID | Retrieve Directory Path
Choose a color | Display Color Selection Dialog
Choose a font | Display Font Selection Dialog
'3D' Tabs | Set 3D Tab Attributes
Modify A-Shell GUI Settings | Get/Set A-Shell GUI Settings

Subtopics

Mouse Interaction

Proportional Font Text Objects

XP Themes

Beveling

Imaging

Adding Custom Menu Items


Mouse Interaction

To change the screen icon/image of the cursor, see Set Mouse Cursor.

Subtopics

Mouse Hot Spots

Mouse Cursor Reporting1

AutoMouse Translations


Mouse Hot Spots

The Mouse Hot Spot feature involves defining rectangular areas, that when clicked, send a particular keyboard sequence. The A-Shell implementation is compatible with the AMOS version, but its use is now discouraged since the functionality has been largely superceded by the use of real GUI controls (such as buttons).

A-Shell/Windows supports the extended mouse "hot spot" TCRT protocol originally introduced by Alpha Micro with the AM72 terminal and later promoted in conjunction with InSight. Briefly, this allows you to define arbitrary code strings and associate them with rectangular regions of the screen. When the mouse is clicked within one of these regions, the defined string of codes is transmitted into the keyboard buffer. Because the codes are routed into the keyboard buffer, it is almost trivial to add this capability to existing menu programs. (Just set the code string to the letter or number normally used to select that menu item.) Implementing traditional Windows-type data entry screens, where the mouse can be used to move the cursor to any field, is possible but considerably more difficult. (One approach involves extensive use of the EXITCODE feature within INFLD to define a separate code for each field. Upon exiting from any field, the program would check for one of these exit codes, and if appropriate, jump directly to the field indicated by the code.)

All of the mouse hot spots which are active at one time must be specified in one large Tab(-1,162) sequence, which has the following general form:

print tab(-1,162); Count; Len1; Key1;
Srow1; Scol1; Erow1; Ecol1;
Len2; Key2; Srow2; Scol2;
Erow2; Ecol2; Lenn; Keyn;
Srown; Scoln; Erown; Ecoln;

The coding of the individual parameters is described in the table below:

Parameter | Coding and Description
Count | Code as chr$(N+32) where N is the number of desired hot spots. (N=0 to clear all hot spots.)
Lenn | Code as chr$(L+32) where L is the number of bytes in the following Keyn field. (Maximum key length is 16.)
Keyn | From 1 to 16 bytes to be transmitted into the keyboard buffer when the hot spot is clicked on.
Srown | Code as chr$(R+31) where R is the starting row of the hot spot. Use R=0 for the top status line and R = <screen height+1> for the bottom status line.
Scoln | Column code. If columns is less than or equal to 96, then code as chr$(C+31). Otherwise, code as chr$(25);chr$(C-65) where C is the starting column of the hot spot.
Erown | Ending row of hot spot. Code same as for starting row
Ecoln | Ending column of hot spot. Code same as for starting column.

There is a good general discussion of the technique of Mouse Enabling Your Screens in a section under the same name in Chapter 6 of the inSight Programmer's Reference Guide from Alpha Micro. The A-Shell implementation of the feature is completely compatible with the InSight implementation, except that A-Shell allows you to create hot spots on the top and bottom status lines (by referring to them as row 0 and n+1, respectively, where n is the current height of the screen, typically 24.) For those of you eager to experiment with this technique but not eager to hunt down or read the documentation, A-Shell/Windows is supplied with a sample program, AMOUSE.BAS, complete with source, which adequately demonstrates the range of possibilities.

ZTERM supports many of the InSight TCRT codes and ESC sequences.


Mouse Cursor Reporting1

Like Mouse Hot Spots, Mouse Cursor Reporting has been largely superceded by the use of real GUI controls.

Yet another protocol for sensing mouse clicks, also originating with inSight and currently supported by A-Shell/Windows, ZTERM, and AlphaLAN, is known as "mouse cursor reporting". It differs from the hot spot protocol in that once activated, it transmits control bytes into the keyboard buffer for every mouse click, no matter where it is on the screen. The control bytes indicate the position of the mouse and the button that was clicked (or double-clicked), leaving it to the application to decide how to respond. Unlike the hot spot protocol, this protocol requires that you use a single-byte-at-a-time input routine (such as ACCEPT.SBR, TINKEY.SBR, GET.SBR, GETKEY(), etc., and preferably one with a time-out feature) so that you can properly handle the variable-length sequences sent by the mouse and separate them from other keyboard activity.

To activate mouse cursor reporting, use Tab(-1,158). See the sample program MOUSEC.BAS, included in the release in [7,376] for a good demonstration/example.

Special thanks go to James Jarboe IV for the sample program MOUSEC and for his help in clarifying how mouse cursor reporting works.


AutoMouse Translations

Like Mouse Hot Spots and Mouse Cursor Reporting, AutoMouse Programmable Translations have been largely superceded by GUI controls.

AutoMouse is a variation on the "SmartMouse technology" used in ZTERM. The idea is that when activated, A-Shell will attempt to make sense of any left double-click it receives. The way it does this is by identify the text "token" that was clicked on. For example, if you double click on a number, then it transmits that number into the keyboard buffer. That aspect of AutoMouse is more of a user feature than a development topic, so we won’t pursue it further here.

The AutoMouse Programmable Translations, on the other hand, relate to application development. The idea here is that your program may define its own special text tokens (arbitrary strings which may contains spaces and other delimiters) and associate them with specified keystrokes. This is similar in concept to the hot spots described previously, except that while hot spots are associated with specific positions on the screen, AutoMouse Programmable Translations are associated with specific text strings, wherever they may appear. AutoMouse Programmable Translations are maintained using a subroutine (MX_AMOUSEXLT) instead of via a Tab(-1,162) sequence as for hot spots. The flexibility of the subroutine interface offers the advantage of allowing the addition and deletion of individual translations (instead of having to do them all at once, as with hot spots). For a simple example, consider:

xcall MIAMEX, MX_AMOUSEXLT, 0, STATUS, 0, &

"1. Add Transaction", "1"+chr(13), &

"2. Change Transaction","2"+chr(13), &

"3. Delete Transaction","3"+chr(13), &

"4. Post","4"+chr(13), &

"ESC to Return to Menu",27

This might make sense in a menu program featuring those options. While the default AutoMouse translations would handle the numeric options in this menu automatically, you would have to click right on the numbers. After the above call, the user would be able to click anywhere, for example, on "1. Add Transaction" to transmit a "1" followed by a carriage return. Clicking anywhere on the string "ESC To Return to Menu" would send an ESC. (Note we can specify the chr(27) for ESC simply as 27, since it is a single byte value.) The multi-byte translations require a literal or mapped string, or a string expression.

When beveling is enabled and the screen background is a suitable mid-level color (not black or white), clicking on an AutoMouse token will briefly "buttonize" the token, giving it the impression of having been pushed slightly in.

See the latest MIAMEX sample program for another example.


Proportional Font Text Objects

You can convert ordinary PRINT statements, which output fixed pitch text to the screen, into proportional text objects using any of the following methods:

TPRINT: If you compile with the /X:2 switch, you can use the TPRINT statement, which functions exactly like PRINT (to the screen) except that it uses the current default proportional GUI font. (You can override that font via Settings menu.)

DPRINT: Nearly identical to TPRINT, except it creates a sunken panel for the output text, and thus is likely to be used for printing "Data" (whereas TPRINT is for "Text"). Note that the size of the sunken panel will be based on the size that would be needed if the standard fixed pitch font was being used. Also note that when INFLD is in GUI mode (TYPE |G), it displays the field (when not actively editing it) using the DPRINT style.

EPRINT. Similar to DPRINT, except that it uses an EDIT control to display the string, rather than a sunken static text control. Note that EPRINT adds one to the width of the control if the width was otherwise going to be only one column; this should eliminate most of the cases where upper case text is truncated, without causing too much havoc with screen layouts.

In a text-only environment (i.e. under UNIX when the terminal driver name does not end in "G"), TPRINT, DPRINT and EPRINT will revert to acting just like PRINT.

SET.LIT supports an AUTOTPRINT setting that causes existing PRINT statements to act as if they were TPRINT. This is the fastest way to convert your entire application from fixed to proportional text, and to size up the areas where you may have to make some formatting adjustments.

The A-Shell compiler will compile TPRINT and DPRINT as if they were PRINT, if the /X:2 switch is not set. (This might allow you to generate a RUN file compatible with AMOS even though your program uses TPRINT and DPRINT).

Note that DPRINT applies "intelligent justfication" logic to decide whether the field should be right, left or center justified. If both the first and last character of a string expression are spaces, then it center justifies. If the first character is a space or monetary symbol and the last character is a non-space, then it right justifies. Otherwise it left justifies. This should result in the desired alignment for data fields in most cases, although you may have to adjust any fields in which you were intentionally counting on the fixed width of spaces. In the proportional font world, you cannot count on spaces for positioning of text; always use explicit Tab(x,y) statements for each output token to avoid confusion.

Subtopics

Alignment Problems with Text


Alignment Problems with Text

When switching from fixed to proportional text, you are likely to run into problems with columns not aligning as they used to. This is due to the fact that with proportional fonts, character widths vary depending on the character. In particularly, the space character is very thin compared to most others, especially the capital letters (like W). However, because A-Shell continues to use the same row/col grid for Tab(x,y) commands, you can usually solve your alignment problems by following these guidelines:

• Always use a Tab(x,y) prior to outputting a "token" of text. This will at least ensure that your text prompts and messages always start in a consistent position. (In other words, don't use spaces to position your text.)

• Avoid overwriting parts of existing messages. Instead, try to replace the entire message. (You cannot reliably determine the X,Y coordinates of a particular character within a proportional text string.)

• To overwrite an existing text object, you can simply Tab(X,Y) to the start of it and output a new text string. (You might want to pad the string with sufficient spaces so that in the case of text mode, it would fully overwrite the string.)

• Add a few extra spaces on the end of text tokens, to provide some "breathing room" for the proportional version of the message to expand if it contains a lot of wide (or capital) letters. For example:

TPRINT TAB(X,Y);"Vendor Name: "; TPRINT TAB(X,Y);MESSAGE$;" ";

One situation you may run into is where you use a combination of Tab(x,y) with some spaces to align fields like this:

1. Name:

Addr:

12. Parish:

Postal code:

Assuming the last two items were variables (i.e. depending on some other flag, you might display "City", or "Borough" instead of "Parish", and "Zip Code" instead of "Postal Code"), then you might have created the above display with code like the following:

PRINT TAB(10,5);" 1. Name:"

PRINT TAB(11,5);" Addr:"

PRINT TAB(12,5);"12. ";CITY$

PRINT TAB(13,9);PHONE$

This works because the spaces occupy the same width as the numeric digits and the period, so in all cases the main part of the label starts in column 9. But if we convert these PRINT statements to TPRINT (or use SET AUTOTPRINT), they will no longer line up because spaces, digits, and periods all have different widths in the proportional font world. Following the guidelines give above, the ideal solution would be to recode this as:

TPRINT TAB(10,5);" 1. ";TAB(10,9);"Name:"

TPRINT TAB(11,5);" ";TAB(11,9);"Addr:"

TPRINT TAB(12,5);"12. ";TAB(12,9);CITY$

TPRINT TAB(13,5);" ";TAB(13,9);PHONE$

But unfortunately that involves a lot of retyping. Slightly less retyping would be this solution:

TPRINT TAB(10,5);" 1. ";"Name:"

TPRINT TAB(11,5);" ";"Addr:"

TPRINT TAB(12,5);"12. ";CITY$

TPRINT TAB(13,5);" ";PHONE$

The above solution works because each of the TPRINT statements now has two arguments. The position of the second argument is calculated based on the number of characters in the first (which is 4 in each case), regardless of the fact that those characters will occupy different widths when rendered using a proportional font. So the result is equivalent to the previous example, where the Tab(x,9) was explicit.

But even this may be a lot of work if you have a lot of screens like this. In the case, you may want to use the shortcut of adding OPTIONS=GUI_SPC_IND to the MIAME.INI. This causes any string which contains leading spaces, or a combination of leading spaces, numeric, digits, a period, and one or more spaces, to be output as if it was a separate print object from the rest of the string. In other words:

PRINT TAB(10,5);" 1. Name:

Would be interpreted as if it had been coded as:

PRINT TAB(10,5);" 1. ";"Name:"

This will generally result in the kind of alignment you were probably hoping for. (However, unless you know you have this problem, we don’t recommend just turning on this switch as a precautionary measure, because it increases screen complexity which may lead to some other undesirable side-effect.)


XP Themes

Windows XP Themes are supported for any applicable GUI controls, provided that the file ashw32.exe.manifest is present in the same directory from which ashw32.exe was launched. XP Themes provide various visual enhancements, such as buttons which automatically highlight when the cursor passes over them. However, a downside of XP Themes is that you lose the ability to control the colors of most GUI objects. The one exception is that you can still control the foreground color of text objects, but you must add 64 to the foreground color parameter (fgc) of AUI "CONTROL", MX_WINCTL, or AG_CONTROL commands.


Beveling

Beveling has been largely superceded by more powerful GUI enhancements, although is still of interest for traditional text mode programs.

Beveling is the term we have given to a display enhancement that uses shading to give a three dimensional (or "beveled") appearance to certain display features. Currently this affects only line drawing characters (such as box borders) and input fields (processed with INFLD.SBR), but may potentially be expanded to other features as opportunities are recognized. It may be turned on (and saved with the other settings) via the Settings menu, or it may be turned on and off under program control, using AG_BEVEL (as described in Tab (-10,x) ).

Most people prefer the beveled look, at it gives the application a more "Windows-like" appearance, but for best results you should follow the guidelines and tips described below.

Since the effect is produced by drawing lines in lighter and darker shades of the background color (to simulate the effect of light and shadow), it requires that you use a "middle-range" background color. By "middle-range", we mean one whose R, G, and B values are somewhere in the middle between 0 and 255. The worst case is black (RGB=0,0,0) or white (RGB=255,255,255), since there is no way to make a darker version of black or a lighter version of white. But in fact, most of the standard colors are hardly any better, since they are typically made up of various combinations of 0 and 255. For example, the typical blue is made up of R=0,G=0,B=255; yellow is typically R=255,G=255,B=0. It is possible to simulate darker and lighter shades of such colors, but the effect is not as good as with colors whose RGB values are, say, between 50 and 200. The best results are probably achieved with the standard Windows gray background, which is R=192,G=192,B=192, although any pastel color will work well both in terms of making the beveling stand out and in terms of making the application appear at first glance to be more Windows-like than DOS-like.

You can redefine the RGB values for the standard color numbers 0-15 either via the Custom Colors option in the Settings | Colors dialog, or via AG_SETCOLOR. Also note that as an alternative to explicitly defining a suitable background color via RGB codes, you can use MX_SYSBCLR or SET TERM SYSBCOLOR to associate one of the standard numeric colors 0-7 with the current Windows background color, which is typically gray but changes according to the desktop color scheme selected in the Windows control panel.

When drawing boxes or grids using line drawing characters, the beveling effect looks best if you make the background color of the lines (or box border, if using a routine such as MSBOXX.SBR) match the background color of the surrounding screen area.

To maximize the Windows-like effect of the beveled (sunken) INFLD fields, you may want to experiment with the INFLD color parameters, for example, making the background of the field light gray while editing it and then returning it to the surrounding background color once the field is updated. (This has nothing to do with beveling but it is often nice to select a redisplay foreground color that is slightly different from the initial data foreground color to highlight those fields that have been edited.) The easiest way to experiment with INFLD color parameters is via the INI.CLR file or under MX_INICLR.


Imaging

As of A-Shell / Windows Build 771, you can perform basic display and print operations on BMP, JPG, TIF and PCX format images. Display operations are handled by AUI.SBR|document=2zconref\3xcall.docx;bookmark=AUI_IMAGE, while printing operations are handled by the IMAGE embedded print file. TWAIN ACQUIRE (i.e. scanning or other image input) is also supported in IMAGE.SBR.

Aside from the documentation for IMAGE.SBR and //IMAGE, you will find in the DSK0:[7,376] sample file account a sample program, IMAGE.BAS and four sample image files (SAMPLE.JPG, SAMPLE,PCX, SAMPLE.TIF, SAMPLE.BMP.) There is also a sample GDI print file, IMAGE.TXT, which prints a couple of the sample images. The IMAGE.BAS program prompts you for opcodes, filenames, and other parameters needed by the IMAGE.SBR routine, allowing you to experiment with the various parameters. It also demonstrates one way to implement the ability to temporarily maximize the image via a function key, menu prompt, or mouse click.

If you don’t have the sample programs, you can install just them from the standard A-Shell / Windows release package by selecting the Custom install method.

IMAGE.SBR and the //IMAGE printing function are implemented with the help of an external library, VIC32.DLL, which due to licensing restrictions, is not included in the standard release of A-Shell. However, the licensing fee is rather nominal and activating the library can be accomplished without having to update the A-Shell executable. Contact MicroSabio for details on obtaining and distributing the library.

Unisys Corp holds a patent on the LZW compression type used in nearly all GIF files found on the web. Although the imaging library we are using supports LZW decompression, it is not enabled until you obtain some kind of "certificate" from Unisys indicating that you have paid their license fee. In the absence of that, we suggest you stick with uncompressed images or other compression types (such as JPEG for color images and G3/G4 TIFF for bi-level document images.)


Adding Custom Menu Items

One way to quickly make your applications more "Windows-like" is to use the Windows menu bar system as an alternative to traditional text-style application menus. AUI_MENU provides the necessary capabilities to accomplish this, and is adequately documented. Here we will instead go over a detailed example of adding Windows menu selections to a "typical" accounting application.

Our example application uses two levels of main menus. The first level offers choices for the various accounting modules (GL, AR, AP) while the second level displays the individual programs or tasks within each module. Our plan is to add Windows menus for both levels to the menu bar of the top-level menu program so that the user can bypass the second level and go directly to any individual program/task. We will accomplish this by creating an MDF (Menu Definition File) listing all of the programs and organizing them into three drop-down menus.

So far, this is very straightforward. The only complexities are deciding which of the menu action mechanisms to use, and how to integrate these actions with the existing main menu program. Briefly, the choices for each menu action are:

• Execute a Windows command line

• Call a custom DLL

• Force a string of characters into the keyboard buffer

• Specify a document or URL and let Windows decide how to launch the appropriate application to open it.

Subtopics

Keyboard String Menus

Command Line Menus

Registry (or Shell Execute) Menus


Keyboard String Menus

Of the four types of menu items, probably the easiest to use is the type that transmits a string of keyboard characters when selected. These can be set up to transmit the same characters that a real user would type on the keyboard, and thus the program needs no special code to detect and process the selections (other than adding them to the menu in the first place and deleting them later.) This is possible even though a single Windows menu option in this case will span two separate menu programs. For example, to select the first choice on the top level menu and the third choice on the second level menu, we could just make the keyboard string be "1"+chr(13)+"3"+chr(13). The first part of the string would be responded to by the top level menu program, and the second part would still be in the keyboard buffer, and thus responded to by the second level menu program.

One complication to be overcome, though, is how to input the chr(13) (aka carriage return) control character into the MDF. Fortunately, there are two ways to do this. One is to use the Control-G lead-in, which tells the A-Shell/VUE editor to insert the next character into the file as-is, rather than treating it as a command. So the sequence Control-G Control-M would insert the carriage return character (i.e. chr(13) or Control-M) into the file, displaying it as a dim M. The only problem with this approach is that may create confusion when printing or typing the MDF on the screen or editing it with another editor. To avoid those problems, as of Build 828.2, you can also use the special notation of ^X to indicate Control-X (where X can be any character from A-Z, plus [, ], \, ^, and _.) For example, consider the following line:

&G/L,"Account Maintenance",KBD,"1^M3^M"

This would create a menu item that transmitted the keyboard characters "1" followed by chr(13) (aka Control-M) followed by "3" followed by another Control-M.

The other complication with this approach is to make sure you disable or remove the menu items as soon as we change to a context where there are no longer appropriate. Fortunately again, this is reasonably simply in a menu program. All we have to do is insert a call to disable or delete the menus immediately prior to chaining from or exiting the menu.

To complete our example, here is the MENU.MDF we’ll use:

;Menu Definition File for GL, AR, AP, PR

;G/L is the first item on the main menu;

; its selections can be reached by entering 1 <CR>

; (to get to the GLMENU program), then the appropriate

; # followed by another CR…

TOP,"&G/L",SUB

&G/L,"Account Maintenance", KBD,"1^M1^M"

&G/L,"Period Maintenance",KBD,"1^M2^M"

&G/L,"Transaction Entry", KBD,"1^M3^M"

&G/L,"Financial Statements", KBD,"1^M4^M"

;A/R is the second item on the main menu

TOP,"&A/R",SUB

&A/R,"Customer Maintenance", KBD,"2^M1^M"

&A/R,"Sales Transactions", KBD,"2^M2^M"

&A/R,"Cash Receipts",CMD, KBD,"2^M3^M"

&A/R,"A/R Reports",CMD, KBD,"2^M4^M"

;A/P is the third item on the main menu

TOP,"&A/P",SUB

&A/R,"Vendor Maintenance", KBD,"3^M1^M"

&A/R,"Expense Acct Maintenance", KBD,"3^M2^M"

&A/R,"Voucher Entry", KBD,"3^M3^M"

&A/R,"Payment Processing", KBD,"3^M4^M"

&A/R,"A/P Reports", KBD,"3^M5^M"

;We'll also add a separator bar and then our application's

; documentation file to the Help menu

HELP,"h1",SEP

HELP,"Application Documentation",REG,"c:\vm\miame\doc\app.pdf"

Note that the "h1" in the first HELP menu line above doesn’t display but is needed in order to have a unique identifier for the separator bar, so that it can be deleted later. Also note that the second HELP menu line above use the menu type "REG" rather than "KBD". The "REG" type uses the Windows Registry to open the specified document with the application that has been previously registered to understand that type (Acrobat in the case of PDF.)

Here’s an example of the code to reference the above MDF, adding it to the menu bar at the start of the main menu program and removing it before ending or chaining to another program:

START:

OPCODE = 1 : STATE = 0 ! (add, enable)

call DO'WIN'MENU

DO'MAIN'MENU:

! Display and process main menu…

print tab(10,10);"1. General Ledger"

print tab(12,10);"2. Accounts Receivable"

print tab(14,10);"3. Accounts Payable"

print tab(18,10);"Enter Selection:"

input "",SELECT

if (SELECT < 1 or SELECT > 3) goto EXIT'PROGRAM

CHAIN'TO'SELECTION:

OPCODE = 3 ! (delete)

call DO'WIN'MENU

chain PROGRAM$(SELECT)

EXIT'PROGRAM:

OPCODE = 3 ! (delete)

call DO'WIN'MENU

end

! add/delete/change Windows menu items

! Inputs: OPCODE (1=add, 2=change, 3=delete); STATE (0=enable, 1=disable)

DO'WIN'MENU:

! If MAIN.MDF exists, do it

LOOKUP "MAIN.MDF",X

if X # 0 then xcall MIAMEX, MX_WINMNU, OPCODE, "MAIN.MDF", STATE, STATUS

return

One "error" in the above program is that it removes the HELP menu selection (which presumably ought to be available from anywhere in the application) along with all of the rest of the menus when it chains out of the main menu. To treat one set of menu items (in this case the HELP menu) differently from another set, you can use multiple MDFs. In this case, it would have made sense to have one MDF for the G/L, A/R and A/P menus, and one for the HELP menu. The HELP menu could then have been left in place while the others were deleted. We could also have just handled the HELP menu addition with the "traditional" form of MX_WINMNU, since there is little advantage to the MDF technique for adding just one item.

When using multiple sets of menu items, the main limitation is that they be structurally independent from each other so that they can be added and deleted independently from each other. The simplest way to ensure this is to not mix groups of independent menu items on the same submenu.


Command Line Menus

Let’s consider the pros and cons of using command line menus rather than keyboard string menus in the above example. The main two shortcomings of keyboard string menus are that you have to be careful to disable them as soon as the program’s input context changes, and you can only perform actions that can otherwise be performed with the keyboard. This latter comment may not seem like much of a "shortcoming" until we consider the benefits of being able to add functionality to programs via menus without otherwise modifying the programs. The help menu item in the previous example is a good illustration of this; it adds a capability (viewing documentation in Acrobat) to your program that may not have been previously implemented via keyboard commands. Furthermore, it can be added to the menu once and left there to be used from any of the programs in your application.

The command line menu type overcomes both of the above shortcomings. First, the commands are executed independently of your program context and thus you don’t need to worry as much about changing the menu items as the program changes state. Second, you can execute any legal Windows command line, and thus you are not at all bound by the limitations of your application. For example, you can launch desktop utilities like the calculator (CALC.EXE), or entirely new applications, like a backup or email program. However, you might wonder what good this does when all you want to do (in the case of our simple accounting menu example) is select and run a program within A-Shell. It turns out you can use the command line approach for this case as well. The trick is to launch a new instance of A-Shell. Consider the following excerpt from our MDF, this time using the command line approach:

TOP,"&G/L",SUB

&G/L,"Account Maintenance", CMD,"$ASHELL –e run glamnt"

&G/L,"Period Maintenance",CMD,"$ASHELL –e run actmnt"

&G/L,"Transaction Entry", CMD,"$ASHELL –e run trxedt"

&G/L,"Financial Statements", CMD,"$ASHELL –e run finstm"

TOP,"&Utilities",SUB

&Utilities,"Calculator", CMD,"calc.exe $"

Here we used the special macro $ASHELL, which the MDF logic understands to mean launch another instance of A-Shell using the same A-Shell executable and MIAME.INI file as the current instance. The remainder of the command line simply runs the specified program, counting on the fact that the new instance of A-Shell will start out logged in to our current directory. If the programs were in another directory, we would either have to specify their location, or perhaps use a command file to first log us to the proper location and then run the program. The –e switch forces the instance to terminate when the specified program returns to the dot prompt.

The new instance of A-Shell will be on top of the original instance, which will be suspended until the new instance terminates. At that point, you’ll be right back where you started.

This approach has the potential advantage that it might be applicable anywhere in the application. For example, you might be in the A/P voucher entry program and want to look up an account in the G/L. Rather than exit the voucher program to switch to G/L, you might just select the G/L Account Maintenance option from the menu, launching a new instance for that program, then return to the original program when done.

There are, however, some shortcomings to this approach as well. First, it requires that your programs can be run from the dot prompt without first going through some security logic in the main menu. (Many applications load some kind of security or other context information into memory within the main menu, which is needed by other programs in the application. In such a case, the above plan would not work.) Another potential problem might be confusion on the part of the user over how to get back to where they were.

Note that you don’t have to suspend the original instance while the new instance is running. It might make more sense in this case to allow the user to operate as many independent sessions as they like, toggling between them at will. You can accomplish this by adding a " $" to the end of the command line string (e.g. "$ASHELL –e run actmnt $".) (We chose to do this with the calculator item so that we wouldn’t have to close the calculator after each use.)


Registry (or Shell Execute) Menus

The REG type of menu item (used in our original example above for the Application Help menu) is similar to the command line (CMD) type, in that it launches an independent application and thus has no particular connection to the context of the current application. The main advantage of the REG type over the CMD type is that you don’t have to worry about knowing the name or path of the executable needed. For example, if you want to open a CSV file as a spreadsheet, to use the CMD method, you would need to know the full pathname of the spreadsheet program. With the REG approach, you don’t even need to know what the program name is, much less its location.

The main disadvantage of the REG type is that you can’t easily pass any command line arguments. Also, you can’t suspend the current A-Shell session while the new application runs.

Since you can mix and match menu types, even within a single MDF, understanding the advantages and disadvantages of each type will allow you to use the best type for each circumstance.

You can add up to 125 individual menu items.


Steps to GUI

The project to convert your text interface to a GUI may seem overwhelming, especially after reading the previous section. This section will attempt to serve as an antidote to the paralysis of where to start, by spelling out a series of relatively simple steps to get you started down the road, using as an example a rather old-fashioned AlphaACCOUNTING-style employee maintenance program, which looks like this:

this is a linked image

Subtopics

Configure the Display

Activate INFLD GUI Mode

Activate GUI Version of PCKLST

Application Adjustments

Event-driven Programming


Configure the Display

All of the GUI improvements we will be talking about here require, at least to some extent, the use of A-Shell/Windows, either directly in a Windows environment, or indirectly via ATE in a UNIX or AMOS server environment. So the first step is just to configure the A-Shell/Windows display settings.

Subtopics

Define the Color Palette

Adjust Leading to Relieve Crowding

Remove Status Lines

Adjust the Font


Define the Color Palette

Launch your application, then exit back to a dot prompt and use the SET TERM command to see what your standard foreground and background colors are:

.SET TERM

Current terminal settings for TSKAAA are:

Terminal driver: PCTDVG

Baud rate: 19200

Terminal width: 80

Terminal height: 24

Foreground color: 6

Background color: 0

Beveling: Auto

Sys bg color None

Win bg color None

Win text color None

In the above display, the foreground color is 6 (default is green) and the background is 0 (default is black). (If your screen is not green on black, then you have already redefined the meaning of the color palette entries for background 0 and/or foreground 6.) If your application never changes its basic color scheme, then you have two options for doing so yourself. One is for you to initialize the foreground and background color settings when you start the app, either via a CMD file with SET TERM FCOLOR and SET TERM BCOLOR commands, or preferably by adjusting the default or a custom CLR.INI file. The other method is to redefine the palette so that that the default palette numbers foreground 6 and background 0 refer to something other than green on black. See the Colors Menufor details on color customization.

Changing a monochrome green-on-black application to some other pair of colors is not a major improvement, and is not specifically related to GUI, but if you use the Custom Color option on the Color dialog to define some subtle or pastel colors rather than the primary DOS-style colors of the default palette can bring a psychological improvement. The following two shots give an idea of this. First, we have a traditional DOS-like color scheme:

this is a linked image

Then we improve things slightly by moving to a more pastel palette:

this is a linked image

If your intent is to move towards a Windows-like look, and especially an XP-style, look, then you will have to start getting use to the Windows gray dialog background color. The particular shade of gray seems to change which each version of Windows and with the desktop theme, so it isn’t practical to try to define it manually. Instead, decide which of the 8 background palette numbers you want to dedicate to gray. (0 is probably a good bet, since that is the most common background number to use. Or, if you want to preserve your options, you might use 7, which is otherwise the least commonly used color number.) To define the palette number n as matching the current Windows gray background color, use one of the following commands:

.SET TERM SYSBCOLOR n

xcall MIAMEX,MX_SYSBCLR,1,n

PRINT TAB(-10,AG_SYSBCLR);n;chr(127);

While you’re redefining your background color to match Windows, you might as well do the same with your standard foreground (text) color and editing window background colors. The standard text color in Windows is black, and the standard editing window background is white. Since these coincide with existing palette entries (although the particular shades of black and white may differ), it seems reasonable to link those palette numbers to the Windows color definitions of black text and white editing windows. Again you have your choice of the following methods:

.SET TERM WINBCOLOR 1 ; (define fg 1 to match windows edit bg)

.SET TERM WINTXTCLR 0 ; (define bg 0 to match windows text clr)

or

FGTXT = 1 ! FG color # to use for text

BGSYS = 0 ! BG color # to use for main window

BGEDT = 1 ! BG color # to use for editing windows

xcall MIAMEX,MX_SYSBCLR,1,BGSYS,BGEDT,FGTXT

or

PRINT TAB(-10,AG_SYSBCLR);BGSYS;",";BGEDT;",";FGTXT;chr(127);

After setting the above colors, you will probably want to save them in your current settings file (use menu File...Save), but note that this only saves the current Windows definitions for those colors. If the Windows colors have been changed by the next time you launch A-Shell, they will again be out of sync. So it is best to incorporate the above color initialization logic into your application startup so it is always current.


Adjust Leading to Relieve Crowding

The next simple step is use the Misc. Settings dialog to add "leading" (vertical spacing between the rows). Windows GUI programs rarely pack fields as close together as a typical single-spaced text application, and short of redesigning your screen layout, adding leading is the simplest way to alleviate the crowding. Note that the font size will shrink as you increase the leading, so you probably will find the best compromise somewhere in the vicinity of 6.


Remove Status Lines

While we’re trying to get a more spacious feeling, we might want to get rid of the top and bottom status lines, which aren’t really being used in this application. The following show shows the effect of the Windows color scheme, increasing the leading to 6, and removing the status lines (see Enable Disable Status Lines in Tab (-10,x) Functions to accomplish this):

this is a linked image


Adjust the Font

If your application is fairly good at Text Message Tokenization then you may want to try converting it all to proportional font text. The simplest way to try this is to use the command:

.SET AUTOTPRINT

before running your application. This will have the effect of making all your PRINT statements act like TPRINT, which is to say that rather than drawing fixed pitch text on the screen, they will create static text controls. If the effect is a disaster, then use SET NOAUTOTPRINT to restore the normal fixed pitch mode. In this case, you’ll may want to leave the fixed-to-proportional conversion to later. At this point, just make sure you have a good scalable font (Settings...Font...System Fixed); Lucida Console seems to the be a good choice.

If your application looks somewhat reasonable with SET AUTOTPRINT on, then you can proceed to tinker with the proportional font options. First, check which font you have set; Settings...Fonts...GUI (Control). The default (and certainly the most Windows standard) is achieved if the font setting is blank. But you can always choose a specific font if you don’t like the Sans Serif default font.

Here’s what our sample app looks like with SET AUTOTPRINT turned on:

Because this application happens to use individually positioned print tokens for nearly every screen output, the switch to a proportional font actually works pretty well.

With proportional fonts, you have the option to scale them to the window size or not. Most Windows programs do not scale the fonts (or the control sizes) when the window size changes. A-Shell/Windows will always scale row/column coordinate system to the window size (which will have the effect of making rectangular controls like buttons scale with it), but you can defeat the font scaling by setting the font scaling option in the Misc. Settings dialog to 0. In that case, you will probably want to adjust the Window size until you get a pleasing balance between the font size and the window size. If you set the font scaling option to a percentage (somewhere in the range of 80-110), then the fonts get bigger as the window gets bigger. Again, some experimentation will be needed to find a suitable balance between the scaling factor and the window size.

Whether or not you scale the proportional fonts, they have to fit inside their (generally invisible) rectangular containers. When the font gets too big relative to the container size, the text gets clipped or may wrap. Again, since this effect is not always predictable, it is best to choose a size or scale factor that is small enough to leave some margin for expansion.

Most of the other options in the Misc Settings dialog will not apply until after we get into the GUI version of INFLD, so we’ll discuss those after INFLD in the next section.


Activate INFLD GUI Mode

Assuming your application uses INFLD, at least for input, you can activate the GUI version globally by adding SBR=INFDEF:|G to your MIAME.INI file. Without any changes to your application, this will cause INFLD to use Windows edit controls for field editing. In the case of date fields, it will use a date picker control. For fields with a list of possible choices defined in SETDEF, it will use a combo box. However, unless your application uses INFLD to display data (as well as to edit it), the enhancement will only affect the field that is being editing, and to some extent the fields that have been edited on the current screen. As each field is updated by INFLD, it will, by default, be converted to a sunken static text field. You can force it to redisplay the updated field using an edit box by adding |E to your SBR=INFDEF statement. To go one step further, you can use ||C instead of |E, which will leave the date pickers and combo boxes in place also. (If you don’t like the date pickers and combo boxes, use |g instead of |G.)

In our first attempt with |G active, our screen now looks like this. (The only thing which has changed so far is that the field we are actually editing, in this case, Social Security, is now a Windows edit box, and the fields which have been edited and redisplayed by INFLD are displayed in sunken boxes.

this is a linked image

To get INFLD to redisplay updated fields using the same kind of edit box as when editing, you can add ||C to the SBR=INFDEF specification, to get the result as shown below (after editing fields 3-7 and 10-11):

this is a linked image

The two dates in the example above have a dropdown button next to them, which brings up a date picker calendar control. If you don’t like this effect at all, and just want to use a regular edit box to edit dates, then replace |G with |g. If you want to us the date picker for editing, but don’t want it to display with the dropdown button, then use |E in place of ||C.

The display above is starting to look a lot like a regular Windows-style program, but there are still some deficiencies. One is that not all of the fields display the same way. This is because the program uses PRINT to display data, which produces the plain text version, and then when we edit a field, INFLD redisplays it using one of its formats (sunken gray box, white edit box, etc.). Furthermore, some fields even get redisplayed using PRINT immediately after editing, which means that even after editing them we don’t get the edit box or sunken rectangle. (In the above screen, this is the case with Marital Status, which gets input as a numeric code, then redisplayed as text. This is also the case with the fields 12-15.)

Speaking of field numbers, the very idea of numbering fields on the screen is somewhat unusual in a Windows program. The idea of an "Any Change? " prompt asking you which field number to change is even more questionable. To deal with these and other differences between our legacy program and a modern Windows-style program, we’ll need to make some actual improvements to the programs. But before getting into that, we’ll first finish up discussing some of the display adjustments and other GUI enhancements which can be done without any program changes.

Subtopics

INFLD-Related Display Settings


INFLD-Related Display Settings

Once you have some edit controls (and possibly combo boxes) displayed, you can appreciate the checkbox options on the Misc. Settings dialog.

Subtopics

Fixed Pitch Font

Standard Colors In Edit Boxes

Edit Boxes Use Leading Space

Edit Box Height


Fixed Pitch Font

When INFLD uses a Windows-style edit control, it normally uses a proportional font as well (the point is, after all, to act like Windows.) But proportional fonts do have the annoying feature of sometimes making it difficult to tell how many characters can be entered, based on the space available. The effect becomes more pronounced as the size of the field increases, to the point that for a 30 character address field, you might only be half way to the end when you run out of characters (if using lower case, spaces, periods, etc.). If using all capitals, the reverse could be true. One answer to this problem is to say "hey, that’s how it is in Windows applications." Another answer would be to set this fixed pitch font option, which will cause INFLD to use a fixed pitch font inside of any edit boxes it creates. The screen shot above was using the standard proportional font for editing, which is why the social security field, even though full with the maximum number of characters, appears as if it could support about 3 more digits. The following series shows the effect more dramatically, on an alphanumeric field. In each, case, the field as shown as the maximum allowed number of characters:

The image above shows the address line being actively edited in a fixed pitch font, while the field below has been redisplayed in the standard proportional font. Note that even the fixed pitch font option does not always exactly fill the field ; in the example above, it looks like we should be able to fit one more character. This discrepancy is due to the lack of smoothness in scaling fixed pitch fonts. The two samples below give a good comparison between the fixed and proportional font. The first shows how the field above looks when redisplayed (since the standard redisplay uses a static text control and thus is not affected by the "fixed pitch font in edit box" option.) Some might find the huge discrepancy between what the field looks like while being editing and after (or before) editing to be an annoyance; others might like the way it makes it the active field stand out, and be easier to read, both of which may be appreciated by keypunch operators who might otherwise have difficulty seeing which field is active (by the tiny vertical bar caret) or what character they are about to insert or delete.

The second example shows what the address line looks like when being actively edited in a proportional font. Note that although it looks nicer in general, it does suffer from the problem of being more compact, and thus the field looks half empty even after reaching the maximum number of characters:


Standard Colors In Edit Boxes

INFLD has long supported the ability to define a set of colors which it would use, depending on the mode it was in. This can result in an interesting effect on a color text screen, but is of questionable value in a Windows GUI, (where it may just seem weird). This checkbox option provides a simple way to ignore your carefully selected INFLD colors and just use the Windows default (black text on a white box). Our examples above were already using standard colors so we’ll move on to the next option.


Edit Boxes Use Leading Space

Because an edit box uses up some space drawing its border, and due to the varying factors which affect font size, you may find that your edit boxes are too small to either fit the editing font, or to see the editing font if it does fit. The example below illustrates a borderline case, where the characters are not being clipped, but we are still getting little tick marks along the baseline of the edit box due to the cursor and/or tails of characters intersecting the edge of the box.

To alleviate this slightly, we’ll set this option, which will cause the edit controls to use up to half of the leading space to make the control a bit taller. (This requires, of course, that you set your external leading to a non-zero value, preferably something like 6.) This provides a slight improvement:


Edit Box Height

This is a weird option. It arises because for some odd reason, Windows allows edit boxes to be independently scalable, but not combo boxes, whose size is based on the font associated with it. If you have a mixture of combo boxes and edit boxes on a screen, you may find that it looks bad for them to be different sizes, as in the following excerpt:

If so, check this option, which will force the edit box height to conform to the combo box height as shown here:

Note that this will defeat the ability to scale the combo box height by increasing the window height. But you should be able to adjust the height of these controls by changing your font scaling factor.


Activate GUI Version of PCKLST

If your application uses PCKLST.LST, you can convert it to use the GUI version (XTREE) by adding the following to your MIAME.INI:

SBR=PCKLST_GUI

This will convert the standard text implementation, which looks something like this...

...into the XTREE version, which looks something like this:

Note that in the above examples, the XTREE version shows more columns, because the default proportional font is smaller and thus allows more information to fit into the same screen area. It also supports horizontal and vertical scroll bars, but no bottom title bar. See the XTREE documentation for more details on its many features which go way beyond what the text version (PCKLST) supported.


Application Adjustments

At this point, we are running out of GUI improvements that you can activate without making any changes to your programs. So now we begin to discuss some of the things you can do systematically and/or strategically to get the best results with the least effort. These are mostly in the form of ideas, rather than step-by-step instructions.

Subtopics

Buttons

Yes/No Fields and Checkboxes

Groupboxes

Anachronisms

INFLD

Subroutines for Each Field

Parameterized Field Attributes

Main Menu

Printing With GDI

Dialogs


Buttons

Many programs display lists of short keyboard (possibly function key) commands that are available in a particular context. It is generally simple to convert these to self documenting buttons which perform the same actions as the original commands and thus do not affect anything but the code that displays them. This is also a good way to document special keys that may be used from any field, like F1 for help, F2 for previous screen, etc. See the table of Virtual Key Symbolic Names for information on how to code a button to act like a function key. Note that buttons don’t have to be any more than one row high, so they don’t take any more room than a single line of text.


Yes/No Fields and Checkboxes

A simple type code addition of ||c to an existing Yes/No INFLD field will turn it into a checkbox. This is particularly effective if you have many Y/N fields, such as in a configuration screen. Displaying it as a checkbox does not change the way the field interacts with the application, so it is a very simple change.


Groupboxes

Organize groups of fields by combining them into a Groupbox Control. This can be a nearly one-to-one substitution for existing MSBOXX boxes, but then you have the option of making the fields be children to the groupbox, which means that their coordinates are relative to it. This allows them to be moved around together, and also deleted as a unit.


Anachronisms

Your application may use some display features that are out of place in a modern GUI. For example, many legacy programs display a standard header on every screen which includes the program title, time, date, etc. This may make sense on a dumb terminal, but makes little sense on a PC, where the time and date is available on the status bar. You can move the program title to the title bar of the window, or, after eliminating the superfluous bits, make it stand out by putting it in a large font.

Another example is the traditional AlphaACCOUNTING-style Add/Change/Delete/Print menu which takes a ridiculous amount of display space just to set a mode switch. Better to move right to the editing screen, and if it is necessary to establish an Add/Change/Delete mode, display a row of buttons for that purpose.

After replacing the header and installing a button menu along the bottom, here’s what our screen looks like (OK, the banner isn’t quite right for the application, but you get the idea):

this is a linked image


INFLD

The advantage of using INFLD for displaying fields is that you can use one set of field parameters for both input and display, letting INFLD do the formatting work as well as adapting to the capabilities of the display environment. But rather than convert your PRINT FIELD’1 statements to INFLD.SBR, you might as well go one short step further and just use the same code that you use for editing the fields to display it. For example, if your program has separate routines for displaying and editing your data, e.g.:

DISPLAY'FIELDS:

PRINT TAB(8,10);FIELD1

PRINT TAB(9,10);FIELD2 USING "#####.##"

etc.

INPUT'FIELDS:

CALL INPUT'FIELD1

CALL INPUT'FIELD2

etc.

Assuming the INPUT’FIELDS routines use INFLD already, just make sure they use a common global variable for the OPCODE parameter (1=edit, 2=display), in which case you can reorganize it as follows:

DISPLAY'FIELDS:

OPCODE = INFOP_DISPLAY ! display

CALL DO'FIELDS

RETURN

INPUT'FIELDS:

OPCODE = INFOP_PRELOAD ! input

CALL DO'FIELDS

RETURN

DO'FIELDS: ! caller sets OPCODE=1 for input, 2 for display

CALL FIELD1

CALL FIELD2

etc.

With INFLD doing the output, our screen now looks like this:

this is a linked image

Now we are getting pretty close, at least visually, but we still have the text INMEMO display of comments. To complete the visual makeover, we’ll change that to a multi-line edit control:

this is a linked image

At this point, the only obvious trace of text mode aesthetics visible is the use of numbers with the field labels. Aside from that, we still have some work to do on the operational side to implement the ability to click on any field.


Subroutines for Each Field

Adopt a common subroutine model for each field, which uses parameters to set the field location, and returns an exitcode. This allows the special details of the field to be kept together with the field, while still allowing you to adjust the inter-field behavior at the level above, or even to use the same field editing/display code in different contexts. For example, rather than the traditional AlphaACCOUNTING model:

FIELD1:

<set INFLD parameters>

xcall INFLD, ...

IF INXCTL OR CNGCTL GOTO ANYCNG

FIELD2:

<set INFLD parameters>

xcall INFLD, ...

IF INXCTL OR CNGCTL GOTO ANYCNG

etc.

Break the above monolith into individual fields and move the interfield logic to a higher level, i.e.:

DO'FIELDS: ! caller sets OPCODE=1 for input, 2 for display

ON FNO CALL FIELD1,FIELD2,FIELD3,...

<check exitcodes, set next FNO accordingly>

IF NOT DONE GOTO DO'FIELDS

ANYCNG:

<confirm record update>

FIELD1:

<set INFLD parameters>

xcall INFLD, ...

RETURN

FIELD2:

<set INFLD parameters>

xcall INFLD, ...

RETURN


Parameterized Field Attributes

Changing from hard-coded to variable field parameters won’t immediately improve the interface to your programs, but it will further the cause of separating your business and display logic, and make it much easier to implement more comprehensive application improvements, such as the switch to Event-Driven control.

One way to quickly extract the existing hard-coded field parameters and coordinates is to add the SBR=INFDEF:|G|E global switches and then bring up your main display and step through all of the fields so that they get processed by INFLD. Then hit Control-Right-Double-Click to capture the field data in a spreadsheet, then rearrange the columns to get it down to just the information you need for each field (row, column, TYPE codes, etc.) Save your field parameters in a file for each screen, and use a standard MAP layout and import routine to load the parameters at the start of each program.

Among the many advantages of having your field parameters separated from the programs, it allows a non-programmer to do a lot of useful but otherwise tedious cleanup and improvement, for example, adding tooltips and help keys. It will also allow you to centralize your field editing logic in a single routine, used throughout your application, which you can then update once to add global features like field-level help.


Main Menu

It might well be time to re-design your main menu, especially if it was designed for terminals, complete with graphic characters to make a logo. Since this is the part of the application that people see the most, it makes sense to give it a little design effort. One thing to consider is consolidating all of the submenus into a single Tab Control (with separate tabs for the submenus, and the items themselves being clickable.) Another thing to do is display a large graphic, logo or banner. If you don’t have one already developed, hire a designer to make you one. A third suggestion is to use the remaining space to provide shortcuts (via buttons or clickable text, or maybe even a list box) to the most common functions, making it even quick for the user to get where they want to go. This is much more effective if the user can customize their own shortcuts. Once you put all your menu options in a file, with security levels and other related attributes for each choice, it will be relatively easy to tinker with the menu design.


Printing With GDI

The GDI printing commands provide an easy way to upgrade plain text output to incorporate fonts and other graphics. And ATE makes this available even to UNIX. Furthermore, unless you had a heavy investment in embedding your own ESC sequences (or PCL code) in your reports, you can insert GDI directives into existing printouts, so it isn’t necessary to do a major redesign of your reports to give them a facelift.


Dialogs

The Model Dialog Box control makes it easy to create pop-up windows for displaying and editing information that doesn’t fit neatly into the existing screen. Because they don’t overwrite the existing window, can be moved around by the user, and force the user to exit the dialog before returning to the original screen, they are particularly easy to integrate into existing code:


Event-driven Programming

A major difference in the architecture of modern programming languages designed for point-and-click user interfaces, and traditional programming languages like AlphaBASIC, is in how the program maintains control. In the point-and-click world, programs are "Event Driven", meaning that external events (like mouse clicks) are able to interrupt the program, forcing it to execute a "handler" for the event, whereas in the procedural model, the program decides for itself what statement to execute next.

This may sound like a drastic and un-bridgeable difference, making it next to impossible to provide a point-and-click interface from a procedural language. But like so many other so-called new technologies in the computer world, the innovations are more in the terminology or way of looking at things than in the way they actually work. Just as you don’t need C++ or Java to implement object-oriented programming techniques, you don’t need VB or .Net to implement event-driven programming techniques.

All operating systems of interest to this discussion, including AMOS, UNIX, and Windows, support event interrupts for handling keyboard, network, disk, and other events which occur on their own timetables. Typically the operating system associates a driver which each type of event. The driver services the hardware, transferring data between it and memory buffers where it can be operated on by higher software levels. All these operating systems also maintain one or more run queues to schedule work to be done in time slices.

The main thing that distinguishes event-driven programming from procedural programming is that in the former, the main body of the program is a loop that waits for event messages, calling routines to process the events of interest and passing the others on to a default event handler. In a procedural (sometimes called "linear" program) , the "main loop", if any, is typically related to waiting for the user to perform some keyboard action. However, there is nothing stopping you from implementing your own wait-for-event main loop and letting the AUI translate all the events of interest (mouse, keyboard, timer) into keyboard sequences which are reduced to exit codes by INFLD. As shown below, the two models then become very similar in appearance.

In the standard event-driven model (top diagram), the operating system translates all of the events into coded messages. The main loop waits on these events, checks to see if they are of interest and passes them on to either its own hander or the default OS handler.

In the procedural version (bottom diagram), A-Shell filters the events (using the standard event-driven model), handling the ones which don’t apply to the application itself, and translating the ones that do apply into keyboard sequences which are picked up by whatever input routine is currently running (presumably INFLD). Depending on the event and or what the user types, the characteristics of the field, etc., the input routine will eventually exit, returning an exit code to the main loop. The main loop then determines from the exitcode what the next field or procedure will be, which eventually leads to another input operation and the process starts over again.

You’ll note that neither of these flow charts makes at all clear where the "real work" of the program is done. In the top model, it is all buried within the "Process Event" routine. Typically a startup event will trigger the creation of the main window in the application, and then it will be up to the user to click on a button or something equivalent to trigger the event which starts a particular process within the program. While that particular process is running (for example, generating a report), subsequent events just queue up until the current subroutine returns back to the main loop. Similarly, in the procedural version, the same thing happens. While it is generating the report, if keystrokes will just queue up, waiting until it gets back to the next input routine. In either case, you can (and should) improve the event-responsiveness of long procedures by checking to see if there are any events waiting (but in both cases that can get tricky if the subsequent events contradict the current activity.)

The main problem with the standard event-driven model, is that since there are so many possible events, you end up with myriad little event-handling routines which are difficult to keep track of and coordinate with each other. Along the same lines, any lengthy process must be broken up into event-sized chunks because suspending the event-handler for too long makes the program appear to have gone dead.

The procedural version is actually easier to work with from the programmer standpoint, because the number of events is reduced to a manageable number, and because A-Shell itself takes care of the low-level events (like painting the window) independent of the application, the application doesn’t have to artificially break lengthy procedures down into tiny independent event-sized chunks. In a business application environment, all that is really needed in a lengthy procedure like a report is that it check for a single cancel event, which can be done within the context of the current procedure without returning to the main loop.

Another advantage of the procedural model is that it allows the program to decide for itself when it is appropriate for the user to interrupt the flow of the procedure. For example, when filling out a certain type of form, there may be no reasonable need to jump around randomly from one field to another, and allowing it (which the standard event driven model is powerless to stop) may just complicate the ability of the program to both validate the data and assist the user in the data entry process by supplying appropriate defaults based on the context. In such a program, the procedural model can simply ignore misguided mouse-clicks and go from field-to-field in a logical manner until the form is filled out or the user aborts the operation.

Still, it may far from trivial or even obvious how to convert a traditional procedural data entry model to this event-driven equivalent. To help analyze that question, here is a flow chart representing the traditional field-by-field (aka "AlphaACCOUNTING-style") data entry logic:

This flowchart is quite a long ways from either of the event-drive versions above. It does actually have logic after or between each field to decide whether to proceed to the next field or jump to the "Any Change?" prompt. In many cases, programmers have kept this model but added additional logic to process other exitcode conditions, perhaps to support moving backwards on up arrow, displaying help, etc. You can actually retain this model and still support the ability to click on any field to edit it, but it means that each of the test routines (shown above as "Abort or Change Mode?") has to be upgraded to support the ability to jump to any field. This will not be efficient from a programming standpoint.

However, it would not be that difficult to change the model above to the model below:

Essentially what we have done is converted each of the "Input Field #n" routines from the previous flowchart and turned them into individual subroutines, to be called based on the value of the Fno (field number) variable. (The box marked "Input routine for Field #Fno" would probably consist of a statement of the form "on FNO call FIELD1, FIELD2, …"etc.) The condition logic "Abort or Change Mode?" in between each field from the previous model is now centralized into a single routine which is represented here by the four shaded boxes. In practice, this routine might become quite complicated in the sense of having a lot of individual IF statements to deal with the various permutations of Exitcodes and field . But, it is all nicely contained, and if carefully parameterized, a single copy of this logic can be applied to all your data entry programs. (It really just needs to know the range of field numbers, but might also benefit from access to an array of field information allowing it to make advanced decisions based on the geometry of the field layout.)

The only other step absolutely required to complete the conversion is to arrange for all of the applicable field objects to send identifiable keyboard strings that are turned into exitcodes when they are clicked. This will be a matter of displaying any fields you want clickable support for using the AUI CONTROL cmd parameter, or using the INFLD hlpidx parameter.

The last box ("Done with fields, wait for event") could be no more than the traditional "Any Change?" prompt. But to achieve a more typical GUI style, you would probably replace the "Any Change?" prompt with two or more buttons (OK and CANCEL). Upon falling out of the last field, you could use Eventwait to put the focus on one of the two buttons and allow the user to select one via the keyboard, or to click on one of the fields to go back to edit it.

Subtopics

Further Improvements


Further Improvements

There is always the "danger" that once you start on this conversion process, you’ll soon realize that with a little more up-front effort, you can create a generic data entry program or at least a template that can be used with an array of field data, a set of prompts (or screen layout), a set of field-entry routines, and some standardized file i/o logic to replace dozens of existing custom programs. The first one of these is hard to write, but after that, you may be able to convert significant chunks of your application quite easily.

An added payback for the effort involved is that you will have achieved a high degree of separation between your user interface, data, and business logic. But it is important to note that the arguments for doing a more thorough overhaul of your software should be based on the merits of better structure, easier maintenance, etc., since it is not strictly needed just to achieve the GUI interface.


GUI Tools

Tool Name | Description
ASE | The A-Shell Editor (ASE, pronounced "Ace") is an integrated development environment for A-Shell developed by Firmaware and available to all A-Shell programmers. Please contact MicroSabio for more information.
LEO | The most sophisticated AUI development tool is a program called LEO, developed by Jorge Tavares and included in the A-Shell Editor. Use the same contact info as above.
Text Attribute Manipulator | Tool to allow you to change the default text attributes.
Control Dump | Debugging and design tool.
Control Definition Snapshot | Related to tracing GUI events is the ability to get a snapshot of the definitions of all the controls currently in existence. See Control Dump.

Subtopics

Text Attribute Manipulator

Control Dump


Text Attribute Manipulator

At the opposite extreme from LEO is a very simple-minded tool built in to A-Shell which allows you to change the default text attributes as a way of experimenting with design changes to existing legacy screens. To access the tool, first issue the SET AUTOTPRINT command (see Adjust the Font) to convert plain text PRINT statements into static text control objects. Then, use Control+Shift+DoubleRightClick to bring up GUI Control Operations popup dialog:

this is a linked image

Select the Change Text Attributes button to bring up this dialog:

this is a linked image

Changes here will affect the attributes of subsequently output text, without changing the attributes of text objects already on the screen. As an example of how you might use this in conjunction with a legacy text file maintenance program, just before displaying the main screen, you could set up some text attributes. Then, cause your program to actually output the background labels, which will now be in the color/font/style selected. Now, try changing the attributes again, perhaps using a different color and maybe DPRINT instead of TPRINT, and then cause the program to display data fields. If you end up with something pleasing, you can capture and record all the field data, with the attributes you applied, by generating and saving the control dump.


Control Dump

The control dump is a tool used both for debugging as well as for design. It outputs relevant details about each currently defined control to a CSV file and loads it into your local spreadsheet application. The spreadsheet data can later be fed back into the LEO design tool, or used to build your own repository of field layout definitions. To generate the dump, use Control+Shift+DoubleRightClick to display the GUI Control Operations popup dialog (see above) and then click the button Dump the Control Info to Spreadsheet.


Environment Variables

Updated December 2010

Several environment variables are created and/or used by A-Shell and ATE, and they are all described in the following sections. Note that:

• In nearly every command context where you can specify a filespec, you can embed an environment variable reference by surrounding the environment variable name by %, e.g. "%MIAME%\doc\ashelp.mdf".

• A-Shell treats environment variable names as case insensitive (i.e. %MIAME% and %miame% are equivalent). This is consistent with Windows, which treats environment variables as case insensitive, but it might be confusing in the UNIX environment, where environment variable names are case sensitive (and traditionally upper case.)

• ATE-related environment variables (e.g. ATECACHE, ATEPERMCACHE) are recognized by any instance of A-Shell that is aware of an ATE configuration (i.e. via the -atecfg cfgname command line parameter). Practically speaking, this means that child processes launched by ATE (such as APEX, or the File>Open Local Session menu function), understand filespecs containing ATE environment variables such as %ATECACHE%. This is particularly useful for the //META,FTP GDI directive, which is often processed by APEX in a child instance of ATE (and therefore previously didn't understand %ATECACHE%). This feature was added in A-Shell 1133 of January 2009.

Variable | Platform | Description
APEX | Windows | Defines the location where the APEX work files and archived print files (.apf) are kept. If not defined the default is <My Documents>\APEX. (The <My Documents> directory is determined from the Registry entry \\HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Personal.) If that is not found, it uses %TEMP%\APEX. The directory will be created as needed, provided that the parent directory exists.
ASHCLIENTIP | UNIX | Optional definition of the client's IP address.
ASHFTPDEBUG | Windows | Activates low level FTP debugging
ASHTMP | UNIX | Directory to use for creation of temporary files used during spool processing.
ASQLTRACE | All | Set to 1 to activate detailed tracing of SQL.SBR operations.
ASWCACHE |  | Defines local directory for automatic image caching.
ATE | ATE | Same as %MIAME% but for ATE only
ATECACHE | ATE | Temporary cache (cleared on exit)
ATEPERMCACHE | ATE | Permanent cache (not cleared on exit)
ATEEXE | ATE | ATE or A-Shell/Windows executable filespec (Pseudo-environment variable)
ATELICMODE | ATE | Returns a value indicating ATE license method.
ATELOCALDIR | ATE | Default Local Directory from the connection properties dialog.
ATEPROFILE | ATE | ATE defines this variable to match the name of the current connection profile.
ATEVER | ATE | ATE or A-Shell/Windows version (pseudo-environment variable)
FORCEATE | Windows | Use ATE protocol for some XCALL communications.
HOME | UNIX | Standard UNIX variable defining the user's home directory.
MIAME | All | A-Shell base directory—i.e., the location of miame.ini.
MIAMEFILE | All | Complete filespec of miame.ini; is created automatically by A-Shell once it locates miame.ini.
PERMCACHE | ATE | Alias for ATEPERMCACHE
REMOTEHOST | UNIX | Same as ASHCLIENTIP, but somewhat extended.
TERM | UNIX | Standard UNIX variable defining terminal type
XTREERAW | ATE | Disable XTREE data transfer optimization.


ASHCLIENTIP

Optional definition of the client's IP address. When a connection is made to a A-Shell / UNIX, an attempt is made to identify the client's IP address by various means. This is the first step, and is mainly of use with sophisticated front-end connection managers that may prevent the true client IP from being determined by the normal means.


ASHFTPDEBUG

If you define this variable, the FTPDLX file transfer routine (used by ATE implicitly and by A-Shell/Windows when you explicitly call FTPDLX) will output detailed, low-level debugging information to the file %TEMP%\ftpdebug.log (prior to A-Shell build 1153 of June 2009, the log file was named c:\debug.log). Note that even without this, a somewhat higher-level debug log of the last file transfer can always be found in the file FTPDLX.LOG (in the current directory.)


ASHTMP

Optional definition of directory to use for creation of temporary files used during spool processing. Temporary files are often used to assemble the completed spool request from parts, such as PREFIX and SUFFIX options, or resulting from pre-filtering, before sending to the system spool queue.) If ASHTMP not defined, the MIAME directory is used.


ASWCACHE

Added August 2015

To help alleviate the performance overhead when many image files or icons are loaded from a network file server, images may now be automatically cached on the local workstation provided the following:

• The environment variable ASWCACHE is defined and points to a valid directory. The directory will be created if it doesn't exist, provided the parent directory exists. It can be anywhere, but obviously should be on a local drive.

• The operation of loading the image file into memory takes more than 10 ms. This has been determined by limited testing as a reasonable threshhold between typical performance of local disks and that of network disks.

• AUI_CONTROL will automatically check the cache first whenever it creates an image control, eliminating the overhead of reloading the file over the network if it is cached locally.

Comments

Since the images are auto-cached as used, and auto-removed from the cache on exit, there is no need for any special management on the application's part—i.e. for manually syncing from the file server to the local workstation. However, since the benefit of the cacheing occurs starting with the second load of each image, it is only useful in applications which repetitively load the same images or icons, from a file server, many times during a session.

An easy way to set the environment variable is via the MX_SETENV function, or SETENV.LIT, e.g.

.SETENV ASWCACHE=C:\VM\MIAME\CACHE

Warning: Since the cache directory is cleared on exit, you must be careful not to use a directory containing permanent files!!!!!!!!!

You can trace the the cache logic by activating the FOPENS trace option. It shows the search operations, and also records how long the image load operation takes; look for "loadandresizex" in the ashlog.log or debug message window, e.g.in the following, the load takes just over 16 ms (16001 microseconds), and thus would be auto-cached if the cache is defined.

loadandresizex (\\SERVER\icons\BETA\clock.png), rc=0, himg=78dfd0 [16001 us]

History

2015 June, A-Shell 6.1.1412: Add new enviornment variable to A-Shell


ATE

Same as MIAME, except that it is only recognized by ATE, and thus is useful for referring to the ATE base directory in commands executed on the host computer. For example, to transfer a file from the host to an ATE subdirectory using ZTXFER, you could use %ATE% to refer to the ATE base directory without any danger of the host computer expanding the environment variable relative to the host, as it would with %MIAME%.


ATECACHE

ATE defines this variable to point to the temporary cache directory as specified on the Misc tab of the ATE configuration dialog. This is the standard location for storing temporary files related to your application commonly required by the PC (images, icons, etc.) that are not needed beyond the end of the current session. (The directory is cleared on exit from the ATE session, unless the ATECACHE and ATEPERMCACHE directories are the same.)


ATEPERMCACHE

ATE defines this variable to point to the permanent cache directory as specified on the Misc tab of the ATE configuration dialog. This is the standard location for storing files related to your application commonly required by the PC (images, icons, etc.) that are somewhat permanent in nature.


ATEEXE

This isn't a real environment variable, but if queried via the AG_GETENV command, will return the full filespec of the ATE client or A-Shell/Windows executable, e.g. "c:\Program Files\MicroSabio\ATE\bin\ashw32.exe".


ATELICMODE

Added November 2010

The pseudo-environment variable ATELICMODE is supported in AG_GETENV to return a single decimal value containing flags indicating how the ATE workstation was licensed. The bottom 8 bits of the value are 0 if successfully licensed, else one of the LICF_xxx flags from ASHINC:ASHELL.DEF.

The next byte(s) contain one or more bit flags from ATELF_xxx:

Symbol | Value | Meaning
ATELF_PROTO | &h0100 | ATE handshake was initiated, and also that the ATE client is at least 5.1.1164.0. (Prior to that, command TAB(-10,AG_GETENV);"ATELICMODE";chr(127) will return an empty string.
ATELF_PC | &h0200 | ATE client has a local license.
ATELF_SRV1 | &h0400 | The server attempted to pass the ATE license via the new streamlined protocol (1162+)
ATELF_SRV2 | &h0800 | The server attempted to pass the ATE license via the LICENS/ATESRV mechanism. This also implies that the server is less than 5.1.1162.0 and/or that the passed license wasn't valid (in which case the lower byte should be <>0).
ATELF_AUX | &h1000 | The server attempted to pass an auxiliary license to the client. (Will always be combined with ATELF_SRV2.)

History

2009 October, A-Shell 1164: Function added to A-Shell


ATELOCALDIR

ATE defines this variable to point to the local FTP directory specified on the FTP tab of the ATE configuration dialog. This has been somewhat superseded by the ATECACHE and ATEPERMCACHE directories, but might still have some utility depending on your application.


ATEVER

This isn't a real environment variable, but if queried via the AG_GETENV command, will return the version of the ATE client or A-Shell/Windows executable, e.g. "4.9(930)-1".


FORCEATE

If defined (e.g. FORCEATE=1), A-Shell Windows will use the ATE protocol for communicating between certain XCALLs and their GUI implementations, instead of the more direct method. Currently this only affects XTREE, but might in theory be expanded to other XCALLs. The intent is purely for debugging purposes. (Emulating ATE within a single workstation is simpler to debug than a "normal" ATE environment where the client and server are on different machines and even different operating systems.)


HOME

Standard UNIX variable defining the user's home directory. This is only used by A-Shell to look for a file .PRINTER containing the name of the default printer if no printer specified in the spool request and no default defined in miame.ini or the EZ-SPOOL configuration files. The file should just consist of the desired printer name on the first line.


MIAME

This should specify the A-Shell base directory (i.e. the directory where the miame.ini is found, and under which are various control directories such as doc, bin, dsk0, etc. Under UNIX, this variable is usually predefined in a common login profile (such as /etc/profile or $HOME/bash_profile), so that the miame.ini specification does not have to be explicitly added to the A-Shell command line. Under Windows, the miame.ini specification is usually included in the command line associated with the shortcut/icon, eliminating the motivation for pre-defining it. Note that although A-Shell does not automatically define this variable, it will recognize and interpret %MIAME% as the directory where the current miame.ini is located.


PERMCACHE

This is an alias for the actual environment variable ATEPERMCACHE. (If you are going to manually create the environment variable, define it as ATEPERMCACHE. When referencing the environment variable, A-Shell will interpret PERMCACHE as equivalent to ATEPERMCACHE.)


REMOTEHOST

Optional definition of the client's IP address. Same concept as ASHCLIENTIP, except that it is checked only if ASHCLIENTIP not defined, and after a scan of the system accounting database fails to come up with a match. REMOTEHOST is defined automatically by some shells. Note that in the case of CONDEV.SBR, the REMOTEHOST definition will be used in preference to an IP determined by any other means (and thus you should avoid defining both REMOTEHOST and ASHCLIENTIP differently.


TERM

This is the standard UNIX environment variable for the current terminal type. A-Shell queries this variable to determine which driver to use. If it matches one of the internal drivers, it uses the internal driver; otherwise it uses the generic curses interface. You can confirm that A-Shell recognizes your TERM type by executing SET TERM. If it shows the terminal type as GENERIC, then it doesn't recognize your TERM type.


XTREERAW

If defined (e.g. XTREERAW=1) on either the ATE client or the server job to which the client is attached, XTREE data transfer optimization is disabled. This is mainly intended for testing or debugging issues relating to the optimization logic introduced in 5.0.993 XTREE for reducing the amount of raw data transferred between XTREE and the application during cell editing validation.


Overview

"ISAM-A" is the name for A-Shell's implementation of Alpha Micro's ISAM PLUS file system. It is based on a commercial third-party ISAM product called D-ISAM, which in turn is an upward-compatible version of the Informix C-ISAM library.

Using the third-party library meant that we could not provide compatibility with Alpha Micro's ISAM PLUS at the binary file level, although files can be easily converted using the ISMUTL dump and load operations. But it did allow us to maintain BASIC source and RUN compatibility with virtually all of the ISAM PLUS language statements. In addition, the commercial library is very fast and robust, and supports a number of additional features which give it several advantages over the AMOS version. The following several topics provide additional details about programming with ISAM-A, including differences between the AMOS (ISAM PLUS) and A-Shell (ISAM-A) versions, extensions, and a reference to the language statements.


Specifications & Features

The following table lists various sizes, capacities and limits for ISAM-A files and processing. Note, however, that some of these limits have been arbitrarily set just for efficiency. If you have legitimate need for larger limits, contact us. Also note that where the word "extension" appears in the table below, this indicates a feature that was not present in the AMOS version and which may require some modification to your application; see A-Shell Extensions for more details.

Feature | Specification
Maximum record size | 8192
Maximum number of keys per record | 20
Maximum DAT file size | Prior to A-Shell 4.9.948: 2GB As of A-Shell 4.9.948: 1TB
Maximum IDX file size | Prior to A-Shell 5.1.1134: 2GB As of A-Shell 5.1.1134: 1TB
Maximum # of records per file | 2 ^ 31
Maximum bytes per key | 80
Maximum parts (fields) per key | 20
Maximum number of duplicate keys | 65536
Compressed keys | yes (optional, extension)
Compressed data records | yes (optional, extension)
Transaction support | yes (extension)
File recovery from log | yes (extension)
Audit trail | maybe (extension, under consideration)
Auto expansion of file | yes
Index rebuild utility | yes
Index verification utility | yes
Add/delete index without dump/reload | yes
ODBC / OLEDB / SQL access | yes (via third party utilities)
Maximum INPUT CSV line length | 4k
Maximum ? TAB(x) | 4095 in A-Shell 5.1, 472 in A-Shell 5.0


ISAM-A vs. ISAM

The following points may be of interest to developers considering migration from ISAM (aka ISAM 1.0) to ISAM-A (aka ISAM 2.0):

Subtopics

ISAM-A Pros and Cons

Locking

File Structure

File Access Statement Syntax Ambiguity

File Administration Utilities

Converting Files to ISAM-A

Converting Programs to ISAM-A


ISAM-A Pros and Cons

ISAM-A is an all-around better system than ISAM. It's faster, more robust, offers more features, and is easier to use. One significant feature is the ability to go backwards (e.g. GET'PREVIOUS) as well as forwards through the indexes. On the ease-of-use front, particularly noteworthy is the fact that all of the index maintenance is automatic. In other words, when you create or update a record, all keys are updated for you. It is even possible to add and delete indexes to existing files, without even recompiling the programs that access them (provided you don't delete an index that is being used to access the file). On a similar note, the ISAM-A ISMUTL utility allows you to verify and rebuild indexes without having to provide the index configuration specs or dump and reload the file. In ISAM 1.0, all index operations must be manually and explicitly handled by the program.

The above mentioned advantages notwithstanding, ISAM-A does have a couple of limitations which can impede the easy migration from ISAM 1.0. The most significant is that ISAM-A does not allow synthetic keys. In other words, there will always be one key entry in each index for each record, and it will match the data in the record. In ISAM 1.0, it was possible to add multiple keys for a single record in a single index, or to have data records with no keys, or for keys to be formatted differently than in the data record. For example, for an alphabetic name index, in ISAM 1.0, you could have the data in upper and lower case but fold the keys to upper case. In general, these kinds of issues can be dealt with during conversion by a combination of adding fields to the data record to match the desired keys, and/or by creating additional files just to use the indexes (i.e. effectively ignoring the data). Note that in the latter case, although it is possible to store record numbers and to access ISAM-A files by record number, this should be highly discouraged. Instead, if you want to create a synthetic index, link it to the main file by means of field which is a unique key to the main file.

The other limitation relates to non-standard manipulation of the data file. Although ISAM 1.0 provides operations for adding and deleting records, some developers either bypassed them or extended them, taking advantage of the fact that the data files were accessible as ordinary random files. A simple example would be a case where, in order to go beyond the 512 byte record size limit in ISAM 1.0, you would add a "side-car" data file which essentially shared an index with the main data file. This kind of situation is easily dealt with during conversion by just combining the side-car files into one, larger, data record. In more exotic cases, you may need to rethink your file design. It is worth noting, though, that these "limitations" of ISAM-A are essentially the same kinds of "limitations" you will find in any relational database, which are the "price" for gaining access to many advantages, such as the ability to have a single, generic index verification/rebuild utility that works on all files (as opposed to a motley collection of specialized rebuild programs that would be needed to handle all these "tricks" under ISAM 1.0).


Locking

ISAM-A has integrated locking, independent of LOKSER. For ISAM 1.0, LOKSER was recommended, but not mandatory. If not use, then it was mandatory that you implement your own locking scheme, using something like XLOCK or FLOCK.


File Structure

Both versions use a single data file (.DAT for ISAM-A, .IDA for ISAM 1.0), and at least one index file, and both use a single OPEN statement to open the combination of the index and the data. However, while ISAM-A stores all the indexes in a single IDX (which are all opened at the same time), ISAM 1.0 using a separate IDX file for each index, and required additional OPEN statements for each of the secondary indexes.

ISAM 1.0 data files used "blocking", meaning that individual records could not be split across 512 byte boundaries. Thus, if you had a record size of 128 bytes and wanted to add one more field, you might as well increase the record size to 170, because anything between 129 and 170 will result in only three records per 512 byte block (with wasted space at the end of the block). ISAM-A uses "span'blocks" mode, meaning that records are stacked end to end with no concern for block boundaries. This is much more efficient on a modern operating system, but does mean that the data file will probably not be a multiple of 512 bytes, and thus may "appear" as a sequential instead of random file (e.g. to the LOOKUP statement or DIR command). See OPTIONS=ABSLOOKUP.


File Access Statement Syntax Ambiguity

ISAM-A uses a different set of statements for accessing the file than ISAM 1.0, so for the most part there is no confusion at the source code level. (They share the same CLOSE statement, but this is true with every other file type as well.) The one ambiguity is in the OPEN statements, which are syntactically similar but semantically different:

ISAM-A:

OPEN #channel, filespec, mode, recno, fstat {,end'file} {, wait'record} {,wait'file} {,read'only}

ISAM 1.0:

OPEN #channel, filespec, mode, recsize, recno {, wait'record} {,wait'file}

If the mode is INDEXED or INDEXED'EXCLUSIVE, the compiler cannot tell from the syntax alone which version of ISAM you are trying to open, and thus must rely on COMPIL switches and rules:

• OCMPIL assumes ISAM 1.0, while COMPIL and COMPLP (or any version of the A-Shell compiler with /X:1 or /X:2) assume ISAM-A

• Adding the /I switch causes COMPIL and COMPLP to assume ISAM 1.0 when ambiguous.

• Under AMOS, ORUN only supported ISAM 1.0, while RUN and RUNP supported both. Under A-Shell, there is only one RUN and it supports both versions of ISAM. (There is no ambiguity in the RUN file tokens.)

• With COMPIL and COMPLP, you can use non-ambiguous forms of the Mode to force the compiler to recognize your intent, regardless of the switches used. ISAMP'INDEXED and ISAMP'INDEXED'EXCLUSIVE indicate ISAM-A, while ISAM'INDEXED and ISAM'INDEXED'EXCLUSIVE indicate ISAM 1.0.

• At runtime attempting to open an ISAM file using the wrong version will result in either a file not found (Error 17) or a file type mismatch (Error 25).


File Administration Utilities

ISAM 1.0 uses ISMBLD.LIT to create files and ISMDMP.LIT to dump or display their structure. ISAM-A uses ISMUTL.LIT to perform these operations as well as several others. A-Shell also provides a utility called ISMCHK which facilitates performing unattended verification of many files at a time (e.g. at night).


Converting Files to ISAM-A

Although the ISAM and ISAM-A files have different structures, you can convert the data by dumping the ISAM 1.0 file to a sequential file using ISMDMP, and then creating your ISAM-A file and loading it from that sequential file using ISMUTL.

The AMOS and A-Shell versions of ISAM-A files are more similar, but still are not binary compatible so you have to perform some kind of conversion. The most straightforward is to dump the file on one system with ISMUTL, transfer the sequential file to the other system, then reload it using ISMUTL. If you have a lot of huge files to transfer, it may be more efficient to use the A-Shell ISMCVT utility (discussed in a separate topic later on in this document.)


Converting Programs to ISAM-A

There is no universal method for converting program written for ISAM 1.0 to use ISAM-A, although in general, the conversion is fairly easy, and almost certainly presents an opportunity to simplify your code. From a logical standpoint, essentially all you have to do is get rid of all your extraneous locking and index maintenance operations that are simply unnecessary with ISAM-A.

As a suggestion, it might be good to proceed by creating a set of template routines (open file, find a record, get next record, etc.) for both ISAM 1.0 and ISAM-A access. Next, create a simple utility to replicate your template routines into file-specific versions (e.g. open CUST file, file CUST record, get next CUST, etc.) Then replace your embedded statements referencing ISAM statement with calls to your generic routines and confirm that the programs continue to work as before. Then you can start converting individual files from ISAM to ISAM-A by just substituting the template routines for ISAM with those for ISAM-A.


ISAM-A vs. Other Indexing Schemes

Although it is impossible to offer many concrete details for comparing ISAM-A to other file indexing schemes, here are some general observations which you may find interesting enough to consider migrating from your custom indexing schemes to ISAM-A.

Performance: ISAM-A indexing uses an efficient B+ tree organization which generally means that you can access any record in 5 disk accesses or less, even in files containing millions of records. In comparison, a index based on binary searching (e.g. SERCH.SBR) would require an average of 11 disk accesses to read a record in a file of only 1024 records. For a file of a million records, the number is more like 21 accesses. Since a random disk seek is by far the slowest operation in data processing (by orders of magnitude), this simple fact alone is likely to make a dramatic difference in your file throughput.

Simplicity: Since ISAM-A takes care of so many details for you (like locking and index maintenance), it is generally much simpler to program with. Not only does this make development easier and faster, it also reduces bugs by eliminating all of the minute details (XCALL parameters, the need for synchronizing manual operations such as locking and index manipulation, etc.) And makes your programs easier to understand and maintain later.

Stable and Robust: ISAM-A is a very mature system with a long track record, both in and outside of the A-Shell community.

Standard Utilities: A single utility, ISMUTL, can handle all of your file administration (creation, rebuild, verification) needs.

Auto Expansion: ISAM-A files automatically expand, eliminating the need for a lot of logic worrying about files filling up and needing to be rebuilt.

ODBC, SQL Access: With ISAM-A files you have the option of accessing them from popular reporting and querying tools, such as Crystal Reports, via third-party ODBC and SQL drivers.


A-Shell ISAM-A vs. AMOS ISAMPLUS

Although A-Shell's ISAM-A is mostly upward compatible (at a programming level) with AMOS ISAMPLUS, there are a couple of considerations that require attention in your code.

File names: ISAMPLUS files contain a single data file and a single index file (which contains all of the individual logical indexes). Under AMOS (ISAMPLUS), the data file extension is IDA, whereas under A-Shell (ISAM-A) it is DAT. This is a minor inconvenience for programs which look for the IDA file, but this can be alleviated for the most part by means of the MAPIDA setting in the MIAME.INI file. In ISAM-A, files also contain a third physical file with an LCK extension which is used for locking (and which can generally be ignored by your application).

Data file layout: Although the IDX files are completely different in format between AMOS and A-Shell, the data file layouts are quite similar, except for one important difference: the A-Shell version has an extra control byte on the end of each record which indicates whether the record is deleted or not. (Binary zero indicates deleted.) Thus, if your declared record size is 512, the actual physical record on disk will be 513. Records are stacked end to end with no consideration for "blocking". Under A-Shell, if you use the compressed data feature, only the fixed header portion of the data record will be stored in the DAT file; the compressed portion of the data record is actually stored in the IDX file.


File Size Limits

Following is a reasonably complete answer to the question "What is the limit on ISAM file sizes?" Note that this discussion applies to both standard ISAM and ISAM-A.

• The 2GB OS file size limit: In order for any file to exceed 2GB, the file system must support it, and you must be running an "LFS" (Large File Support) version of A-Shell. All versions of A-Shell after 4.9.948 (December 2005) contain LFS, except the Windows versions which contain a "c" in the version string. So, other than those limitations, A-Shell does not impose any inherent limit on overall file size.

• ISAM data file size limit: Both ISAM and ISAM-A (aka ISAM-PLUS) use internal 32 bit record pointers. Although it might be possible, with care, to treat them as unsigned, by convention, these are signed and thus this imposes a limit of 2*31 (approximately 2 billion) records. If your record size was 512 bytes, that would impose a theoretical overall data file size of 2GB * 512 = 1TB.

• ISAM index file size limit: Both ISAM and ISAM-A also use internal 32 bit index pointers, although the index block size is different between the twoISAM-A uses 1024 byte index blocks, imposing a theoretical IDX file size limit of 2TB. ISAM 1.0 used 512 byte index blocks, while ISAM 1.1 is configurable (see ISMBLD.LIT /B switch), supporting IDX block sizes from 512 to 16384 (1TB to 32TB theoretical limits).

Note that the index size is dependent on the number of data records, key size(s), and amount of extra space to allow for performance and tree balancing reasons. So in practice this may lower the theoretical limit on the number of data records considerably.

The above numbers are all theoretical limits. In practice, you will likely run into some severe performance issues long before you get to those sizes. Some of the factors to consider here are:

• File system performance on large files. All file systems slow down (quite substantially) when dealing with very large files, because of the need to employ some kind of hierarchical pointer structure in order to locate the physical disk block associated with a particular logical position in the file. The details may vary between file system types, but I have not been able to locate a definitive reference to which file system(s) are the best for such large files.

• Cache efficiency falls dramatically with such large files, because the nature of ISAM leads to random jumps all over the file. Other than the first couple of levels of the index, the rest of the accesses in both the index and data files is likely to uniformly spread, meaning that the cache efficiency will not be much better than the raw ratio of the amount of cache memory available to the size of the files.

• Because of the cache problem, you quickly run up against the raw random access performance of the disk drive. With a typical 7200 RPM drive offering 8 ms average seek time, your total time to read a random record is going to be 8 ms (seek) + 4 ms (latency) = 12 ms, or about 85 reads or writes per second (not counting transfer times, scheduling delays, etc.) So, if you wanted to scan a billion record file in index order, even if the index accesses are totally cached, each data read will probably require a seek, and thus it would take over 3000 hours! Operations requiring random index seeks, such as lookups, adds, and deletes, would be considerably slower still.

Obviously you would want to go with the fastest possible drives (15K RPM and 6 ms average access would cut the overall access time by 1/3) and as much RAM as you can possibly get. Also, splitting the index and data across two drives would help considerably.

But the biggest help would come from restructuring your data to reduce the size of any individual file. Within reason, you'll get much better performance by having more, smaller files.

For example, even though it might not be that elegant, if you had a transaction history file with 120 million records, you would probably get better performance by splitting it into 12 files of 10 million records each (one file per month).


Auto-Expansion

One difference between the A-Shell ISAM-A and the AMOS ISAMPLUS is that ISAM-A files grow automatically as data is added to them. This can create a bit of confusion due to the fact that when the file is first created, regardless of how many records you asked for, the size of the DAT file will be zero, and the number of records allocated according to the stats will be 100 million (which is just a dummy number, intended to assure your application that it didn't need to worry about file expansion). The IDX file will start out with a few blocks to accommodate the index structure and the meta information about the index.

Note that although the files will expand themselves as you add data to them, they will not automatically contract themselves as you delete records. Instead, deleted records are marked with a special control byte, and re-used for subsequent add operations. If you delete a large number of records at one time, you may want to compress the file by dumping it and reloading it.


ISMUTL VERIFY

ISAM-A supports an additional ISMUTL operation called VERIFY. It is equivalent to REBUILD, except it only checks the index without doing any updates on it. This is somewhat faster than REBUILD, and also lets you find out whether there was a problem in the first place. (REBUILD just rebuilds new indexes from scratch, so you have no idea whether the operation was necessary or not.)

Beginning in A-Shell build 1164 of 2 Nov 09, ISMUTIL VERIFY operation outputs information to ashlog.log on errors. (On the screen, it only shows the type of error without any helpful details.)


ISMCHK

ISMCHK is a BASIC utility included with A-Shell which facilitates running unattended checks on your files and generating reported to be examined later or faxed/emailed to you. See the notes in the ISMCHK.BP source code for syntax and configurable options.


CVTISM

CVTISM is a BASIC utility which allows you to convert AMOS format ISAMPLUS files to A-Shell format ISAM-A files without dumping and reloading them. This can save a lot of time, especially if your files are large and your AMOS system is slow. See the notes in the CVTISM.BP source code for syntax and other instructions.


Compressed Indexes

As of A-Shell 4.9.948, compressed indexes are supported. These have no effect on your application code, and only serve to decrease the size of the IDX file on disk if they contain keys which are conducive to one or more of the following compression schemes:

• Compress 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. (For example, an alphabetical name index.)

• Compress 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.

• Compress 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.

To specify that you want a compressed index, you must rebuild the file using ISMUTL.LIT 1.4(129) or higher, which allows for a more detailed response to the "Allow Duplicate Keys" question:

Are duplicate keys allowed for this index? (Y/N{+LTD})

For compression, add L(eading), T(railing), D(duplicates) to Y/N

Ex: YL (dupes allowed, compress leading dup chars)

Ex: NLT (no dupes allowed, compress leading dup chars, trailing spaces)

For example, answering the question "Y/LT" will allow duplicate keys and activate compression of Leading and Trailing spaces. "N/T" will disallow duplicate keys and activate compression of trailing spaces only. "Y" or "N" by itself gives you a traditional non-compressed index. (OK, so it's a bit cryptic; the objective was to avoid breaking existing command files that execute ISMUTL.)

Compressed indexes should only be used with indexes containing string keys, and generally only makes sense with keys longer than about 8 bytes. You pay for the disk savings with some CPU overhead, so you have to use your judgment to decide when the payoff is in your favor. (In general, systems are much more disk bound than CPU bound, so if you can achieve a 25% or more reduction in the IDX size, compression will probably improve performance.)


Compressed/variable length data

As of A-Shell 4.9.948, you have the option compressing the data records, which is essentially equivalent to supporting variable length records. The feature works by dividing the records into two parts: a fixed part (at the start of the record), followed by a variable (compressible) part which makes up the remainder of the record. The fixed part must contain all of the keys, and should probably contain most of the data, except for the parts which are likely to contain sequences of null bytes, spaces, or "0". The variable part gets compressed by collapsing contiguous sequences of those three special characters, and then the result is stored in the IDX file rather than in the DAT file. (The IDX file structure is already conducive to handling variable length chunks of information, and this allows the DAT file to continue to be made up of fixed length records).

As an example of where this might be very useful, consider a customer master record of 512 bytes, to which you want to add some comments. You could use an external storage scheme, such as INMEMO, for the comments, but the simplest scheme might be just to add it to the end of the customer file by increasing the record size from 512 to 8192 (the current maximum record size), and declaring the last 7680 bytes of the record to be compressible.

To specify compressed data records, you must build your file with ISMUTL 1.4(130) or higher. At the record size prompt, instead of specifying a single value as you would for normal fixed length records, you enter the maximum (uncompressed) size, followed by a slash, followed by the length of the fixed length header portion of the record. In the example just described, you would use "8192/512". (As with the cryptic format for specifying compressed indexes, the objective here was again to preserve compatibility with existing command files that execute ISMUTL.)


Transactions and Logging

In this context, the term "transaction" refers to a logical operation involving multiple physical operations on one or more files which should be performed as a single unit (all or nothing). For example, posting a payment to an account may involve updating a receipts file, an open items file, and also changing a balance in the customer master file. You don't want those to get out of sync, so if an error occurs somewhere in the middle of the transaction, you want to back it all out. Transactions support gives you just this capability via the TRANSACTION'BEGIN, TRANSACTION'COMMIT, and TRANSACTION'ROLLBACK statements (described separately above).

Transactions require that all file updates be logged. The log makes is possible for the TRANSACTION'COMMIT and TRANSACTION'ROLLBACK commands to either make permanent or discard the changes since the TRANSACTION'BEGIN. So in order to use transactions, you must first open a log file (with TRANSACTION'LOG'OPEN).

Some additional notes about transactions:

• 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 ISAM-A operation that alters data, whether a transaction is in progress or not. (See discussion of the recovery feature following 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).

• In most cases, you would use a single log file for an entire application, although in some specialized circumstances it might make sense to maintain separate log files for individual users. (The danger there is that actions by other users may affect the context of transactions, compromising the ability to replay them.)


Recovery

As a side benefit to transaction logging, the log file also makes it possible to "replay" (or "recover") all file updates (whether or not part of a "transaction").

As an example of the recovery feature, let's say you do nightly backups, after which you erase the log file. Half way through the day, somebody accidentally erases one of your ISAM-A data files. To recover it, you would restore all of the ISAM-A files from the previous night's backup (taking care not to overwrite today's log file). Then you would replay the transactions from the log using:

.ISRCVR logfile


External Data Access Tools

One of the benefits of using a third-party commercial library for implementing ISAM-A is that there are other third-party add-on tools available. Either of the products below will allow you to access your ISAM-A files from standard query and reporting tools such as Crystal Reports, Excel, Access, etc. If you are interested in this type of tool, please contact MicroSabio to check on latest developments.

ConnX

ConnX Solutions, Inc. (http://www.connx.com) provides an ODBC/OLEDB driver for DISAM, along with an SQL query tool. It does not (yet) support F6, I4, and B5 data formats. If you intend to use this tool, you may want to convert your floating point fields to IEEE single (F4) or double (F8) formats.

EasySoft

EasySoft Limited (http://www.easysoft.com) provides a similar interface, which does support all the standard field types, but is somewhat more expensive than the ConnX tool.


BASIC Error Codes

The error codes in the table below are all decimal values.

Error # | Meaning
201 | Incompatible ISAM file
202 | ISAM library not available (not licensed?)
207 | Index structure smashed
208 | Duplicate key (not allowed)
210 | Invalid number
213 | Invalid record size
214 | Too many concatenated keys
215 | Primary key information missing
216 | Maximum record size exceeded
217 | Invalid key type
218 | Maximum binary key size exceeded
219 | Key range outside record
220 | Overlap keys must be alphanumeric
222 | Too many secondary indexes
223 | No such secondary key number
224 | This secondary key has been deleted
225 | Number of records dumped don't match number in file
226 | Key information missing
228 | Cannot create existing file (file already exists)
229 | Data file smashed
230 | System error
231 | ISAM file must be rebuilt


Performance

Performance issues and optimization under A-Shell are not generally a concern, since A-Shell systems tend to exceed users' performance expectations. (We don't take all the credit for this; it is mostly due to the overwhelming power of the hardware, and in the case of UNIX, to the operating systems' sophisticated I/O logic.) However, there are some cases, particularly those involving Windows networks, where a performance improvement would be highly desirable. And in any case, it is human nature to want anything to go faster. With that goal in mind, the following topics present several performance enhancement suggestions that are relatively easy to implement, as well as some explanations that may lead you to solve performance-related problems.

Subtopics

Peer-to-Peer Issues

QFLOCK.SYS in Memory

Local Copies

Memory Mapping

Read-Only Mode

Accessing Files in the MEM: Device

Pre-load Frequently Used Programs

Temporary Files

Local Print Files (Windows)

Number of Files per Directory

XCALL SERCH Optimization

Optimizing File Sorting

Use Span'Blocks

Use Larger Record Sizes

ISAM Performance


Peer-to-Peer Issues

Here is a real-world discussion from November 2007 concerning network performance issues and related problems.

Situation

One of my clients is experiencing severe network problems. Here are the facts:

· The network is a peer-to-peer running XP-PRO and XP-HOME on eight PC's.

· Their version of Ashell is 4.8(480)

· ashell.log shows error # 183 and "connection to network lost".

· The only network application they run is Tentmaker.

· When we converted from the Alpha to the PC, we left the DSK structure exactly as it was on the Alpha. Hence, they have DSK0 thru DSK20 on their system. Data files are on DSK1-DSK7. The RUN code is on DSK8 thru DSK14. Temp files are on DSK15-DSK20.

This is the only site that I have with problems. The system just "locks up". To restart the system, the sysop has to ZAP the phantom jobs. They can't erase QFLOCK.SYS.

Comments

These are tough problems to solve. I would estimate that over the last 10-15 years, we have seen a dozen of these kind of extreme cases, where network flakiness is making it difficult to use the system. I'm not sure that any single factor was responsible for more than a couple of the problems, but the list of problem causes, in order of popularity, would probably be:

· Virus checking software out of control. (In one extreme example, one of the PCs had been configured to run a virus check on any new media on the network, so that when another PC put a diskette in, the network ground to a halt, even though the user at that PC had no idea.) But any individual PC could be configured to run real-time virus checking across the network to the server, which would cause such a slow down as to possibly lead to "connection to network lost" as a result of timeouts.

· Conflicting software usage. While the business application (A-Shell, Tentmaker) invariably is blamed for the problem (with the common argument being that nothing else is experiencing this problem), often we find that on a network of more than 5 PCs, it is not uncommon for one of them to be involved in some software or file-sharing activity that is not really authorized (like downloading/storing music, games, etc.) or is simply a background hog (Exchange Server), or spyware that is generating extreme CPU and network activity. In the first case, the culprit is not likely to complain, and in the other two, the software doesn't complain, even as it wreaks havoc on the rest of the applications sharing the network.

· Bad hardware components—cables, network cards, switches. These are very hard to diagnose. In some cases, a packet analyzer (or even just using the netstat utility) might be able to give you a clue that there are a lot of network errors, but it's pretty difficult to pin down the source, without the kind of concerted effort that end-users have little patience for. Fortunately, most of the components are cheap and require little or no configuration, so you might, for example, simply try swapping out the main hub/switch. (I've had to do that at least twice on my office LAN, and in both cases the symptoms were similar to what you describe, i.e., general flakiness.)

· OS/configuration conflicts: When you have a mixture of operating system versions, the potential for non-optimum overlapping/conflicting configurations is great. The ideal peer-to-peer network environment would use a Domain server (W200x Server) that everyone logged into from XP-SP2 clients. The least ideal is one with no real server and a mixture of "Home" class clients.

Unfortunately, none of the above information is really helpful to you, in the sense of offering an easy solution. Assuming that it is not practical to have a network technician come in and do a thorough overhaul of the network, if I were in your position, I would consider just switching them to the ATS/ATE model (replacing the peer-to-peer connections with telnet connections). It's not a totally trivial switch, particularly if it's the first time, and it will almost certainly require an update since I don't think ATS/ATE really functioned under 4.8, and there are licensing costs, but I would be willing to help you set up an eval to see if it actually helped.

The ways in which ATS/ATE can help are:

· Allows you to totally eliminate file sharing, at least for the device acting as the server. This can result is very substantial performance gains, since peer-to-peer I/O can be very inefficient when multiple users are sharing a file. (In fact, if you don't disable the file sharing for the shared A-Shell devices, you lose almost all of the performance gain.)

· If the problems are associated more with one client than another, this will be more readily apparent, and also less likely to cause problems for the other clients, since telnet disconnects can be trapped in software and automatically cleaned up, unlike peer-to-peer network problems.

· If the application processes more file data than screen I/O (which is virtually always the case for business applications), the load on the network is greatly reduced, since with telnet, the only data passing over the network is the screen I/O. An extreme but typical example is a report program, that might process 5MB of file data, while it displays a few hundred bytes on the screen.

· ATS allows you to remotely connect to the server, which is good for diagnosis and any other offsite access needs. All this requires is a typical inexpensive broadband Internet connection (DSL, cable) and a typical DSL/cable router (selling everywhere for well under $100).


QFLOCK.SYS in Memory

(UNIX only.) This is mainly only relevant if your application uses XLOCK, FLOCK, or a related locking subroutine, and/or you have a large number of jobs. If either is true, then make sure you use the MEM: (rather than DISK) option on the QUEUE statement in the MIAME.INI. See the system parameter QUEUE and the next topic for more discussion of memory mapping. .)


Local Copies

Networked Windows environments are quite efficient at serving up entire files over the network from a fileserver (as in word processing applications), but they are relatively slow at serving up record-level operations. Here, the disk operation overhead is much higher than in the UNIX world because of the need for machine-to-machine communication. Loading a file from the server may require only a couple of units of machine-to-machine communication, but reading the file via thousands of individual record operations (which is typical of AMOS-style report programs) requires thousands of units of machine-to-machine communications. This overhead typically becomes the limiting factor in Windows installations of A-Shell.

Memory mapping doesn't really help here, since it doesn't eliminate the need for machine-to-machine communication, and in any case, it only works properly for read-only situations anyway. If we can limit ourselves to read-only access to a file in a particular program, then a better solution is to request that A-Shell give you a local copy of the file. In this case, when the file is opened, A-Shell copies the entire file (in one big transfer operation) from the server to the local workstation and then references the local copy until the file is closed (after which the local copy is deleted). This technique can significantly speed up report programs, or any other program that performs many read operations from a file, by eliminating that machine-to-machine communication overhead. As a side effect, it also reduces network traffic and the load on the fileserver, thus potentially speeding up other programs running across the network.

Local copy mode is activated similarly to memory mapped mode, using xcall ASFLAG,64.


Memory Mapping

Memory mapping is a file access technique that works very well under UNIX. Under Windows, it only makes sense in read-only applications, and even there, the "local copy" option (covered in a subsequent topic) makes more sense. So it is for all practical purposes only of interest under UNIX. The concept is to map a disk file onto a memory address space, such that it can be accessed via memory operations rather than disk operations. The file doesn't have to fit entirely in memory, because the demand paging system (otherwise associated with virtual memory) takes care of swapping pages in and out of memory as needed.

It may appear that this is hardly different that ordinary disk caching, in which frequently accessed disk blocks are held in memory to minimize physical disk accesses. However, there is significant performance difference between accessing a cached disk record via a disk service call and accessing a memory record. Disk service calls require a context switch from user to supervisor mode, even if the data is in cache, whereas memory access calls do not. Such context switches are relatively expensive operations, being perhaps hundreds of times slower than ordinary instructions. So even though reading a disk record from cache and reading the equivalent data directory from memory may both appear to be "lightning fast", the difference can become significant when you have a lot of little disk accesses.

If memory mapping is so wonderful, you might ask why we don't just use it all the time. The answer would be that it can cause memory to be used inefficiently, which can have an adverse impact on the system performance. The recommendation would be to only use memory mapping with reasonably small files that are heavily accessed in specific programs. Good candidates would be any custom (non-ISAM) index files, or any small file whose records are accessed multiple times in a particular program. (ISAM files are not generally good candidates except perhaps in certain individual programs and when the files are not too large, because there is no convenient way to map the index without the data.)

The worst candidates examples are large files that are accessed sequentially or sporadically, with little repetitive access to the same records. For example, it would be a bad idea to memory map a customer master file probably in the customer maintenance program. Such a program is not likely to be disk-bound, and the amount of memory spent mapping the file would be better spent on other uses, like ordinary disk caching

Memory mapping must be activated within individual programs, and applies only to files opened after the memory mapping option is turned on, so in addition to identifying heavily accessed files, you would need to identify specific programs that were disk-bound in order to benefit from it.

Memory mapping is activated within a program using xcall ASFLAG,16. Once this call is made, any file subsequently opened within that program (other than for sequential access) will be memory mapped. The implementation therefore consists of inserting an xcall ASFLAG,16 into selected programs just prior to opening the file(s) that you want to memory map. You can either rearrange the file opens to put the one(s) you want to memory map last, or you can insert a subsequent XCALL ASFLAG,0 to clear the memory map flag after the intended files have been opened. No other changes are needed in the program; A-Shell will automatically convert the relevant disk operations to memory operations for you.

It is safe to allow a mixture of simultaneous memory-mapped and traditional I/O to any given file under UNIX.


Read-Only Mode

The benefits of read-only file access apply to all environments. The idea is that if you have no intention of updating a particular file, then there is no reason to pay all of the overhead that is associated with locking the file and coordinating your accesses with other users. The performance difference between reading records in a file opened for read-only access, and reading records from the same file opened for normal (read/write) access is relatively minor in a single-server UNIX environment, but very substantial in networked environments such as NFS or Windows.

In the Windows case, the decision to use read-only mode vs. local copy mode would be based on the size of the file relative to the number of accesses to be made to it. Local copy mode is more efficient (because you cut the network entirely out of the picture) but it does involve the initial overhead of copying the entire file across the network to the workstation. So you aren't going to read most of the records in the file during a particular instance of a program, then it probably is more efficient to leave the file on the server and use read-only mode.

In the case of NFS under UNIX, local copy is not an option, so read-only mode is the recommended approach for optimizing read access to a file.

Your mileage will vary, but it is not uncommon for read-only access over a network to be twenty times faster than reading from a file that has been opened for read/write access by more than one person. (When only one process has the file open, it doesn't seem to have much effect.)

Read-only access can be specified in one of two ways. One is to the "read'only" suffix to the open statement, for example:

Open #1, "MYFILE.DAT", RANDOM'FORCED, RECSIZ, RECNO, READ'ONLY

The READ'ONLY suffix is requires that you use the /V:1 switch or any of the /X switches when compiling the program.

A second approach is to use xcall ASFLAG,1 prior to opening the file. Like the other ASFLAG uses described above, all OPEN statements after the xcall ASFAG,1 are affected. So you either need to rearrange your OPEN statements, or clear the read-only flag using xcall ASFAG,0.


Accessing Files in the MEM: Device

Updated December 2008

In some situations, it makes sense to load an entire file into your user memory partition and access it directly from memory. This can be accomplished using the MEM: device. Use the LOAD command to load the file into your user partition. Once loaded, you can open it and read/write to it just like any other random access file, simply by specifying MEM:<filename> in the OPEN statement.

If you write to the file while it is in your memory partition, you'll need to use SAVE.LIT or the equivalent MX_USRSAV function in order to write the updated file back to disk.

Note that LOAD.LIT dynamically allocates additional memory for any files so loaded, so it is not necessary to worry about the size of your pre-allocated memory partition.

Accessing a file using the MEM: device is naturally much faster than ordinary disk access (even when the file is cached). It is nearly as fast as memory map mode, and much faster than local copy or read-only modes. The biggest advantage that the MEM: approach has over the previous methods is that it can be used without making any program changes. The trick is to add OPTIONS=AUTO_MEMOPEN to the miame.ini file, which causes all BASIC file open operations to automatically check to see if the specified file is in memory before opening the disk copy. If it is already in memory, then it is accessed as if it had been using the MEM: device. This way, you can use MEM: access in specific programs merely by using LOAD.LIT to load the file prior to running the program.

Be careful when using AUTO_MEMOPEN that you don't inadvertently leave the file in memory longer than intended, because subsequent programs will act as if running normally, but any changes to the file will only affect the memory copy.

Update Note: Build 1114 of 27 May 2008

The MEM: device, as well as OPTIONS=AUTO_MEMOPEN, can now be used with sequential input files. For example:

OPEN #1, "MEM:MYFILE.TXT", INPUT

The above statement would work if MYFILE.TXT was loaded into the user memory (using LOAD MYFILE.TXT).

OPEN #1, "DSK1:MYFILE.TXT[123,456], INPUT

As with RANDOM files, if OPTIONS=AUTO_MEMOPEN, then the above OPEN statement will first check user memory to see if MYFILE.TXT is loaded, and if so, will use that copy directly.


Pre-load Frequently Used Programs

This advice mainly applies to Windows file server environments and where your application has a tendency to frequently chain to one or more particular programs. RUN and LIT programs are fetched from disk as needed and flushed after use (with the one exception being RUN.LIT). They are not cached in memory automatically (like SBX routines are) out of concern for the confusion that creates in development environments where you are frequently modifying and re-running programs. It is also very difficult to "guess" an optimum strategy for caching RUN files, since usage patterns vary spectacularly among applications. But it is easy enough to create a CMD file to LOAD your most commonly used RUN and LIT files before starting the application.

Most modern systems are memory rich (or should be, given the low cost of memory), so you can probably afford to be "extravagant" (by traditional AMOS terms). However, there is obviously a point at which it becomes more efficient to allow the system more memory to use dynamically as it sees fit than to lock it up storing individual copies of RUN programs for each user. (There is currently no equivalent of loading a program in system memory, so each user needs to load their own copies.)


Temporary Files

A particularly good use of the MEM: device is for temporary files. Such files are typically only used by a single program anyway, so there is no point in having them on disk, except that we might not previously been able to afford the memory. Now that memory is cheap (and dynamically allocated as needed by the MEMORY and LOAD commands), there is little reason not to put any temporary files that are heavily accessed directly in memory.

Unfortunately, there is currently no way to create a file directly in memory. The ALLOCATE statement does not support the MEM: statement. So you would have to first allocate the file on disk then load it in memory, as in this example:

! Example of creating, loading, using a temp file in memory

! First, allocate the file on disk… (we use the device TMP0:

! which, in the case of Windows, should point to a local

! workstation drive rather than the server

allocate "TMP0:MYTEMP.DAT", BLOCKS

! Next, load it into our user memory

xcall MIAMEX,108, IDX, "TMP0:MYTEMP.DAT"

! Remove it from disk (no longer needed there)

kill "TMP0:MYTEMP.DAT"

! Now open the file in memory…

open #1, "MEM:MYTEMP.DAT", RANDOM, RECSIZ, RECVAR

! Read and write to the file just like any other file

read #1, REC

write #1, REC

<etc>

! Close file and delete it from memory

close #1

xcall MIAMEX, MX_USRDEL, IDX, "MYTEMP.DAT",


Local Print Files (Windows)

If you create large print files on a Windows network, you can improve performance by making sure they are written to the local workstation rather than to the server. As in the example above, the recommended practice is to define a special device (call it TMP0: or PRT0: or LOC0: ) which points to the local workstation (C: drive). This works best in applications that already have a configuration option to specify the logical device were particular classes of files, such as print files, get written.


Number of Files per Directory

This advice applies to all platforms: try to keep the number of files in any one directory down to a reasonable number (ideally no more than a few hundred). If you let the number of files creep up into the thousands, the overhead for performing operations on that directory (such as adding, deleting, or finding a file) grows at an alarming rate. Even worse, it can become impossible to perform UNIX wildcard operations because the shell runs out of memory while attempting to enumerate the wildcard list. A large number of print files can also cause severe fragmentation of the file system, which further slows things down.

This situation tends to occur in applications that create unique printfile names and which leave it to the users to delete print files periodically. Whereas under AMOS, with 32MB logical disks, they might have run out of space after accumulating several hundred print files, under UNIX with a 20 GB logical disk, they may accumulate tens of thousands of print files and still not begin to notice the disk filling up. (They will notice the system slowing down, but will probably not recognize the cause.)

There are several ways to avoid this problem. The simplest would be to just delete (or archive) the print files on a periodic basis. If you want to leave them on the hard drive for archival purposes, then at least move them to another directory which is not accessed constantly by A-Shell. Better yet, tar all of the print files for the period into one tar file (ideally a compressed one). If you ever need to get one, you can list the contents of the tar files and extract individual files as needed.

Another approach would be to use the COMMAND=SBX: feature in the printer init files, along with a custom SBX routine, to archive or relocate the print files as they are printed.

Ideally, you would not only keep your print files and related output files in their own directories (outside of the directories holding the permanent data and program files), but you would even put them on a separate file system (or disk partition). That way, you insulate the more important part of the application from the potential dangers of large numbers of output files, such as filling up the file system, excessive fragmentation, etc.


XCALL SERCH Optimization

The best way to optimize files using SERCH.SBR is to replace them with ISAM-A files. (At best, looking up a record in a file of 32K records would require on average 15 disk operations for SERCH.SBR, and about 3 for ISAM.) If that is not practical, then at consider one or both of the following suggestions:

• Change your file reorganization threshold so that the index is kept sorted (i.e. so that the unsorted "overflow" area is kept small). On a machine where sorting took a relatively long time, you might have been tempted to delay sorting until the overflow area became quite large. But in the typical A-Shell case, it is much more likely that the accumulated delay in having to continually search the overflow area is much greater than the overhead in sorting the file.

• If UNIX, memory map the index file whenever possible. If Windows, use one of the other techniques (read-only, MEM:, local copy) in any program that does not need to update the file.


Optimizing File Sorting

If you do a lot of sorting, or have very large files to sort, or would like more sorting capabilities, we recommend that you switch from BASORT and SORT to the OptTech sort routine, which was developed by third party specializing in sorting. It supports up to 100 sort keys, as well as complex operations like removing or exporting duplicate records, and is much faster than BASORT (particularly with files that do not fit in memory). It has some down sides as well, such as not being interface compatible with BASORT, not supporting files which have block padding, and there is a per-copy licensing fee. Contact us for more details if interested. Otherwise read on for tips on getting the best performance our of SORT and BASORT.

The main trick to optimization of BASORT.SBR and SORT.LIT is to specify SBR=MALLOCSORT in MIAME.INI. This causes A-Shell to dynamically allocate a large chunk of memory to allow the file to be quick-sorted or tag-sorted directly in memory, instead of having to use the much slower, disk-based, polyphase merge sort. We recommend that you always specify SBR=MALLOCSORT. However, there is a limit to how much memory the sort routine will allocate. By default, this limit is 8MB. If you plan to sort larger files, you might want to increase this limit using the MALLOCLIMIT statement in miame.ini.

With modern Windows workstations (which typically have 256MB of memory), there is probably no harm in bumping MALLOCLIMIT up to 64MB. On UNIX boxes, or in Windows Telnet or Terminal Server environments where many users are sharing the same memory, there is definitely a tradeoff between to be considered. If you allow one user to allocate too much memory, system performance may suffer, at least until that memory is fully returned to the system.

In many operating systems environments where multiple users are sharing the same physical memory, even though a user frees up a temporary memory allocation, the system might not make the memory immediately available to others. This is due partly to historical experience suggesting that a process that allocates and then releases a chunk of memory is likely to re-allocate it again before it exits (and thus it is more efficient to "reserve" the freed memory for re-use by the user that freed it.) The other reason is there may be significant overhead in the "garbage cleanup" necessary to consolidate the freed memory with other available segments. The one guaranteed way to force the system to re-use freed memory is for the process to exit. (That is, if you have a single program that needs to sort a huge file, let's say 256MB, then you could launch an A-Shell session using MALLOCLIMIT=260MB, sort the file, then exit that A-Shell session so that the memory will be immediately made available to the rest of the system.)

Also note as an alternative to changing the MALLOCLIMIT, you can simply change your current memory partition size, dynamically, with the MEMORY.LIT command. (BASORT.SBR will use your partition if there is sufficient memory available there for a quick sort or tag sort.) So in the case just described, it would be easier to just use a command file to set the partition size for the process, rather than using a special version of the miame.ini. The one potential downside of that approach is that if the requested amount of memory is not available, MEMORY.LIT will simply fail, whereas in the case of MALLOCLIMIT, BASORT will try for a smaller allocation if the original request fails.

As of Build 833, BASORT contains some minor optimizations to the tag sort routine that come into play when the file being sorted is opened with the span'blocks modifier or when the record size divides evenly into 512 (or is larger than 512, in which case span'blocks is automatic). So when laying out a file to be sorted, it makes sense to use record sizes like 16, 32,64,128,256, etc., or to use span'blocks.


Use Span'Blocks

Historically under AMOS, all disk I/O was organized around 512 byte blocks. Because of this, logical records in a file were not split across block boundaries. Instead, filler bytes were simply added to the end of each block as needed. For example, if the record size were 170 bytes, three records would fit within a block (3 x 170 = 510) with two bytes left over. In this case, each block would have two wasted bytes at the end. Eventually, under AMOS 2.x, this requirement was lifted, but you had to specify the span'blocks modifier on the file open statement to force it to allow logical records to be split across blocks. For example:

Open #1, "myfile.dat", random'forced, 170, recno, span'blocks

This method is certainly more efficient in terms of disk space, but possibly less efficient in terms of performance, so it never became very popular. However, under UNIX and Windows, it is virtually always more efficient in all cases. In addition to eliminating wasted space, it also lends itself to optimization involving the reading and writing of arrays of records at a time. (The BASORT routine, for example, uses this technique with its temporary files.) Thus, thus the use of span'blocks is highly recommended under A-Shell.

Span'blocks is automatic whenever the record size is greater than 512 and irrelevant if the record size divides evenly into 512. It is also automatic for ISAM-A files. However, note that for any given file, if you use span'blocks in one program, you need to use it in all the programs that access that file, since it does affect the way the data is organized on disk.


Use Larger Record Sizes

This may sound like strange advice, especially for those of us that grew up squeezing our record sizes down to the absolute minimum possible. Surely, all else being equal a larger record is no more efficient than a smaller one, but it may not be any less efficient either. As was hopefully made clear in the discussion about memory mapping and local copies, the biggest bottleneck in disk I/O is not the transferring of the bytes or the network bandwidth but the various forms of overhead related to initiating the operation. Those forms of overhead are not related to the number of bytes transferred in an operation. In other words, the time required to read a 768-byte record is, for practical purposes, about the same as the time require to read a 16 byte record.

Consequently, it doesn't make sense to try to squeeze bytes out of your records, especially if it requires you to go to extra trouble to pack data into compact formats. For example, whereas it might once have made sense to store dates in a compressed 2 byte format, packing and unpacking them as needed, it probably makes more sense now to store them as 8 bytes, or even 10 (with slashes).

The only reason to minimize record sizes is if, in doing so, you make the file easier to back up (i.e. it fits on a convenient medium) or you make it more practical to load into memory. But an increase of 25% in the size of the file is unlikely be significant in either case.

Similarly, don't worry about 512 byte blocking or the 512 byte record limit. If you need to expand a record, just expand it to whatever size is convenient. A-Shell supports the span'blocks option on the OPEN statement (see previous topic), and invokes it automatically for record sizes larger than 512 bytes. You're much better off with a single record of 900 or 1600 bytes, than with two or three smaller records. (There might be a slight advantage to record sizes that are even divisors or multiples of 1024, but this is a minor factor.)

As an example of where this logic might apply, let's say you are creating a file to store invoice history for each customer. Standard design principles would suggest creating a file with one record per invoice. That way, if a customer had 500 invoices, it would use 500 records, but if he had only one, then only 1 record would be needed. Let's say that the record size is 64 bytes. An alternative approach suggested by the "use larger record sizes" strategy would be to store the invoice history records in "super-records", each holding several invoices. For example, we might go with a 1024 byte record that held up to 16 invoice items. It might take a bit more logic to access the file this way, and we would waste, on average, half a record (512 bytes) for each customer. On the other hand, we cut the number of file operations needed to fetch the invoice history for a customer by a factor of 16, making this design much faster, even allowing for the fact that we would be, on average, transferring twice as many bytes (due to the half-empty records).

You would have to decide for yourself if the performance advantage was worth the negative baggage (waste of space, extra logic required, etc.) Quite likely it is not. The point of this exercise was not to suggest a goofy database design, rather to make clear that the main disk bottleneck is in the number of records accessed, not in their sizes. If performance is important to you, then try to get more accomplished with fewer individual disk I/O operations.

One more example of this principle is worth noting. Many applications have one or more utility programs, such as file rebuilds or reports, that read every record sequentially in a file. Although such programs will probably benefit from one of the methods described previously (e.g. memory mapping, local copy, read-only mode, etc.), yet another approach would simply be to read more than one record at a time. Let's assume again that we plan to read a sequential series of 64 byte records. Instead of reading them one at a time, we might do something like the following:

map1 XREC

map2 REC(16) ! array of 16 file records

map3 KEY,S,10

map3 DESCR,S,50

map3 CODE,B,4

OPEN #1, "MYFILE.DAT", RANDOM'FORCED, 1024, RECNO

LOOP:

RECNO = RECNO + 1

IF RECNO > MAXREC GOTO DONE

READ #1, XREC

! now process the 16 records individually….

FOR I = 1 TO 16

<process REC(I)…>

NEXT I

GOTO LOOP

The above technique needs some refinement. For example, it ought to deal with the case where the file doesn't contain an even multiple of 16 records. And it needs to be careful about whether reading multiple records at a time interferes with the 512 byte blocking logic. (This is another good reason why you should always use span'blocks mode, because it eliminates these pesky 512 byte blocking concerns.) The point, again, is that although this technique does not reduce the amount of data transferred, it reduces the overhead by reducing the number of individual disk operations, and thus will run faster and create less load on the server.


ISAM Performance

Updated February 2012

Although ISAM-A is the preferred file structure for use in A-Shell, and has been for many years, ISAM 1.0 continues to be fully supported.

In August 2008, A-Shell build 1122, a major performance-related update of ISAM was undertaken to meet the needs of a new client. This "new ISAM" is known as ISAM 1.1.

For large ISAM files, you can achieve much better performance by increasing the IDX block size and/or number of index levels from the previous fixed values of 512 and 3. The ISMBLD and ISMDMP utilities, updated to ISAM 1.1, allow access to the new capability.

To take advantage of the new capabilities, you must dump the file and build a new one with the ISMBLD switches /B:# and /L:#.

Following are descriptions of how the ISMBLD.LIT switches may be used to improve performance. See the following topic for information on the very important /L:# switch, and ISMBLD.LIT for a full listing of the switches.

See also ISMBLD.SBX, ISMDMP.LIT, and ISMROK.SBR.

IDX BLOCKS (/B:####)

Increasing the IDX block size helps by increasing the number of keys that can be scanned per disk operation, reducing the number of levels needed, and reducing the number of block splits during adding, all at the cost of more bytes being transferred to/from the disk per node accessed. For most modern disks and computers, the tradeoff works well, at least up to 2048. Our recommendation is to choose a block size 20-50 times larger than the key size.

MEMORY MAPPING (/MI and /MR)

Under UNIX, memory mapping the IDX, either fully (/MI) or just the first few blocks at the top of the tree (/MR), affects only the ISMBLD loading operation. In general memory mapping results in a very significant performance increase, when the total file size is small compared to the available system memory (else it may adversely affect the cache efficiency). /MR only maps a handful of blocks, so there is no danger of it affecting cache efficiency, but on the other hand, the overall benefit is smaller. If you want to get this same effect in your application, you'll need to use XCALL ASFLAG.

Memory mapping does not have much, if any, benefit under Windows.

FAST LOAD (/F)

Like /MI and /MR, this also only affects the load operation. It speeds the process somewhat, by eliminating the initial key lookup operation that otherwise is performed to check whether the record being loaded is a duplicate. If you know that your load file is clean, this can shave about 20% off the load time. But the penalty is that if there is a duplicate key, instead of skipping the record (as in the normal case), the load will abort with an error.

AUTO-EXPANSION

Beginning with A-Shell 1344 of March 2013, the number of blocks added during auto-expansion is now limited to 8 MB of data or 2000 index blocks. For very large files, this makes the auto-expansion process more seamless.

Real-World Analysis

An A-Shell user asked a question about ISAM performance, and MicroSabio provided an in-depth answer that covers a lot of ground. See the discussion here on the A-Shell forum.

Subtopics

IDX LEVELS (/L:#)


IDX LEVELS (/L:#)

Increasing the IDX levels helps balance the tree, avoiding the top-heavy situation where we have to sequentially scan many blocks at the top (root) of the tree in order to find the right branch. The optimum number of levels is that which results in only one block at the root of the tree, and is related to the number and size of keys, and inversely related to the size of the IDX blocks. ISMBLD (and ISMDMP) will work out the math for you and display a list of the projected IDX blocks at each level, e.g.:

.ISMBLD TSTNEW

Key size: 50

Key position: 1

Size of data record: 64

Number of records to allocate: 500000

62415 index blocks will be allocated

Empty index blocks to allocate: 62415

Projected IDX blocks by level: 4000,20000,100000

Warning: IDX is top heavy; consider adding levels or increasing block size.

The above example shows building a file with 500000 records each with a 50 byte key. Using the default values (512 byte IDX block and 3 levels) the estimated number of blocks at the top level is 4000 which is extremely top-heavy. (The top level must be scanned sequentially until we find our branch, sort of like turning the pages of the dictionary one by one to find the right page.) So in this case, each key lookup will take an average of 4000/2 or 2000 disk operations just for the top level, then typically one each for the remaining levels.

(The numbers work out nicely in this example because assuming an average loading efficiency of 60%, that gives us 5 keys per 512 byte index block, hence the ratio of 5X between each level of the IDX.)

Since 2000+ disk operations per key lookup is going to result in TERRIBLE performance, let's hit Control-C here (before the IDX is built) and try to optimize it.

To optimize this IDX, we can either increase the block size, the number of levels, or ideally both. Using our heuristic for the ideal block size of 20-50 times the key size, we could either go with 1024 or 2048; let's try 1024 and 6 levels:

.ISMBLD TSTNEW/B:1024/L:6

Key size: 50

Key position: 1

Size of data record: 64

Number of records to allocate: 500000

29415 index blocks will be allocated

Empty index blocks to allocate: 29415

Projected IDX blocks by level: 1,5,50,500,5000,50000

As you can see, now we have a projected IDX tree with only 1 block at the top or root, 5 below that, and then a 10X factor between each of the rest. This is vastly better than the original default configuration, reducing the average number of disk operations per key lookup from over 2000 to about 7.

If you have the time to experiment, you might want to try a block size of 2048 (/B:2048) and 5 levels, which produces an IDX level breakdown something like: 1,3,47,1034,22728. It is hard to predict whether the decrease of one level combined with the increase in block size will be a net gain or loss; it will probably depend on your hardware, but probably won't make a major difference.

Projected vs. Actual IDX structure

The projected number of IDX blocks by level resulting from a particular combination of records, key size, block size and levels is just an estimate based on an average distribution of keys and the number of records specified. In a production environment, you might build the file with a small initial number of records and then rely on the auto-expand feature to increase the file size as needed. Unfortunately, unlike the case with ISAM-A, the auto-expand does not adjust the IDX structure, it only adds blocks to it. Thus what might be an ideal configuration for an initial file size of, say, 10,000 records, might turn out to be badly top-heavy if the file grows to 500,000 records. Thus, you may want to experiment using ISMBLD to specify the number of expected records (i.e. the file size you'd like to optimize the IDX for), in order to figure out the best number of levels. (Just ^C before creating the actual file.) Then you can use the appropriate /B:### and /L:# values, and don't worry if the initial index appears to have more than the optimum number of levels (e.g. 1,1,3,30,3000). Keep in mind that the performance penalty for too many index levels is just one disk operation per level, while the penalty for too few levels is essentially unlimited.


Socket Programming

Sockets (sometimes called "Berkeley sockets" because they were first introduced in Berkeley Unix) are almost certainly the most common mechanism for communicating between two computers across a network (especially the Internet). Some examples of common networking protocols that are built on sockets are: Telnet, FTP, HTTP, and SMTP. In terms of the TCP/IP protocol stack, sockets exist at the interface between the transport layer and the application layer, and are generally based on either of the two common transport protocols–TCP or UDP–approximately as illustrated here.

Application Layer | Telnet FTP A-Shell
 | <sockets>
Transport Layer | UDP | TCP
Network Layer | Network Layer (IPv4 or IPv6)
Datalink (MAC) Layer | Ethernet, Device Drivers
Physical Layer | Hardware (e.g. 10BaseT)
 | TCP/IP Protocol Stack

TCP (Transport Control Protocol) provides a reliable, stream-oriented "connection" analogous to a telephone call, while UDP (User Datagram Protocol) is a simpler, unreliable, datagram-oriented, "connectionless" protocol more analogous to a letter sent through the mail. (It is also possible for sockets to bypass the transport layer; these are called "raw" sockets.)

When two computers communicate via sockets, one is considered the "server", and the other is the "client". The distinction relates solely to how the connection is established. The server "listens" (i.e. waits) for a client to "connect". In the case of TCP, once the connection is made, both sides can read and write (even at the same time, since the connection is "full duplex"), and either can initiate the close.

In the context of socket programming, "clients" and "servers" are designations given to processes, not computers. (The two processes may exist on the same computer or on different computers thousands of miles apart.) This use of the terms should not be confused with the common notion of the "server" being a central computer and the "client" being a user device like a workstation.

A socket is identified by the combination of an IP address and a 16-bit "port" number. Generally ports 1-1024 are reserved for "well-known" services (e.g. Telnet=23, SMTP=25, FTP=20,21, HTTP=80, etc.) while ports 1025-65535 are available for custom application use. A socket "connection" between two processes (typically but not necessarily on different machines) is defined by the two endpoints. Several connections can share the same endpoint at one end (for example, several Telnet sessions on the same server and all at port 23) but they would have to have unique endpoints at the other end, as shown here:

Subtopics

Listening vs. Connection Sockets

Socket Subroutines

Scenarios and Issues

Sample Programs

Interfacing to External Services


Listening vs. Connection Sockets

When a client makes a socket connection, there is only one socket involved: the "connection socket". But on the server side, there are actually two sockets: a "listening socket" and a "connection socket". The server starts by creating a "listening socket" and "binding" it to a protocol, address and port number. Then it "listens" on this socket for a client connection. The act of accepting the connection creates a new "connection socket" used for the duration of the connection. The listening socket then may or may not be closed, depending on the design of the server.

The A-Shell TCP subroutines encapsulate these details, making it appear as if there was only one socket. But in reality, it internally creates a listening socket, and then closes it after accepting a connection and returning the connection socket to the caller. Because it closes the listening socket, the port becomes available again for another process (or the same process) to again listen on the original port.

A single program could actually support multiple socket connections, all on the same port. This is not of much practical significance, though, since the subroutine blocks while waiting to accept a connection (and thus would be unable to service the existing connections during that time.) To service multiple concurrent connections effectively, you generally need multiple server processes.


Socket Subroutines

A-Shell includes three general-purpose socket routines, TCPCLI, TCPSRV, and TCPX. TCPCLI and TCPSRV were the original routines, designed specifically for the client and server ends of a connection, respectively. TCPX is the new version (as of Build 855), combining and extending the features, and is preferred for new programming. With these, you can create or interface to most kinds of TCP based socket services. Since the subroutines are already documented, we will instead go on to discuss higher level considerations.


Scenarios and Issues

This section discusses various issues relating to socket programming, and includes some samples of common scenarios.

Subtopics

Simple, Blocking, Iterative Server

Non-Blocking, Checking Without Waiting

Packet Fragmentation and Consolidation

Serving Multiple Concurrent Connections


Simple, Blocking, Iterative Server

This scenario reflects one of the most common types of socket conversations, that of a server which fulfills a single request per client connection. An example might be an inventory lookup and pricing server. The client prepares a request (e.g. perhaps a list of part numbers and quantities.) It then connects to the server (which spends its time in waiting for such connections, except when it is actually busy servicing one.) If the connection fails, the client might wait and retry. Upon connection, the client passes the list of parts and quantities to the server, the server looks them up in the inventory and pricing databases, and then returns the list updated with the available quantities and current prices. The client then terminates the conversation and the server goes back to waiting for another client connection.

There is nothing in this model requiring that the conversation be terminated after one request/reply cycle.

A flow diagram representing this kind of conversation and indicating the actual TCPCLI.SBR and TCPSRV.SBR opcodes is given below. (TCPX supports the same opcodes, so the references to TCPCLI and TCPSRV in the diagram apply equally to TCPX).


Non-Blocking, Checking Without Waiting

One possible shortcoming with the implementation just described is that both client and server are "hung" during the read operation (waiting for the other end to send something.) If the remote end malfunctions, the local side would become more or less incapacitated. (You could ^C out of the wait state, but that is of little benefit to an unattended process.) The danger of this happening is minimal in the simple server just described, but in some cases, it could perhaps be more of a concern. In that case, you may want to employ one of the following techniques.

The first is simply to check for input (using Opcode 7) before invoking the read operation. Since you can set a timer on the check operation, you can be certain of not getting stuck. The main problem with Opcode 7 is that it can only tell you if there is data to read, not how much. Consequently, in order to achieve maximum robustness, you would need to program for the possibility of receiving a fragmented packet. (See the following discussion on packet fragmentation.) A better solution to that problem is Opcode 8, which will tell you how many characters are available. Perhaps better still would be to use the TIMER parameter to set the maximum time to a very short interval, and the FLAGS parameter to the number of characters you want to wait for. (This is a new capability added to TCPX that was not supported by the earlier routines.)

An alternate approach is to open the socket with FLAGS=0 (i.e. to clear the blocking flag.) In that case, an attempt to read (or write) to a socket that is unable to supply (or receive) any data will return an error code rather than hanging the process. Under Windows the normal error code is -10035 (Operation Would Block.) Under UNIX, it is typically –11 (Resource Unavailable.) When such an error occurred on a read or write call, the application would want to loop and retry after a short wait.

Even in the non-blocking case, an active close at the remote end will be indicated by a return STATUS of 0 to a read call. An attempt to write to a socket that has been closed by the remote end may accept a few characters but will eventually return an error such as –32 (Broken Pipe).


Packet Fragmentation and Consolidation

The TCP transport protocol guarantees that all bytes sent are delivered in the order sent. However, packets may be fragmented and/or consolidated at any point along the process. For example, if you send out several packets of 100 bytes in rapid succession, they may be consolidated and delivered as a single packet of several hundred bytes. Or conversely, a large packet of 4000 bytes may be broken up and delivered as two or more smaller packets. In fact, the very idea of a "packet" doesn’t really exist in TCP, which is a byte-stream protocol. "Packets" are used at the network and datalink layers to implement the TCP byte-stream, but are essentially invisible to us as the TCP level.

This is an important consideration when using TCPX (or TCPCLI / TCPSRV), since the fact that they can send or receive a logical packet of data at a time, may falsely give the impression of these logical packets being the same as physical packets, i.e. more like "messages" or "data records", when they are not. They are just groups of bytes, which may well be regrouped (but never reordered) during the transport process. It is up to the application to design a protocol that works with this paradigm. There are several possible approaches to doing this.

One is to build your own two-level protocol on top of TCPX (TCPCLI / TCPSRV), with the lower level simply being responsible for accumulating (or transmitting) bytes, and the upper level mapping the buffered bytes into logical "packets" or "records". This is a bit awkward to do in BASIC, although it is certainly possible using unformatted variables with substring addressing, or arrays, along with the ability to map overlay structures in BASIC.

Another is to make extensive use of Opcode 8 to always check that the number of bytes in your "packet" is available before reading, and to always specify the "packet" size in the FLAGS argument when reading, so that you don’t accidentally read more than one "packet" at a time. This, of course, works in conjunction with a protocol involving fixed length logical "packets".

As discussed in the preceding topic, TCPX added the ability to combine a time-out with a blocking read operation. This simplifies the task of reading complete packets, but doesn’t completely eliminate the possibility that fragmentation and network delays will result in the timer expiring after receiving only a part of the desired logical packet. (This, however, would be pretty rare, and gets rarer still as the time out value is increased and the packet size is decreased. In fact, with packets less than about 1000 bytes, the chance of them being fragmented is practically nil, and even if there is fragmentation, the chance of there being a significant delay in arrival of the packets is another order of magnitude smaller. So it wouldn’t be unreasonable to forego the effort of reassembling physical packets into logical ones and instead just treat such a condition as a general protocol error, and reset the connection.)

A third approach, which might be combined with either of the others, is to include mandatory "ACK/NAK" messages in your protocol. These allow you to synchronize the two processes, as well as providing a way to abort the connection at convenient points where errors might be anticipated. For example, consider a simple file transfer protocol. The client sends a (fixed length) "request packet" to the server asking to retrieve a certain file, and the server responds first with a "header packet" giving details about the file (most importantly its size) and then sends a series of "data packets" containing the file. If the sender immediately followed the "header packet" with "data packets", they might arrive merged, requiring the receiver to separate them. But if the sender waits for the client to "ACK" the "header packet" before proceeding, the client can avoid excess manipulation of the incoming data, and if necessary, it can abort the transmission right here before it starts by sending a "NAK". The following code excerpt illustrates such a client:

! Simple file transfer client

map1 CONTROL'PACKET ! arbitrary packet layout (must match server!)

map1 CTL'OPCODE,B,1 ! 0=end, 1=request file, 2=ACK, 3=NAK

map1 CTL'SIZE,B,4 ! # bytes in file (0=NA)

map1 CTL'DATA,S,251 ! requested file name

map1 CTL'PAK'SIZ,F,6,256

map1 DATA'PACKET,X,1024

FLAGS = 0 ! (blocking connection)

call CONNECT ! connect to server

if STATUS <= 0 goto ERROR

CTL'OPCODE = 1

CTL'DATA = "MYDATA:SAMPLE.DAT"

FLAGS = CTL'PAK'SIZ ! send fixed length request packet

call SEND'CONTROL'PACKET

if STATUS < CTL'PAK'SIZ goto ERROR

call READ'CONTROL'PACKET ! wait for response

if STATUS < 1 goto ERROR ! premature close (0) or other error (<0)

if STATUS < CTL'PAK'SIZ then ! (partial packet received – loop and get more)

< get rest of control packet >

endif

open #CH, CTL'DATA, OUTPUT ! open file ch to write received file

! (if error during open, our error trap

! should send a NAK to server, possibly

! with a reason in CTL'DATA)

CTL'OPCODE = 2 : FLAGS = CTL'PAK'SIZ

call SEND'CONTROL'PACKET ! send ACK to server

if STATUS < CTL'PAK'SIZ goto ERROR

RCV'LOOP:

FLAGS = 0 ! receive up to size of DATA'PACKET

call READ'DATA'PACKET

if STATUS <= 0 goto ERROR ! premature close (0) or error (<0)

PRINT #CH, DATA'PACKET[1,STATUS]; ! write received bytes to file

TOT'RCVD = TOT'RCVD + STATUS

if (TOT'RCVD < CTL'SIZE) goto RCV'LOOP

close #CH

call CLOSE'CONNECTION


Serving Multiple Concurrent Connections

A single server process can practically only serve one client process at a time. If another client tries to connect while the server is busy servicing another request, that client will receive an error during the connection attempt, such as "connection refused". If the duration of your typical server session is very short, and there are not too many clients competing to access it, then the easiest way to handle the possibility of a busy server is by having the clients retry their connection attempt after a short wait. However, if the average connection time is long, or the number of competing clients is sufficiently large, this will not give very good results, and a more powerful mechanism of supporting multiple clients is needed.

The "normal" way to implement concurrent connection servers in the UNIX world is by forking a new child process to handle each new connection. The typical Telnet daemon is an example of this. It listens on port 23 for a client connection, and as soon as it accepts one, it forks a child, which inherits (and takes over) the connection, while the original server closes its copy of the connection and goes back to listening for the next client connection.

The TCP subroutines do not internally provide such a forking mechanism. There are, however, workarounds to this obstacle (including using SUBMIT to fork your own child-server).

One such workaround would be to launch multiple servers, each listening on a different port. The clients would then need to be capable of iteratively trying to connect at each of the specified port numbers until a successful connection was established. A variation of this technique would be for the server, upon accepting a connection, to launch a child instance of A-Shell, passing it a command line which launched a new copy of the server at a new port number. At the same time, it would return to the client this port number so that the client could disconnect and then reconnect at the new port number.

Multiple independent processes cannot all be listening on the same port, which is why the scheme just described requires separate port numbers. (Technically, there is a way around that restriction, but it involves opening a listening socket in one process, and then spawning multiple children that inherit and share the listening socket. This is beyond our scope at this point.)

A more sophisticated workaround is for the server, after accepting a connection, to "hand it off" to a child process to be serviced, thus freeing the server to immediately accept another connection. You can do this using SUBMIT.SBR or AMOS.SBR. You would need to pass to the child process (via command line arguments) the name of the program to service the connection and most importantly the socket number.

Sockets are inherited by child processes launched via SUBMIT, but the child process needs to be told the socket number so it can pass it to TCPSRV.SBR.

Such a server program would contain code something like this:

LOOP:

SOCKPORT = MY'PORT ! specified listening port

call ACCEPT'CONNECTION ! wait for connection

! (return STATUS, SOCKPORT)

if STATUS <= 0 goto ERROR

! Now pass socket to child…

xcall AMOS,"SUBMIT CHILD "+str(SOCKPORT) ! launch CHILD.CTL

! (inherits our socket)

call CLOSE'CONNECTION ! close our copy of socket

goto LOOP ! wait for another client

The CHILD.CTL file might look something like this:

;CHILD.CTL
RUN CHILD $0

A-Shell supports DO-file style arguments passed to CTL files via SUBMIT.

The CHILD.BAS program might look something like this:

SOCKPORT = str(CMDLIN) ! (BASICPlus) pick up socket # from cmd line

call READ'SOCKET ! wait for client to send us something

<process request>

call WRITE'SOCKET ! send client response

call CLOSE'CONNECTION ! (or, we could loop back for more

! read/write cycles)

END ! Terminate program and A-Shell session


Sample Programs

A-Shell comes with a number of sample programs that can help you experiment with (or develop) client/server socket programs. The most general is TCPTST.BAS, which interactively prompts you for each operation, and supports both client and server modes. EMAILX.BAS (included with the EMAILX developer’s toolkit) contains a fully functioning example of a client program communicating with an SMTP server. And the pair of RXCALL.BAS and RPCUTL.BAS contain a fully functioning example of both ends of a client/server connection using a custom protocolm, designed to send XCALL parameter information between machines to implement remote subroutines.


Interfacing to External Services

Although the TCP subroutines are quite useful for communicating between A-Shell processes, they are probably even more useful for communicating with the "outside world". As noted previously, most of the important services on the Internet are based on well-documented socket protocols. This means that you can use TCPX or TCPCLI to write client programs which can talk to Internet servers, and you can use TCPX or TCPSRV to write server programs that standard clients can use to talk to you.

As a trivial but instructive example of talking to an Internet server, you can fetch raw web pages from any Internet web server using code similar to the following:

map1 BUFFER,S,1024

map1 HOSTNAME,S,80

map1 SOCKPORT,F

map1 TIMER,F,6,5000 ! 5 second timeout

map1 FLAGS,F,6

HOSTNAME = "www.microsabio.com" ! web site or IP addr (without http://)

SOCKPORT = 80 ! standard http port

FLAGS = 1 ! blocking mode

xcall TCPX,9,STATUS,BUFFER,SOCKPORT,FLAGS,TIMER,HOSTNAME ! connect to site

if STATUS < 0 goto ERROR

BUFFER = "GET /index.html" + chr(13) + chr(10) ! (must have CFLF!)

FLAGS = len(BUFFER) ! # bytes to send

xcall TCPX,2,STATUS,BUFFER,SOCKPORT,FLAGS,TIMER ! send GET command

if STATUS <= 0 goto ERROR

LOOP: ! retrieve the home page, one buffer at a time

FLAGS = 0 ! retrieve one packet at a time (up to BUFFER size)

xcall TCPX,4,STATUS,BUFFER,SOCKPORT, FLAGS,TIMER

! depending on how remote side closes socket, we may get STATUS 0 or -10054...

if STATUS = 0 or STATUS = -10054 goto DONE ! remote side closed

if STATUS < 0 goto ERROR

<process page text in BUFFER>

goto LOOP

DONE:

xcall TCPX,6,STATUS,BUFFER,SOCKPORT ! close

END

The GET command syntax above is an HTTP 1.0 "Simple Request", which is a generally deprecated form, although nearly all web servers will support it. Refer to the RFCs for HTTP (such as RFC 2616) for full specifications on the HTTP protocol. The point of the example is just to demonstrate how simple (and text-oriented) many of these Internet socket-based protocols can be.

A slightly more complicated example can be seen by looking at the detailed log file created by the EMAILX.SBX routine, which will show the exchange between a mail client and an SMTP server. As with the HTTP protocol, SMTP is based on simple CRLF-terminated text commands.

If you need design a protocol for a server that will be accessed by "foreign" (non-A-Shell) clients, you may want to follow the model of protocols such as HTTP and SMTP and base them on CRLF-terminated text lines. Although human-readable text-based protocols may seem slightly less "efficient", this is really not much of a concern because of the substantial packet overhead suffered by small packets. For example, the smallest possible Ethernet IPv4 packet is 68 bytes, so there is little point in trying to compress your command lengths down to a few bytes, unless you can pack many of them together in a single packet. On the other hand, there are several significant advantages to text-oriented protocols, including:

• They are easier to document.

• They are easier to debug. (A simple text log of all data sent and received tells all.)

• You can test the server side using Telnet as a client.


Print Tab() Functions

As part of the PRINT statement, Tab() functions provide a compact interface to a wide variety of capabilities, ranging from basic green screen terminal functions originating under AMOS to exotic GUI workstation commands implemented only under A-Shell. The table below provides both an overview and detailed links to the specific references for the major categories of Tab() functions.

Tab | Description
(x) | One dimensional typewriter-style Tab to column x.
(x,y) | Two dimensional cursor positioning Tab to row x, column y.
(-1,x) | Tab(-1,x) Functions shown in the Appendix.
(-2,x) | Set Foreground Color.
(-3,x) | Set the background color. See notes on Set Foreground Color.
(-5,x) | Set Number of Rows.
(-6,x) | Set Number of Columns.
(-10,x) | A-Shell GUI functions. See TAB(-10,x) Function Listing.
(x,y,z) | The Three-D Print Tab combines Tab(x,y) cursor positioning with a user-defined set of attributes (z).

Subtopics

Set Foreground Color

Set Number of Rows

Set Number of Columns

Three-D Print Tab


Set Foreground Color

Tab(-2,x) is not an extension and is implemented very much as under AMOS, although most AMOS applications were monochrome and thus you may not be familiar with this command. Set the foreground color to x, where x normally ranges from zero to seven (0=black, 1=white, 2=blue, 3=magenta, 4=red, 5=yellow, 6=green, 7=cyan). You can also specify color values from 8 to 15 but these are equivalent to the "dim" versions of colors 0-7. (It is actually possible to define these all independently, either in A-Shell/Windows or in most color terminal emulators, so that "dim" may be a misnomer. But from a programming standpoint, Tab(-2,x);Tab(-1,11) is equivalent to Tab(-2,x+8). Color values beyond 15 are mapped to the modulo-8 equivalent. Note that color is a "mode" attribute, meaning that it takes up no space on the screen and it stays in effect chronologically (rather than spatially) until overridden by another color.


Set Number of Rows

Tab(-5,x) sets the number of display rows to x. This was only available under AMOS with the AM65 and AM75 terminals, and x was essentially limited to 24 or 42. Under A-Shell, it is still limited to the display device, but in the case of A-Shell/Windows, the display device supports from 1 to 50 rows. In the case of the ZTERM terminal emulator, as of build 144 it also supports from 1 to 50 rows provided you use the "z" version of the terminal driver. See Selecting a Terminal Emulation.


Set Number of Columns

Tab(-6,x) sets the number of display columns to x. This is purely an A-Shell extension and only applies to A-Shell/Windows, which supports from 1 to 160 columns. Dumb terminals and emulators are typically limited to 80 and perhaps 132 columns, which the Tab(-1,80) and Tab(-1,81) commands are designed to switch between.


Three-D Print Tab

As of build 947 of 3 December 2005, A-Shell supports a "three dimensional" form of the BASIC Print Tab command:

? 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 nature of the text being displayed. Having done that, you can then define a set of display attributes for each of the types, through a series of calls to MX_DEFTABXYZ.

The 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$. See MX_DEFTABXYZ for more information. Use multiple calls to the function, one per text type or Z value.

Comments

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 MX_DEFTABXYZ calls.

It has been 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.

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 types 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

...

At runtime, you would issue five MX_DEFTABXYZ calls to define attributes for the five types of text (assuming you wanted to alter the appearance of that type of text from its original style)

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 AG_CONTROL 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.


SBX Subroutines

One of the most powerful features of AlphaBASIC is the ability to call external subroutines using the XCALL statement. Not only are such subroutines useful for modularizing application development, they also encourage code reuse, and perhaps most importantly, they encourage the development of high-quality utility routines that can be shared by a wide cross-section of developers.

Under A-Shell, subroutines are supported, but up until Build 779, they had to be written in C and then linked into the A-Shell executable. Although we make available, on a somewhat customized basis, the tools for developing your own subroutines in C, most would-be subroutine developers have been put off by the technical obstacles and have chosen instead to have us write their routines and then include them in A-Shell. This has resulted in 200+ subroutines being included in the standard A-Shell release, but it has limited the development of new subroutines, especially those that might be useful to more than one developer. It has also created an annoying situation in which minor enhancements to a subroutine require a new version of the A-Shell executable to be linked.

To remedy these shortcomings and to encourage the development of new routines, A-Shell Build 779 introduced the ability to create your own subroutines in BASIC. These subroutines can be fetched dynamically from disk when they are called, and offer most of the normal advantages of subroutines (modularity and true argument passing) plus the additional advantage of being dynamically loaded and thus able to be updated and distributed independent of the A-Shell executable.

Nearly everything said here about writing subroutines also applies to external functions which are invoked via XFUNC().

Subtopics

BASIC or C?

Subroutines vs. BASIC Programs

Development Steps

File Handling

Persistent Variable Storage

Calling Variably-Named Routines

External (XFUNC) Functions

Performance Notes

Memory Usage

Loading and Cacheing

Named Parameters in Subroutines

Calling SBX Remotely on ATE Client


BASIC or C?

Subroutines written in BASIC are much easier to develop and deploy, and thus BASIC will most likely be the language of choice for most future subroutines development. However, there are a couple situations where BASIC may not be the best choice. One is where the subroutine performs some low-level, execution-intensive, performance-critical function. Obviously, subroutines written in C (and compiled to machine code and then linked directly into the A-Shell executable) will execute more efficiently, both in the calling overhead and in the instruction execution cycle. This is probably not a major issue, since A-Shell executes so fast. But if you were writing a routine to, say, convert from ASCII to EBCDIC or even to sort an array, it would probably be noticeably quicker in C. (Fortunately, we already offer subroutines written in C for both of those functions.)

The second situation where BASIC is at a disadvantage in subroutine development is where the subroutine needs access to internal A-Shell data structures or functions. However, in most of those cases, specialized knowledge of the data structures or functions is needed anyway, and thus we would be the most logical one to develop such routines. So this probably isn’t much of a practical restriction for developers in the field either.

There is another difference between the way the two types of subroutines execute, but it isn’t obvious whether it is an advantage or a disadvantage. In the case of subroutines written in C, they execute as "true" subroutines, meaning completely within the calling process. In fact, there is very little difference between a BASIC function, such as INSTR() and an equivalent subroutine written in C. They both consist of a single run-time opcode token followed by a list of parameters, and they are both implemented internally in C, and execute completely within the execution environment and stack of the calling program.

Subroutines written in BASIC, on the other hand, are loaded from disk (unless already in memory) and executed in a separate, temporarily allocated memory space. They are still part of the original process and original job, but they have a separate stack and separate BASIC environment, which starts from scratch at the start of the subroutine, just like it does when you CHAIN to a new program. It is in fact very similar to what happens when you use xcall AMOS,"RUN xxxxx" (provided the OPTIONS=AMOS_RUNSBR parameter is set in the MIAME.INI.) The most obvious consequence of this is that regardless of how badly the subroutine screws up, there are only two ways it can abort the calling program. One is by explicitly calling a particular MIAMEX.SBR function (discussed below under "Use End to Return to Calling Program..."). The other is by crashing A-Shell itself, since the subroutine is running in the same instance of the A-Shell executable as the calling program was. (But we’d like to think that crashing A-Shell is more or less impossible, so we don’t need to dwell on this possibility!) Otherwise, regardless of how the subroutine ends, either gracefully or otherwise, it will release its resources and the calling program will resume at the next statement. Be sure to read the following topic on Error Trapping, which relates closely to this topic.


Subroutines vs. BASIC Programs

Subroutines written in BASIC are written and compiled just like normal BASIC programs, except for a few differences. The first is that after compiling (which you must do with the /X:2 option), you must change the extension from RUN to SBX; better yet, use the ++PRAGMA SBX which automatically creates an SBX instead of a RUN. The extension "SBX" was chosen, rather than SBR, to eliminate confusion between machine language SBRs or XBRs for AMOS and BASIC SBXs for A-Shell, particularly for dealers that distribute their application on both AMOS and non-AMOS platforms. The search path for SBXs is the same as that for RUN programs (i.e. current [p,pn], [p,0], BAS:), unless the system parameter OPTIONS=SBX_RUNDIR is set, in which case the [p,0] part of the search path is replaced with the location whence the current RUN file was loaded.

Because of the SBX extension used by subroutines written in BASIC, these routines are often referred to, elsewhere in this document or in other documents, as SBX Modules or SBX Routines.

The biggest difference has to do with parameter passing. Standard RUN programs do not receive parameters, except via the command line or via some indirect method (such as COMMON or a shared file.) Subroutines, on the other hand, generally receive parameters from the calling program, often updating one or more of them for return to the calling program. (This is one of the main advantages of external subroutines vs. those that you include within your Basic program, which do not support true parameter passing.) From the standpoint of the calling program, there is no difference in the way parameters are passed between a traditional subroutine and one that was written in BASIC. But from the standpoint of the subroutine itself, special techniques must be used to retrieve and return parameters. These steps are actually analogous to the procedure used in subroutines written in assembler under AMOS to process the parameters. In this case, however, you use special statements (XGETARG/XPUTARG) or MIAMEX functions rather than system library calls (as with AMOS subroutines) or direct binding (as with many other languages.)

The third difference is that unlike normal BASIC programs, for which the PROGRAM statement is optional, with SBX routines, it is mandatory. (This is also analogous to the situation under AMOS, where assembler subroutines must have a version header.) The following section describes these differences and a few others in a step-by-step manner.


PROGRAM statement

Rewritten August 2015

PROGRAM progname, vmajor.vminor {vsub} (vedit) {,flag}

The optional PROGRAM statement embeds a header in the compiled object code (RUN, LIT, SBX) containing the specified version and flag. The version information may be retrieved both within the running program and from external program files, and is obviously very useful in keeping track of which versions of each module that you have installed or running.

Parameters

progname

name of the program (1-10 RAD50-compatible characters). Note that it doesn't actually get embedded in the compiled code though, so it mainly servers as a source code documentation.

vmajor

major version (0-255).

vminor

minor version (0-15).

vsub

sub-version (A-O).

vedit

edit number (0-4095).

flag

optional flag, default is -1. The only allowed value other than -1 is -2, which causes the program to be allowed to run even if the job is not currently logged in. This is necessary for LOG.LIT, and is otherwise convenient for command programs which may be specified directly on the ashell startup command line. Note however that such a program should then use XCALL LOG or some equivalent mechanism to establish a current directory before accessing files.

Examples:

program MYPROG,1.0(100)

PROGRAM anotherprg,234.15B(4001),-2

Comments:

Given the fairly large range of vedit values (0-4095), it's a useful convenience to treat it as unique identifier for source code changes, leaving the vmajor, vminor and vsub values to be used for higher level purposes (marketing, general releases, etc.) Both of the program editors VUE and APN have macro functions to help streamline the process of associating changes in the edit number with source code comments which programmers should take advantage of. For VUE, the command is Control+_ E, which increments the vedit number in the program statement, if found, or in a comment consisting of ";VEDIT=###", and inserts an edit history node. For APN, you can define your own macro via the Text Clip system. The standard release comes with two related macros, "prog" for creating a skeleton program header and "eh" for entering a new edit history item.

See Also:

• DIR.LIT: /V switch to display program file versions

• GETVER.SBR: get version of current running program

• Fn'FileVer$: get version from file (in SOSFUNC: of the SOSLIB)

• VERSYS.LIT: additional version info


include (++) xcall.bsi

You should ++INCLUDE ASHINC:XCALL.BSI at the start of your subroutine. This file is included in the standard A-Shell release (see notes on ASHINC), and includes some symbols and MAP statements which are used by the parameter passing routines. It will set the variable XCBCNT to the number of parameters passed to the subroutine, and will set up the following array structure with the types and sizes of all the parameters:

map1 XCBCNT,f,6 ! # of parameters passed

map1 XCBSTRUCTX

map2 XCBSTRUCT(30) ! (max of 30 params to xcall)

map3 XCB'PTYPE,b,2 ! (0=X, 2=S, 4=F, 6=B,+16=array)

map3 XCB'PSIZE,b,2

Since this BSI includes code as well as MAP statements, you must position it so that comes before any executable code in your subroutine that deals with parameters. Note that it is not strictly necessary to ++INCLUDE xcall.bsi, unless you plan to use the MX_XCBDATA routine for parameter passing, or you want to know the number and types of parameters that were passed.


Retrieve Individual Parameters

Explicit statements or calls must be made to retrieve the parameters passed to the SBX routine. This may seem like an extra step compared to languages, like C, which handle the parameter passing more directly (by setting it up at compile time). But it is actually similar in concept to the higher level, runtime-adaptable interfaces like ActiveX/COM, which provide the flexibility for the modules to examine their own interfaces at runtime. This adds a little overhead and some complexity, but allows the external modules to be much more resilient to version changes in one side independent of the other. For example, a subroutine may be designed initially with 3 parameters, but later additional features may be added that require another parameter. The updated subroutine can still work with older programs since it can see that only 3 parameters were passed and act accordingly. In fact, the older version of the subroutine can even still work with newer programs, since the additional parameter can be ignored. Or, it can report to the caller that there seems to be a version mismatch. All this makes it much easier to develop reusable subroutines independent of the applications that use them.

There are two different methods for retrieving parameters. The older method (now deprecated as of Build 903 but still supported) uses the following subroutine:

xcall MIAMEX, MX_XCBDATA, xcbadr, xcbget, <parm#>, <variable>

MX_XCBDATA is a constant, defined in ASHINC:XCALL.BSI, specifying the opcode to MIAMEX.SBR. The first <parm#> is 1 (not 0.) The <variable> you specify should be mapped in a way that is "reasonably compatible" with the actual type and size passed to the subroutine, although conversions and truncations will be applied automatically if necessary. XCBADR is a pointer to the parameter list, and is set up automatically by XCALL.BSI. XCBGET is another constant, also set up by XCALL.BSI, which indicates the operation (get vs. put.)

The new method (Build 903+) uses one or both of these special Basic statements:

XGETARGS ARG1{,ARG2,...ARGN}

XGETARG <arg#>,ARG

The first statement (XGETARGS) retrieves (some or all of) the subroutine arguments into the corresponding variables. (The first argument is returned in ARG1, the second in ARG2, etc.) If more args were passed than you specify variables for, the extra arguments are ignored. Conversely, if you specify more ARG variables in the XGETARGS statement then were passed by the caller, the excess ARG variables are ignored. In either case, the operation is non-destructive to the original argument list, so you can later go back and retrieve (or re-retrieve) parameters using XGETARGS, XGETARG, or the original MX_XCBDATA statements. XGETARG <arg#>,ARG performs the same function as XGETARGS except that it retrieves only the one argument (whose number is specified in <arg#>, with the first parameter being #1).

As with the original MX_XCBDATA operation, variable type and size conversions will be made as necessary, within the bounds of reason.

If the subroutine supports different, incompatible parameter calling formats, it can examine the parameter count, type, and size information provided in the XCBCNT and XCBSTRUCT variables set up by ASHINC:XCALL.BSI and then use the appropriate XGETARG or XGETARGS statements.


Return Individual Parameters

After you have done all of your processing, to return any individual parameters to the calling program, use one of the following.:

xcall MIAMEX, MX_XCBDATA, xcbadr, xcbput, <parm#>, <expression>

XPUTARG <parm#>,<expression>

Both methods are supported, but as of Build 903, the XPUTARG statement is preferred (and is more efficient). Note that unlike the retrieve parameter statements where you must specify actual variables to received the parameters), the "put" parameter statements allow you to specify a variable or an expression.


Ending / Returning from SBX

The SBX routine will end and return to the calling program when it hits any of the following:

• An END statement.

• The physical end of the SBX. This is not very good form, but acts the same as END.

• A RETURN (<expression>) statement. This is a special form of the RETURN statement used to return from a GOSUB, which takes an expression argument in parentheses. If the SBX was called as a function, via XFUNC() or XFUNC$(), then the <expression> is returned as the value of the function, and should be a numeric or string expression according to the way the routine is intended to be used. See External (XFUNC) Functions for details on writing and using SBX routines as functions. If the SBX was called via XCALL or VXCALL, then the <expression> is discarded and the statement treated just like END.

The only other option would be to abort directly to the dot prompt (without returning to the calling program), which you can do with the following statement:

xcall MIAMEX, MX_EXIT


Return with Function Value

As of Build 828, you may also return from an SBX routine using a special form of the RETURN statement:

Return(<expression>)

This statement sets the return value of the function if the SBX was called via XFUNC() or XFUNC$(). If the SBX was called via XCALL or VXCALL, then the <expression> is just discarded and the statement acts like the END statement (i.e. returning to the calling BASIC program).

See the subsequent topic for more details on external functions. This is an A-Shell extension and requires that you compile with the /X:2 switch.


Compile, Rename to SBX

Compile the subroutine as you would any other BASIC program, and then rename the RUN module to SBX. You may want to relocate it to the [p,0] or BAS: account if you want to be able to access it from other [p,pn]’s.

You may want to create your own DO file, e.g. COMSBX.DO, which compiles your SBX modules and renames the resulting .RUN file to .SBX.

You may also want to always compile with the /X:2 switch (for A-Shell extensions to AlphaBASIC.) This is mandatory if you use the XGETARG or XPUTARG statements, but even if you don’t, it clearly marks the resulting module as not being compatible with AMOS, eliminating any possibility of confusion by accidentally executing it under AMOS.

It is also recommended that you use the /M switch (to enforce mapping of all variables.) This is good programming practice in general, but is particularly useful in subroutine programming where it will quickly point out two of the most common subroutine programming errors, forgetting to ++INCLUDE ASHINC:XCALL.BSI, and misspelling one of the constants such as XCBGET, XCBPUT, MX_XCBDATA, and MX_EXIT.

As an alternative to manually renaming the .RUN to .SBX, you can specify the following pragma:

++PRAGMA SBX

Or, you can compile with the /X:3 switch, which is like /X:2 but automatically invokes the ++PRAGMA SBX feature. In either case, the output of the compilation will be an SBX rather than an SBR.

Compiling a new SBX doesn’t necessarily replace one that is loaded into user memory! Always do a DEL * to force a fresh copy to be loaded from disk.


Memory Considerations

The default amount of memory available to these subroutines is 360K, but this figure may be changed using the MEMORY statement in the System Configuration file. If the current memory partition has sufficient room, the SBX will use that memory like subroutines do under AMOS. Otherwise, a new, temporary partition will be allocated.

Although memory allocation is fast, if you are concerned about minimizing SBX calling overhead, you would be advised to make the main memory partition large enough so that the SBX memory can be taken from it. For example, if your SBX routines can get by with 360K, and your largest RUN program requires 400K of working memory, then if you set your memory partition size to more than 760K, the SBX routine will be able to share the same memory allocation with the calling program. (Of course, nesting SBX calls would require successively larger partitions to avoid the automatic temporary memory allocations.) To determine how much free memory is available, use the mem(0) function within a running program. To trace memory allocations in the ashlog.log file, use SET TRACE MALLOC ON before running your program.


Nesting of Subroutines

As should be obvious from the fact that these subroutines themselves use MIAMEX.SBR for parameter passing, it is possible to nest subroutine calls, regardless of whether the subroutines are written in BASIC or C. Each level of nesting, though, does use up memory and stack space so it is not recommended that you get too carried away with nesting, particularly with highly recursive subroutine calls.

If you are planning to nest subroutines, for maximum speed it is best to make sure the main memory partition has enough free space for the minimum SBX memory, plus the actual amount of SBX memory required for the number of levels of nesting. As long as there is sufficient free memory available in the partition for the minimum requirement (360K or as specified by the MEMORY= statement), then it will actually only use as much as is needed. So for example, if you have 500K free in the main partition and your SBX minimum is 360K, the first SBX call will simply take over the 500K available. But if the subroutine is small, it might only use up, say, 30K of that 500K, leaving 470K free for the next level down. You could repeat that process severa levels deep before the original 500K was used up, after which separate system memory allocations would have to be made for subsequent levels.


Error Trapping

Since subroutines written in BASIC have their own execution environment, they do not share the error status conditions or error trapping of the calling program. Thus if a BASIC error aborts the execution of the subroutine, causing it to end, it will still return to the calling program, which will have no idea that the error occurred in the subroutine. Thus, it is nearly essential that you implement an ON ERROR GOTO in the subroutine, as well as some means of passing error conditions back to the calling program (such as with a "STATUS" parameter in the subroutine parameter list.) If you aren’t going to pass a status parameter back to the calling program, it may be best to use MX_EXIT to abort to the dot prompt.

If you don’t trap errors within your subroutine and an error occurs, the standard BASIC error message will be printed and the subroutine will return to the caller. However, since this is very likely to go unnoticed by the user, A-Shell will delay for a few seconds after displaying the error message, to give you at least some chance of being able to diagnose the condition.

You can force the ^C condition to be passed back to the calling program using:

xcall ASFLAG, AF_SETCTRLC ! (128) set ^C on return from sbx


File Handling

SBX modules can access files pretty much just like any other program. There are some subtleties, though, with respect to the relationship between the files opened within an SBX module and those opened by the calling program or module. This section discusses those issues.

Subtopics

Accessing Open Files

File Open Persistence

File Auto-Close Behavior

File Channel Conflicts


Accessing Open Files

Although SBX routines start with a fresh memory partition, they inherit the table of open files from their parent. This allows the subroutine to read and write to files that have been opened by the calling program. However, because of this, if you want to open and close files within the subroutine independently from the calling program, then you must be careful to use different file channel numbers.

It would probably be a good idea to adopt some systematic approach to the use of file channels, such as reserving file channels 60000-65000 for use within subroutines.

For sequential files (opened for INPUT, OUTPUT, or APPEND) no special techniques are needed to access the files opened outside of the subroutine. You can use PRINT #CH and INPUT #CH statements just as if you had opened the specified file channel (#CH) within the subroutine.

For random (contiguous) and ISAM files, however, the problem is that the file number variable, which was associated with the file when the file was opened, is only accessible from within the module that opened the file (i.e. the module that owns the record number variable.) So, in the case of random files, while you could access them, you could not change the record number (and thus would only be able to read and write whatever record was last accessed in the calling module). In the case of ISAM-A files, you would be able to move around in the file because this is based on key operations, but you would not be able to get the status back for each operation. To surmount that obstacle, you can call a special MIAMEX function to associate a new record-number variable (and in the case of ISAM, a status variable) with the file:

xcall MIAMEX, MX_FLSET, ch, status, recvar'adr {,statvar'adr}

This function assigns a new (local) record number variable and optionally, ISAM-A status variable, with the file opened by the calling program on channel CH. Note that the parameters have to be mapped in a specific way; see MX_FLSET for details.

Once you successfully execute the MX_FLSET operation, you can have full access to the RANDOM, ISAM, or ISAM-A file within the subroutine.

Comments

See XREAD, XWRITE for an alternative which avoids the need for MX_FLSET.

Don’t forget that the record number and ISAM status variables to be used within the subroutines are the ones whose address(es) you pass to the MX_FLSET subroutine, and not the ones that were originally used in the calling program. Otherwise, you may appear to be reading and writing the file normally within the subroutine, but you will either be reading and writing the same record over and over again (i.e. the last one accessed by the calling program) or in the case of ISAM-A, you will be accessing the file but never getting any valid status results back. (Every key operation would return 0 for ISAM’EQ, since the real return value would be sent to the variable in the calling program.)

Also, be careful of FILEBASE. You may safely ignore this for ISAM-A files where you may never explicitly use the record number, but for RANDOM files, you would ideally want to make sure that the subroutine was written to use the same FILEBASE as the calling program. But unfortunately there is no way to guarantee this. The effective FILEBASE is the one that was in effect when the file was opened; there is no way for the subroutine to override this other than closing and reopening the file.

A-Shell automatically resets the record number and ISAM status variables to their original values on return from a subroutine call, so it is not necessary for the calling program (even if it is itself an SBX routine) to worry about what the subroutine may have done to its file control variables.


File Open Persistence

There are a few ramifications of the fact that files remain open across subroutine calls that you should be careful of. One is that it works both ways. That is, files that are opened within a subroutine remain open (unless explicitly closed or the AF_SBXASRUN flag is set) when the subroutine returns to the calling program. So, for example, you could create an "open file" subroutine whose job was to figure out which file to open and then returned the file channel number. Then, the calling program would have to use MX_FLSET as described above to hook its control variables to the file.

A second ramification is that a file opened by the main program and closed by the subroutine remains closed when the subroutine returns to the calling program. This would surely be a dubious programming technique, but is still worth watching out for. Of course this also works both ways: a file opened in the subroutine may be closed in the parent program.

A third ramification derives directly from the previous one but is much more useful: a file opened in a subroutine may remain open across multiple calls to the subroutine. For example, if you have a subroutine that reads a single response from a serial port under UNIX, rather than opening and closing the file on each subroutine call, or opening the file in main program even though it is only accessed in the subroutine, you may decide to open it the first time the subroutine is called, but just leave it open in case the subroutine is called multiple times.

This raises the question of how to tell if a file is open on a specified channel. The answer is the EOF() function. EOF(CH) (where CH is the file channel number you are inquiring on) will return negative one if the file is not open. Otherwise, it will return 0, or possibly 1 (to indicate a sequential input file at EOF.)

Because these persistence issues are invitations to confusion, it is a good idea to think through your SBX-related file access strategy with an eye towards simplicity.

If you open a RANDOM, ISAM, or ISAM-A file within an SBX routine and then wish to access it in a later call to that routine, you should repeat the MX_FLSET operation to reset the file’s control variables. This is not necessary for sequential files which don’t have control variables, but is essential otherwise, since the control variables are referenced by the file table via their address in memory, and that address is almost certain to change with each call to the subroutine.

See Also

• File Auto-Close Behavior


File Auto-Close Behavior

Created July 2015

Revisions to file auto-close behavior with respect to SBXs:

• ASQL connections are now auto-disconnected using the same set of rules used for the auto-closing of normal files.

• By default, files and ASQL connections are auto-closed only when a RUN file terminates—i.e. not on return from an SBX.

• If the AF_SBXASRUN flag is set at the time a file is opened within an SBX, that file will be auto-closed (or auto-disconnected for ASQL) when the SBX returns. Note that while this behavior is intended as a convenience for unexpected aborts within an SBX, auto-disconnecting an ASQL connection does not auto-close the ASQL library itself. That probably won't matter to the application, but may prevent the library from being unloaded until the A-Shell process finally terminates.

• In a nested SBX call (where an SBX calls another SBX), if the AF_SBXASRUN flag is clear when the file is opened, then it will be auto-closed or auto-disconnected on return from the last SBX that was called with the flag set. For example, if A.RUN XCALLs B.SBX, which sets the AF_SBXASRUN flag and XCALLs C.SBX, which clears it, then any files subseuqently opened in C.SBX will be closed when B.SBX (not C.SBX) returns.

History

2015 March, A-Shell 6.1.1405: Add feature to A-Shell


File Channel Conflicts

When you want to open a file within an SBX that has nothing to do with the calling program, one concern is how to select a file channel that is guaranteed not to be in use already. The best way to do this is to start with a suitably high file channel (one not likely to be used by the calling programs), and then just to be safe, use the EOF() function to verify that the channel is free, incrementing the channel if necessary until a free one is found. For example:

FCH = 50000 ! start with a high file channel

do while eof(FCH) = 0 ! keep looking until we find a free channel

FCH = FCH + 1

loop

open #FCH, FSPEC, output

...


Persistent Variable Storage

Sometimes it is useful for an instance of an SBX to be able to store some data for a subsequent instance of the SBX to be able to use. There are several ways to accomplish this:

• Pass the data back to the caller in a parameter, and have the caller then pass it back to next invocation of the SBX. The downside of this is that you burden the calling program with caring for data which it otherwise has no use for, reducing the degree of data encapsulation offered by the subroutine.

• Store the data using COMMON.SBR. This can work for small amounts of data, but one problem here is that COMMON is subject to various global configuration options, which will interfere with the ability to use your SBX in different environments (i.e. reduces portability).

• Store the data in a file. This avoids both of the issues listed above, but introduces a couple of its own. A minor issue is that storing data in a file is somewhat less efficient than memory based schemes, so might add significantly to the performance overhead of an SBX. A larger one is that in order to allow for each job to have its own inter-SBX storage facility, you’ll probably have to incorporate the job number or name into the storage filename, which means that you might end up creating a large number of files. And since the SBX can’t guarantee that the caller will give the SBX an opportunity to clean up after itself, you might end up littering the disk with files that have no meaning to the application (thus making it hard to know whether they can be deleted or not.) (You could reduce the file count by storing each job’s data as a record within a single file, but this introduces issues associated with maintaining the structure of the file.)

• Store the data in user memory. This avoids all of the problems above. It doesn’t impose any responsibility on the calling program, assume anything about the environment, or add any disk I/O overhead. And, it is self-cleaning, since user memory modules are automatically deleted when an instance of A-Shell exits. So this would be the recommended method for most cases, provided you can count on A-Shell build 916 or higher. The following excerpt of sample code illustrates the technique.

map1 LOCAL'STORAGE ! variables internal to SBX but needed between calls

map2 VAR1,S,100 ! arbitrary variables used by the SBX

map2 VAR2,F,6

Etc.

map1 MODNAME,S,14,"SBX99.MEM" ! arbitrary module name

! To save the data in LOCAL'STORAGE for a subsequent instance of this SBX...

xcall MIAMEX, MX_USRLOD, idx, modname, usrmem'nofile, local'storage

if IDX <= 0 then goto UNABLE'TO'STORE'USRMEM ! (error)

! To retrieve the data from user memory into LOCAL'STORAGE...

xcall MIAMEX, MX_USRIO, status, modname, 0, local'storage

! To update the data in the user memory module directly from LOCAL'STORAGE,

! (without deleting / recreating the module as with MX_USRLOD)...

xcall MIAMEX, MX_USRIO, status, modname, 1, local'storage

! To delete the module explicitly...

xcall MIAMEX, MX_USRDEL, idx, modname

Prior to build 916, you could still use this strategy but would have to first create a sequential disk file in order to load it into memory. Also note that if you want to protect the module from being deleted inadvertently, you can use FLAGS argument to the MX_USRLOD and MX_USRDEL routines to lock and explicitly unlock the module.


Calling Variably-Named Routines

A-Shell 4.7(813) added a new Basic language statement which allows you to call an external subroutine whose name is resolved at runtime rather than at compile time. The statement is identical in syntax and usage to XCALL, except that "XCALL" is replaced by "VXCALL", and the name of the subroutine, which must be a literal in the case of XCALL, must now be a quoted string, string variable, or expression. Here are some examples:

map1 SBRNAM$,S,6,"HELLO"

VXCALL SBRNAM$,ARG1,ARG2,... ! (xcall HELLO,...)

VXCALL "HELLO",ARG1,ARG2,... ! (xcall HELLO,...)

VXCALL SBRNAM$+"1",ARG1,ARG2,... ! (xcall HELLO1,...)

As with other A-Shell extensions to Basic, you must compile your programs with the /X:2 switch to enable the use of the VXCALL statement.

VXCALL can be used equally well with embedded subroutines (those written in C and linked into A-Shell) and external SBX routines. However, its usefulness is magnified in the case of SBX routines, providing an almost open-ended mechanism to customize application behavior at runtime. The following examples will help illustrate this.

First, let’s consider an invoicing module installed in many businesses. Unfortunately, many businesses are particular about their invoices, perhaps requiring a special form, or wanting their own logo, or custom messages to be printed at the bottom, etc. Rather than having to include a bunch of "IF" conditions and a bunch of different routines within the invoice program (with only one being used at a particular site), you could just design your invoice program to assemble the necessary line items and header information into a standardized structure, and then pass it via RXCALL to an invoice formatting subroutine whose name was a function of the site or client ID. For example:

map1 INV'DATA ! (uniform structure with invoice data)

map2 INV'HDR'DATA

map3 ...

map3 ...

map2 INV'LINE'ITEMS(500)

map3 ITEM'NO,S,10

map3 ...

<load up INV'DATA structure...>

VXCALL SITE'ID$,OPCODE'INV,INV'DATA ! (format & print invoice)

In the above example, we are passing an "opcode" variable to the SITE’ID$ subroutine to allow for the possibility of combining several different customization functions within a single subroutine. The developer/distributor of the software could then release source code to a standard version of the customization module (renamed to match the SITE’ID$), and allow each site to customize it as they choose. The fact that the A-Shell runtime system contains the compiler, and that the linking and binding for such subroutines is all done at runtime, makes this particularly feasible. Naturally, there would be a training issue, but in some cases that might create an opportunity to engage the customer’s desire for customization and earn additional revenues at the same time. Even if the developer/distributor does all the customization on behalf of the client, this mechanism provides a very useful mechanism for modularization, isolating the code that is site-specific, from the core of the application.

As a second example, consider the COMMAND=SBX:<sbxname> parameter in the A-Shell printer initialization files. Briefly, what this statement does is cause the print spooler interface to pass the print file to the specified subroutine for processing, either before or in lieu of sending it to a printer. Without the VXCALL mechanism for binding the subroutine name at runtime, this would be impossible.

As a third and final example, VXCALL opens the possibility for the creation of a generic front-end subroutine that handled some kind of pre-processing or interfacing function that you wish to apply to a range of subroutines, some of which you may not have the ability to modifiy directly because they are embedded within A-Shell. Why would you want to do such a thing? One reason might be for security or licensing. Let’s say you have a series of data access or display subroutines, and then your industry (for example, the health care industry) decides to impose (or the government forcefully imposes on them) a regime of strict security requirements to protect the privacy of data. One way to deal with such a requirement would be to develop a single security package that could then be wrapped around a variety of subroutines that had anything to do with data access. For example, if you called your wrapper routine SECURE, you might use it with existing subroutines such as SERCH (to lookup records) and DSPLY (to format/display data) as follows:

xcall SECURE,"DSPLY",XMAX,ROW,COL,DECMAL,OPTION,1

xcall SECURE,"SERCH",CH,REC,KEY,...

The observant reader will note that we didn’t use VXCALL in the above statements, but the point is that our hypothetical SECURE.SBX module would need to use VXCALL to call the routine specified in the first argument. Otherwise, we would need a different version of SECURE.SBX for every other subroutine we wanted to apply it to.

Naturally, this approach introduces another layer of overhead on the underlying subroutines, but virtually all other industry-standard approaches to creating security wrappers around data objects involve substantial overhead as well. It should also be noted that the approach doesn’t provide a very thorough level of data security, since the data itself can presumably be copied and accessed by rogue parties, without using the hypothetical SECURE routine. To protect against that kind of access, you would have to encrypt your data, and build the decryption logic into the SECURE routine itself.

Update Note: A-Shell Build 1186 of June 2010

Names up to 10 characters are now supported. Prior to this update, while the compiler didn't/couldn't complain, the runtime system looked at only the first 6 characters.

Note that the 10 character limit is not related to the RUN format but to the existing 10.3 framework for files loaded into USRMEM and which benefit from the emulation of the AMOS-style file system. When those get expanded, the VXCALL name limit will expand with them.


External (XFUNC) Functions

As of Build 828, A-Shell supports programmable external functions. These are created and act very much like subroutines written in BASIC, except that they return a value and may therefore be used within expressions. Just as external subroutines are accessed via the XCALL (or VXCALL) statement, external functions are accessed via the XFUNC() or XFUNC$() function:

XFUNC(Sbxnam, Arg1, Arg2,..., Argn)

XFUNC$(Sbxnam, Arg1, Arg2,..., Argn)

XFUNC() (without the $) is a numeric function (i.e. evaluates to a floating point value), while XFUNC$() is for string functions. Sbxnam is a string expression that evaluates to the name of the SBX module containing the function code. Arg1 through Argn are arbitrary arguments or parameters to the function (analogous to the parameters in a subroutine statement.)

From the standpoint of the calling program, XFUNC() and XFUNC$() may be used within expressions just like any other numeric function or string function, for example:

PRINT XFUNC$("CENTER",Name$,40);

TOTAL = QTY * XFUNC(PriceFunc$,Part$,Cust$,QTY)

The SBX implementation of the function must end with a special version of the RETURN statement which specifies the value to return:

RETURN (<expression>)

The <expression> should be numeric for functions to called by XFUNC, and string for those called by XFUNC$. This form of the RETURN statement will be treated the same as END (i.e. terminate subroutine and return to calling program) if the SBX was called via a subroutine statement.

External functions may also return updated parameter values just like XCALL subroutines do. In fact, a single SBX module may act as both an external function and an XCALL routine. The distinction is just in how it is called (via XCALL, XFUNC or XFUNC$).


Performance Notes

As a rough comparison of the performance benefits of these two SBX enhancements (XGETARGS and the improved memory allocation), I ran 500 iterations of FACT(30) (i.e, 15000 subroutine calls, nested from 1 to 30 levels deep). On a 1.7MHz laptop, with the previous method, the elapsed time as about twelve seconds versus about two seconds for the new method, i.e. a six-fold improvement, with the new method doing about 2500 SBX calls per second. At 2500/sec, the overhead of SBX calls is negligible enough to not affect many kinds of operations. (But performing the same logic within a single program using global memory variables is still an order of magnitude faster, so you might not want to use nested SBX functions within a CPU-intensive calculation.)

On another test, I wrote a simple SBX which received a channel number and a string and output the string to the specified print file. I then compared the performance of outputting to the sequential file via the XCALL and directly, i.e.:

xcall XPRNT, channel, pline

versus

PRINT #channel, pline

This ran about 7K lines per second with the XCALL to XPRNT.SBX, and about 140K lines per second directly. Again, the message is that using an external XCALL is an order of magnitude slower than doing the same thing directly, but, depending on the situation, that may not be significant. (In an application that generates a 1-5 page printout based on user input, it won't make any difference; in an application that generates a 10,000 page report, the difference will be measured in seconds.)

Obviously, the effect of the overhead is progressively reduced as the amount of work done in each iteration of the subroutine is increased. For example, if instead of merely outputting a line of text to a file, our above XPRNT.SBX routine created an entire page, then the total overhead of the SBX call for even a 7000 page report would be only one second. Or, a more realistic example would be using a subroutine to format and display a field of data. Since you can hardly squeeze more than 100 or so fields of data on a single screen, the total SBX overhead for displaying the 100 fields on the screen would be a few milliseconds, which is not going to matter in that context.

Considering that performance is no longer a consideration in most interactive business applications, the modularization and reusability benefits of external subroutines combined with their reasonably low overhead, argue for their greater use in A-Shell/Basic software development.


Memory Usage

When an SBX routine is called, A-Shell ensures that it has available to it, at a minimum, the amount of memory declared in the second argument to the MEMORY statement in the miame.ini. (If not specified, the default value is 360K.) If the amount of free memory in the current partition (this is the amount that the function mem(0) would display) is sufficient, the SBX takes over all of that free memory in the parent job. Otherwise, a new, temporary partition is allocated using the minimum size.

Note that when SBX calls are nested, the amount of memory used up in each level is only the amount actually needed, not the full minimum as specified by the MEMORY= statement. So, for example, if your MIAME.INI has MEMORY=1000K,500K and you call a series of small nested subroutines, you may be able to stack them many levels deep (as opposed to just 2 levels as implied by the ratio of 1000K to 500K). However, once the amount of free memory in the main partition falls below the minimum (500K in this case), then each nested SBX call after that will allocate a separate 500K temporary partition (which is freed up when the SBX returns).


Loading and Cacheing

Added July 2011

When the RUN interpreter encounters an XCALL statement, it first checks to see if it refers to an internal SBR (embedded within the A-Shell executable). If not there, it checks to see if there is a matching SBX loaded into the user's memory, either due to an explicit LOAD operation, MX_USRLOD, or an implicit prior load of the same SBX. If not in memory, a disk search is performed (looking in the current [p,pn], the [p,0] or RUN directory, depending on SBX_RUNDIR option, and the BAS: directory, in that order), and if found, the SBX is loaded into user memory.

If the SBX is already in memory, it can be reused directly without reloading. And any SBX loaded into memory this way will remain in cached in memory for a time, based on available space and usage patterns to avoid the overhead of having to constantly reload it from disk. (This cache feature essentially eliminates the need to pre-load subroutines into memory, an optimization technique that was common in AMOS.) However, one potential problem with the cache mechanism is that in order to use an updated version of an SBX (newly compiled or newly copied to the target system), the old copy of the SBX must first be removed from memory. COMPIL.LIT will automatically do a DEL * to avoid confusion over this detail, but in other cases you would be on your own to remember to do a manual DEL * or else wait an unknown amount of time until the SBX gets flushed out of memory to make room for something else.

As of 5.1.1221, this potential problem is automatically taken care of. When an SBX is called, A-Shell checks to see if the version available on disk is newer than the one in memory, and if so, automatically reloads it from disk. To reduce the overhead of this check to a negligible amount, the test is never performed more often than once per fifteen seconds for any single SBX. In other words, within fifteen seconds of copying a new version of an SBX into the search path, all calls to the SBX will begin using the new version.

Note that the test is not "directional", i.e. it will reload the version on disk if there is any difference in the time stamp (newer or older), so you can roll back to a prior version the same way you update to a newer version.

WARNING: The search path used to compare the disk version to the memory version is identical to that used to actually load the routine from disk, i.e. first [p,pn], then [p,0] (or the RUN file location, if SBR=SBX_RUNDIR), and finally BAS:. If you intend to roll out a new version of the SBX and take advantage of the AF_SBXAUTOUPDATE feature, make sure that your new version appears before any older versions in the search path. (And if, for some hard-to-imagine reason, you don't want users to immediately being using an updated SBX, don't copy it into the search path.)


Named Parameters in Subroutines

Added January 2014

As described in Named Parameters, you may use named parameters in conjunction with A-Shell functions and procedures. Parameter passing to subroutines is nearly identical to that for procedures and functions, so the implementation details are nearly the same. The main difference is that since subroutines do not have definition statements like functions and procedures do, a new statement had been introduced to allow you to define their parameter names and default values:

DEFXCALL xcallname{+|,}pname{|alias}{=defval},pname{|alias}{=defval}...

DEFXCALL works similarly to FUNCTION and PROCEDURE definition statements, defining the names of the parameters, their order, and optionally default values. But there are several subtle differences, noted below:

• Unlike functions and procedures, subroutine names are not case sensitive, so neither is the DEFXCALL statement. This applies to the subroutine name and the parameter names, but not to the default values. The following two statements are therefore equivalent:

DEFXCALL MSGBOX,MSG,TITLE="Warning",FLAGS

defxcall msgbox,msg,title="Warning",flags

• Immediately following the xcall name, you can use a "+" instead of a "," to create a definition specific not just to the xcall name but to the combination of the xcall name with a literal string or numeric first parameter. This is particularly useful with some built-in subroutines like AUI and MIAMEX which have completely different syntax and semantics depending on the first parameter. For example:

DEFXCALL AUI+AUI_ENVIRONMENT,opcode,guiflags

DEFXCALL AUI+AUI_EVENTWAIT,parentid,ctlid,exitcode,opflags,timer

DEFXCALL MIAMEX+MX_FSPEC,spec,locpath,ext,flags,ddb,status

• You may define a single alias (alternate name) for any of the parameters. This is useful in cases where documentation or usage evolution has resulted in a parameter having more than one common name. For example, to allow the first parameter to AUI_ENVIRONMENT to be called either opcode or opflags, we could define it as:

DEFXCALL AUI+AUI_EVIRONMENT,opcode|opflags,guiflags

• As with function and procedure definitions, you can define default values for any parameters, and doing so converts all of the other parameters (those without defaults) to mandatory status. However, there are many existing internal subroutines which have a large number of optional parameters, making both named parameters and defaults extremely useful, which may determine semantics based on the number of passed parameters.

To better align the declarative capabilities of DEFXCALL with the ways in which existing subroutines may have been implemented (hidden from view in most cases), another difference is that DEFXCALL supports an option to separate the parameter list into an initial mandatory group and a trailing optional group by enclosing the trailing optional group in {squiggly brackets}. For example:

DEFXCALL TEST1,one,two{,three,four,five}

Note that the {brackets} cannot be nested.

In the above example, we are indicating that the last three parameters are optional, which has these important semantic side-effects:

• it makes the first three parameters truly mandatory, even if no default values are defined

• for the parameters in the optional section, even those with defaults defined will be ignored unless the caller specifies one or more parameters beyond that one.

A few examples will help clarify this:

DEFXCALL TEST1,one,two,three,four,five

DEFXCALL TEST2,one,two=2,three,four,five

DEFXCALL TEST3,one,two=2{,three=3,four,five=5}

DEFXCALL TEST4,one,two{,three=3,four=4,five}

All four routines have five defined parameters, but the semantics and requirements are different in each case.

TEST1's parameters are all optional, because no defaults were specified, nor were {brackets} used to identify an optional section.

TEST2's parameters are all mandatory, because there is at least one default defined, yet no {brackets} to mark the optional parameters.

TEST3 has two mandatory parameters (one and two), and three optional parameters. The default specified for parameter two has no effect, since the parameter being prior to the start of the {optional} parameters, must be explicitly specified by the caller. The caller can specify 2, 3, 4, or 5 parameters (or more), but if parameter five is specified by name, then parameter four must also must also be specified, since it has no default and gaps are not allowed, even within the optional set of parameters. The default value for parameter five has no effect, since the parameters within the {optional} list are only passed to the routine up to the highest numbered parameter that is actually specified in the call.

TEST4 is a more logical version of TEST3 in that it eliminates the two default values that had no effect in TEST3 (two=2 and five=5), and adds one that might be useful (four=4). The following call:

XCALL TEST4,100,200,FIVE=500

would be considered legal—the two skipped parameters have defined defaults—and would be converted the equivalent of:

XCALL TEST4,100,200,3,4,500

WARNING: Because the semantics of the DEFXCALL statement are somewhat tricky, and because this is all quite new, pioneer developers are invited to experiment with it, particularly with their own SBX calls, but should probably delay using it heavily (especially with subroutines internal to A-Shell) until it has had a bit more field exercise. At the very least, it will make more sense for MicroSabio to release a standard set of DEFXCALL statements for internal/documented subroutines to avoid divergence in the way these common routines are used by different developers.

History

2014 January, A-Shell 6.1.1373: Named parameters implemented in A-Shell.


Calling SBX Remotely on ATE Client

SBX routines can be called remotely on an ATE client by implementing them as functions; see Call SBX as a Function. This can be a very useful and powerful technique to extend application functionality from the server to the workstation—or vice versa, e.g. to allow the application to take advantage of some functionality existing on the Windows workstation but not the UNIX server. The main limitation in this technique is that unlike a local SBX, the remote SBX can directly return only a single value, i.e. the value of the function. But there are ways around that limitation. For example, you can encode multiple values into a return string which are then parsed by the application. Or, the remote SBX can create a file and FTP it back.

One obstacle to overcome with remote SBXs is getting them installed on the client workstation in advance. This can be made simple by use of the utility function Fn'ATE'SBX() available in [907,10] of the SOSLIB.


Create Directories From Applications

There is often some confusion around the topic of creating directories, generally relating to one or more of the following:

• AMOS-style vs. native-style syntax (e.g. "DSK9:[23,4]" vs "/vm/miame/dsk9/023004" or "C:\vm\data\dsk9\023004").

• Checking if the directory exists, vs. creating it.

• SYSTAT.LIT vs. native OS commands vs. XCALLs

It's not possible to answer every related and imaginable question, but here are a few notes that might fill in the blanks for those unsure about the best approach (particularly since the various components may be scattered all over the documentation):

SYSACT.LIT: One option for creating a directory (using AMOS-style syntax) is just to use SYSTAT.LIT, either manually or via a command file. This is the only method that includes the option to create a password for the directory. The main downsides are that: a) it's dangerous, since you can too-easily delete directories this way; and b) if you wanted to do it under program control, you'd have to create a command file and then shell out to it, which introduces a fair amount of additional complexity.

Checking if the directory already exists: If working with AMOS-style syntax, you can use MX_CHKPPN . Otherwise, if your directory spec is already in native form, you can use MX_FINDFIRST . However, in either case, it isn't clear that there is any performance advantage to checking first if the directory exists, vs. just trying to create it. (The operation to create it will internally determine if it exists and just return with an appropriate status code.)

MX_MKPATH : this is the most straightforward approach, regardless of operating system, but does require that you convert your directory spec to native syntax. To do that, you can use MX_FSPEC , but it requires that you set up some map statements and pay attention to several details. A simpler approach is to use the SOSFUNC: function (included in the SOSLIB Fn'FQFS$(spec), which takes a full or partial AMOS-style filespec or relative native filespec (e.g. ".") and returns the corresponding Fully Qualified native File Spec.

As with MK_FSPEC, it may require a dummy file.ext (typically one uses "z.z"), which you can then strip from the end if you just want the directory, as is the case here. So here's an example of using Fn'FQFS$() and MK_MKPATH to create the AMOS-style directory "TMZ0:[15,37]":

++include sosfunc:fnfqfs.bsi

...

MAP1 NATIVEDIR$,S,260

MAP1 STATUS,F

...

NATIVEDIR$ = Fn'FQFS$("TMZ0:Z.Z[15,37]")[1,-5] ! cvt to native and chop off "/z.z"

XCALL MIAMEX, MX_MKPATH, LOCAL, STATUS

IF STATUS # 0 and STATUS # -1 and STATUS # 183 THEN

<handle error - unable to create directory>

ENDIF

Note that for UNIX, the "directory already exists" error will be -1, while for Windows it will 183.

HOSTEX : Another option (again requiring a native spec) is to use XCALL HOSTEX to access an operating system shell command to check for and/or create the directory. (This will definitely require determining which platform you are on first so you can use the appropriate commands, and thus is probably less sensible than one of the above methods which will handle most of that problem for you.) Here we check for the existence of the TMZ0:Z.Z[15,37] directory under Linux and then create it if necessary. (Assume that we have already converted it to the native syntax using a technique like the one shown above.)

MAP1 STDOUT$,S,200

...

XCALL HOSTEX,"stat "+NATIVEDIR$+" >/dev/null 2>&1",STATUS

if STATUS # 0 then

XCALL HOSTEX,"mkdir "+NATIVEDIR$+" >&1",STATUS,STDOUT$

if STATUS # 0 then

? "Error: ";STDOUT$

endif

endif

In the above code, we captured the stdout and stderr from the mkdir command into the parameter STDOUT$ so that we could display the error message if the command failed.

DEVICEs: In all of the above cases, there is an assumption that for the directory to be created, the parent already exists. The parent of a PPN under AMOS terminology would be called a DEVICE. These DEVICEs (which are just directories from the host operating system's perspective) may be created like any other directory. But in order to then reference PPNs within that DEVICE using AMOS-style syntax, the DEVICE must be defined in the miame.ini using a DEVICE statement (which see for details).


Event Tracing

Beginning in A-Shell build 963 of 05 August 2006, a method is available for making it easier to output debugging/tracing/status information without interfering with the GUI screen context. The components of this mechanism are discussed in the following sections.

9/19/06 note from Jack: Perhaps we should create a section in the dev guide for tracing techniques and related info. that would be the place to document the CTRL+SHIFT+DBLRIGHTCLICK command, etc. It would also cross-reference the LOGDIR entry in the Setup Guide.

Subtopics

Opening the Message Window

Using the Message Window

EVTWIN.SBR

ASHLOG.LOG File


Opening the Message Window

10/27/11 note: We just added new doc for trace/debug statements, Jack says this topic can now be cut way down. But I didn't do it and I don't want to bug him, so the cutting down has not yet been done.

NoteTo manually open the message window (aka "Debug Dialog"), use Ctrl+Shift+DoubleClick somewhere on the A-Shell window, but preferably not on a control that might respond to a click. This will pop up a "GUI Control Operations" dialog, on which you can click the "Show Debug Dialog" button.

To programmatically open the message window, use one of the following ASB extended statements; see A-Shell Extensions.

The xxxx.OPEN statements are optional and mainly server to allow you to set the title on the message window. The xxxx.PRINT and xxxx.PAUSE statements will automatically open the message window if necessary.

The <msg> and <title> arguments are each limited to a single string expression (which may involve string operations and functions but must rely on concatenation to assemble a compound string of many parts, rather than commas or semicolons as you can do with PRINT). They may also start with zero or more of the following special control variables:

$# (displays the running message count as a message id #)

$T (displays the time in HH:MM:SS format)

$P (displays the program name in brackets, e.g. <MYPROG>)

For example, the following statement

DEBUG.PRINT "$T $P The value of X is: " + X

would appear something like:

11:25:01 <MYPROG> The value of X is: 25

Note that the first token of the message (space delimited) that does not start with $ cancels scanning for $T and $P and $#.

A special case of the <msg> expression takes the form of "SYSTRACE " following by a boolean indicator, e.g.:

TRACE.PRINT "SYSTRACE ON"

The above will force the system trace option associated with the message window to be turned on. (The manual way to do this is to right-click on the message window, click Properties, and then check the System Trace option.) Being able to do this from within a program is sometimes useful when you want to activate certain verbose traces but only for a short time, or starting at the beginning of a session, before you would have a chance to manually open the message window and turn on the traces automatically.

The xxxx.PAUSE statements are equivalent to the xxxxx.PRINT statements except that they output an additional message to the message window:

<Application paused - Double-click here to resume>

As suggested by the message, the application is then suspended while waiting for the user to double-click the message window. This is intended as alternative to the usual practice of display message boxes which require a click on the OK button to proceed. Note: Ctrl+C will abort the pause and pass the Ctrl+C to the program.

The actual wording of that message and the acknowledgement message when the double-click is received may be customized via the strings 005,002 and 005,003 in SYS:SYSMSG.xxx.

When the DEBUG.xxx or TRACE.xxx statements are executed on a server whose client is ATE, the message is forwarded to the ATE client to display. If the client is not ATE, the message is output to the standard ashlog.log.


Using the Message Window

Updated October 2011

The message window consists of a popup-dialog, initially positioned in the upper right corner of the screen, and filled with a multi-line text control, scrollable in both directions.

this is a linked image

The messages displaying in the Debug Messages window originate from three sources:

• Internal traces generated automatically by A-Shell when activated by the various TRACE flags (see SET TRACE, the TRACE system parameter, and the subroutines MX_GETTRACE and MX_SETTRACE.

• TRACE.PRINT statements in the application

• DEBUG.PRINT statements in the application when the DEBUG flag is set, which can be accomplished with the SET DEBUG command, MX_DEBUG subroutine, or by clicking on the Set Debug Mode option in the Debug Messages window context menu as seen above. (The latter method is particularly handy as it allows activating DEBUG mode externally while running a program.)

The user can move, resize, minimize or close the dialog using the typical mouse operations, without affecting the application. A right-click context menu is also supported, as shown above.

The message window lacks the more advanced capabilities found in text editors, such as search, edit, file operations, etc. If you find yourself needing these functions, the recommended procedure is:

• select the parts of interest, by clicking on individual lines or using Select All on the context menu

• use Copy, also on the context menu

• launch Notepad or aother editor, and paste the copied messages into it

• use the editor for searching, editing, saving, etc.

Or, from the dot prompt, use vue %MIAME%/ashlog.log to access the logged copies of the messages appearing in the window.

Subtopics

Properties


Properties

The Properties option on the menu pops up another dialog containing checkboxes corresponding to the various TRACE options in the miame.ini or the SET.LIT TRACE options. At the top of the dialog is a master checkbox which controls whether any of the system trace messages appear in the on-screen debug dialog. When the dialog is launched manually, by default the system trace option is set, in which case the display can be considered just a slightly more convenient version of the information also being sent to the ashlog.log file. When the message window is opened under program control, the system trace option defaults to off, since the likelihood there is that the program is going to control the information sent to the message window.

this is a linked image

If the system trace option is set, the remaining checkboxes allow you to turn trace options on and off for immediate effect, rather than having to set them globally in the MIAME.INI or from the dot prompt; this makes it easier to turn on a lot of traces for a very short period in order to investigate something within a complex program. Another advantage of the trace window versus the ashlog.log is that the trace window contains only messages for the current instance of A-Shell.

Note that any traces activated in the message window properties will also be output to the ashlog.log file. Turning them on and off this way allows for greater control than would be possible with SET TRACE or adding TRACE statements to the miame.ini.


EVTWIN.SBR

For maximum flexibility, the DEBUG.xxx and TRACE.xxx statements are actually compiled as:

xcall EVTWIN, opcode, string {,optional args}

where opcode is made up of the following parts:

Value | Meaning
&h0001 | Open
&h0002 | Print (or pause)
&h0003 | Close
&h0100 | Debug (versus trace)
&h0200 | Pause (wait for double-click)

EVTWIN.SBR is included in A-Shell, but if you don't like the way it works, you could theoretically replace it by using an alias and supplying your own SBX. Also, under AMOS, or versions of A-Shell prior to 4.9.963, if you want to be able to run programs containing such statements and compiled with /RC, you would need to supply a dummy EVTWIN.SBR (so that the statements had no effect), or if you are really ambitious, create one that does something useful. (Note that the simplest null SBX would be a program containing just an END statement, with the RUN renamed to SBX.)

See Also

• TRACE and DEBUG Statements


ASHLOG.LOG File

Updated September 2011; see History

A-Shell maintains a log of significant events in the file ashlog.log, which can be an invaluable aid in monitoring a system and tracking down problems after they occur. By default it is found in the directory where the miame.ini file is, but the optional LOGDIR directory in the miame.ini can be used to put it somewhere else. The log automatically resets and archives several prior copies of itself (using ashlog.001, ashlog.002, up to ashlog.005) when it reaches a predetermined size (typically 3MB). The log will contain any critical or unusual error messages, plus any of a wide variety of information messages that can be configured using system trace options, which may be set by any of the following methods:

• TRACE statement(s) in the miame.ini. It is recommend that all A-Shell installations have TRACE=BASERR,SIGHUP,INOUT as a minimum.

• SET.LIT (SET TRACE xxxxx ON/OFF)

• call MIAMEX,MX_GETTRACE and MX_SETTRACE

Applications can also output directly to the ashlog.log file using MX_ASHLOG.

from jm March 2011: Note that LOGDIR, TRACE, SET.LIT, MX_xxx and perhaps others in the above topic are all link candidates, depending on whether this is the consolidated version or not.)

History

2011 September, A-Shell 5.1.1231: All program (RUN/SBX/LIT) load errors are now logged to the ashlog.log file, mainly to improve the prospects for detecting and tracking problems.


Debugging Resources

Documentation in Progress

For now, see Event Tracing.

Other topics might be references to some troubleshooting FAQ we have somewhere, how to interpret the cryptic elements in the ashlog message format, how to locate the source line matching an error location, specific tips on debugging XTREE using the message window, etc. etc


Background Jobs

Many applications make use of some kind of background jobs, which leads to the question of how to implement them under A-Shell. UNDER AMOS, you would typically have launched such jobs from the system INI when the system was booted, but under A-Shell/Windows/UNIX there are a variety of possibilities and considerations, which are discussed below.

Launch background job when the system boots

Start by coming up with the necessary command line which will start A-Shell and then the program (typically via a startup command file). You can test that from the shell prompt (under UNIX) or from the Start>Run prompt under Windows. Once you have it perfected in interactive mode, to make it invisible, for Windows, add the -z (invisible) or perhaps -zi (system tray) switch to get it off the Task Bar; for UNIX, add code to the end of the command line to redirect the output, i.e. ">out.lst 2>1" (to redirect both stdout and stderr to the file "out.lst") or "&gt/dev/null 2>err.lst" (to discard stdout but capture stderr). Under UNIX, you'll probably want to add "-td dumb" to set the terminal driver to "dumb" to eliminate emulation escape sequences from any captured output.

Finally to launch your command at system startup, for Windows create a shortcut with the command line and add it to the Startup folder. For UNIX, add it to rc.local (or the equivalent).

Job dies and needs to be re-launched

The first thing your background application should do is check to see if it is already running. One simple way to do this is to use the -j <jobname> switch to force it to use a specific job name. If the job name already exists, the A-Shell launch will fail, so there would be no harm in just re-launching it as often as you like, either manually or automatically. (This assumes that if the job dies, it will close itself down entirely. You can help guarantee that by using the -e startup switch, adding HOST to the end of the command file which starts the app, adding XCALL MIAMEX, MX_EXIT to your error trap, etc.)

Under Windows you can use the System Scheduler (aka "Scheduled Tasks") to force your shortcut to be launched every few minutes, so that if the background job does die, it will automatically get restarted. Same idea under UNIX, except using crontab.

Another possibility is that other jobs in your application can act as watchdogs, such that if they detect the background job is missing, they can relaunch it using XCALL HOSTEX, or, for UNIX, you might prefer XCALL SUBMIT (but use the /NEXT:0-0-0 option to make it run under control of the atd daemon rather than as a child of the job which launched it.)

Detect new version and re-launch

You can use XCALL GETVER to get the version of the currently running program. You can also use MIAMEX,107 to get the version of a program that has been loaded into memory.

To get the version of the program on disk, you could use DIR/V as you suggest, but it would be more efficient to read it directly from the file. Here's how DIR.LIT does it:

map1 STRING'VERSION,s,13 ! Version string

map1 VERSION ! Version no.

map2 VMAJOR,f,6 ! Major version

map2 VMINOR,f,6 ! Minor version

map2 VSUB,f,6 ! Sub version

map2 VEDIT,f,6 ! Edit number

map2 VWHO,f,6 ! Patch level

map1 VRECORD ! version record

map2 VBINARY(8),b,1 ! Individual bytes

map1 VRETURN,f,6 ! No. bytes actually read

MAKE'VERSION:

STRING'VERSION = ""

open #1,FILE$,input

xcall GET,VRECORD,1,8,VRETURN

if VRETURN = 8 and VBINARY(1) >= 254 and VBINARY(2) = 255 then

VMAJOR = VBINARY(4)

VMINOR = VBINARY(3) and 15

VSUB = int(VBINARY(6)/16)

VEDIT = (VBINARY(6) and 15)*256+VBINARY(5)

VWHO = int(VBINARY(3)/16)

STRING'VERSION = str(VMAJOR)+"."+str(VMINOR)

if VSUB then STRING'VERSION = STRING'VERSION+chr(64+VSUB)

if VEDIT then STRING'VERSION = STRING'VERSION+"("+str(VEDIT)+")"

if VWHO then STRING'VERSION = STRING'VERSION+"-"+str(VWHO)

endif

close #1

return

Actually, there is a function in SOSFUNC: to extract the version from a RUN, LIT, or SBX file on disk: Fn'ProgVer$(progspec$)

Note that while you could install a new RUN while the program is running, XCALL GETVER will continue to get the version of the program running in memory, ignoring the updated one on disk. But Fn'ProgVer$() (or the raw code from DIR shown above) will read the version from the disk file, ignoring the one in memory. So by comparing the two periodically, you could detect when the version had been updated.

Node count and licensing

Do background jobs count as nodes against the license? Yes and no. The first background job does count. Additional jobs do not count until you have as many background jobs as you have licensed nodes, and then they start counting.

Keeping track of what background jobs are doing

The time-tested approach is for your background job to maintain a log file and/or status file that you can examine. You may find the SOSPROC: procedure SysLog() to be helpful. Also, keep in mind that if you want to be able to see the latest messages output to a sequential file, you either need to close it after each message (reopening for APPEND prior to each new message) or disable output buffering using MX_NOBUF. You'll also want to make sure when you query the log file that you don't open it in a way that will interfere with the on-going output to it.

Under Windows, if you run your background jobs from the system tray, you'll be able to make them visible by double-clicking on their icons in the system tray. (Although in a multi-user system, you'll have to do this from the PC which launched the job.)

Note: This topic was originally written as a post on our support forum. You might want to check this topic to see if there have been any additional comments: http://www.microsabio.net/ubb2/ultimatebb.cgi?ubb=get_topic;f=5;t=000899


Job Terminations

Most job termination issues are primarily issues under UNIX and Linux with telnet connections, but kills apply to Windows as well.

One problem with non-hardwired connections, such as network and modem connections, is that they can become disconnected unexpectedly. (Actually, under UNIX, turning off a hardwired dumb terminal can also cause the session to be disconnected, but mainly this is an issue for telnet and modem connections.) Under UNIX, such disconnects generally cause the process to be terminated, which may not be such a good thing, particularly if the process was doing some kind of posting. To make matters worse, since the session’s display is disconnected at the same time as the process is terminated, you typically get no message on the screen, making it difficult to track what, when, or even if anything happened.

A closely related situation occurs when a process is killed using the UNIX kill command or A-Shell KILL.LIT command (and this is independent of the hardware connection type).

Under UNIX/Linux, a process being killed or disconnected is sent a "signal" which in most cases can be trapped and responded to by a "handler", which is essentially like the error trap in a BASIC program. A-Shell contains handlers for a number of signals, but the two of interest to this discussion are SIGTERM and SIGHUP. SIGTERM is the standard kill signal and is sent by KILL.LIT/K, and by the operating system when it is preparing to shut down. (It can also be sent with the UNIX kill utility, using the –TERM switch, as well as via MX_GETSIG.) SIGHUP is the signal sent when a process has been disconnected from its terminal device, such as due to a loss of network connection, or modem hangup. (It may also be sent manually with the UNIX kill utility, using the –HUP switch, or via MX_GETSIG.)

Windows does not support these signals per se, but A-Shell does emulate the SIGTERM signal (with KILL.LIT/K).

When A-Shell receives a SIGHUP or SIGTERM signal, it generates a BASIC error (#250 for SIGHUP and #251 for SIGTERM), allowing your program a chance to do some kind of graceful shutdown instead of just being obliterated. In the case of SIGTERM the error #251 is raised immediately, while in the case of SIGHUP, the error #250 may or may not be delayed, depending on which command line options were specified when A-Shell was launched.

The BASIC error won’t do your application much good if you don’t trap it. Programmers may often neglect error trapping, both because no one likes to think about errors, and because there is a general sense that the errors you plan for are never the ones that occur. Some may also rationalize that the default handling of errors (in which the BASIC runtime system reports the error message and line number, if applicable) is as good, or better, than the typical custom error trap code. These were never great excuses, and they are even less so in the modern environment where BASIC errors can be caused so easily by disconnects, both caused by careless user action (e.g. resetting the PC) as well as by network errors that are not anyone’s fault.

A simple error trap routine might look something like the following:

on error goto TRAP:

......

TRAP:

! special handlers for errors 250-255

on err(0)-249 goto &

TRAP'HANGUP, TRAP'KILL, TRAP'QZAP, TRAP'SOCKERR, &

TRAP'TIMEOUT, TRAP'WINCLOSE

TRAP'SOCKERR:

! <This occurs only during socket comm. Sessions using

! TCPxxx.SBR; it can be handled like most other BASIC

! errors, and thus we just fall through…>

<Existing error trapping, which may display messages,

prompt user to acknowledge, chain to menu, etc., none

of which makes much sense in a disconnect situation.

See ERRMSG.SBR and FILNAM.SBR which may be very handy

in error trap routines.>

TRAP'HANGUP:

TRAP'KILL:

TRAP'QZAP:

TRAP'TIMEOUT:

TRAP'WINCLOSE:

<close files, possibly log error, no input or display>

END ! terminate program

Errors 254 (timeout) and 255 (window close) are discussed in the next topic. Error 252 (queue zapped) occurs if your job table record is removed or corrupted. Although these are somewhat unrelated to the hangup and kill conditions, as a practical matter, the handling is probably the same.

In addition to this method of trapping and logging disconnects, which is highly recommended, but which requires some modification to your programs, you can also have A-Shell at least create a log of these kinds of events by adding TRACE=SIGHUP to theMIAME.INI file (see the TRACE system parameter.

A-Shell/UNIX supports several Command Line Switches (see for details) which modify the way hang-ups are processed: –h (ignore hangup signal), –hd (delayed hangup response), –hp (hangup parent), –hetcki (hangup error on tcki), and –hei (hangup error immediate).

Subtopics

Disconnects and Program Terminations

Trapping Timeouts and Closed Windows


Disconnects and Program Terminations

In some cases, having a process terminate due to an unexpected Telnet disconnect can be very inconvenient, and you would prefer that the process continue to run anyway. As of A-Shell/UNIX 4.7, this is now automatic, provided that the process does not require any keyboard input (which is not practical with a process that has lost its terminal connection.) When the hangup signal is detected, the A-Shell will convert the session into an independent background session and keep running. The process will continue running until it gets another error or until it stops to wait for keyboard input. At that point, it will get an error 250 (as described above), allowing the program to perform any desired cleanup/shutdown procedures. When the program then goes back into another keyboard wait (i.e. returns to a menu, or drops to the dot prompt, or prompts within the error trap for some kind of user response), then it will be terminated and forcefully shut down.

The –hetcki switch causes a TCKI (check for keyboard without waiting) operation to be treated like a regular keyboard request, which will then cause a disconnected session to be terminated. This is useful in programs like ASTAT, which might otherwise run forever after being disconnected. (ASTAT in fact internally sets this flag using MX_CLFLAGS while it is running, and then restores the flags that were originally set as it exits.)

The –hei switch is now needed to get the old hangup behavior, which was to immediately generate a BASIC error 250 and then wait for the program to shut down or to go into a keyboard wait. You might want to set this switch in a program that you specifically did not want to continue running if the session was terminated (possibly a large report that was intended to be output to the screen or workstation printer).


Trapping Timeouts and Closed Windows

Note that an inactivity timeout may occur in any version of A-Shell, while a closed window event only applies to A-Shell/Windows.

In addition to the external events described above, there are a number of internal events which can also interrupt an application. Most BASIC errors fall into this category, but there are two special conditions for which there is no AMOS equivalent and thus deserve further discussion here: inactivity timeout and a manually closed window.

Inactivity timeout is an optional feature of A-Shell that may be activated via the IATIMEOUT System Parameter. By default, it is disabled, but when enabled, a background timer is started that checks on the application periodically to see if it has been idle for the specified duration. If so, A-Shell generates an error #254. Note that although unlike the hangup signal (error #250) in the sense that the terminal connection is still live, as a practical matter, it probably indicates that the operator has left her station and thus there is little point in displaying a message and prompting for an acknowledgement (as you might do with most other errors). This is why it was handled like the hangup and kill errors in the sample error trap routine in the preceding section. (If you think that there is a possibility that the operator is there but just not paying attention to the screen, it might make sense to ring the terminal bell a few times and then use a timed keyboard operation to give her a last chance to resume before aborting.)

Possibilities for detecting timeout conditions abound. At the individual field level, INFLD.SBR and GET.SBR both support time-limited keyboard entry. At the session level, in addition to the IATIMEOUT A-Shell system parameter, many telnet clients support an idle timeout. (In this case, the client would shut down the session and A-Shell would treat it like a disconnect.)

The Closed Window event only applies to A-Shell/Windows when OPTIONS=XABORT is set in the system parameters. In this case, the user is allowed to abort a running application by clicking on the "X" in the upper right corner, or by hitting ALT-F4. Either action in this case will trigger BASIC error #255, which should be handled, for all practical purposes, just like the kill signal (error #251).


A-Shell for Apple Macintosh

Added October 2016

So why is there not a version of A-Shell for the Mac? Since A-Shell is written in C, and there's a C compiler for the Mac, can't it run? Here's the reply from the horse's mouth, as it were.

Yes, there is a C compiler for the Mac, and yes, A-Shell could be made to run on the Macintosh. The obstacles are:

• The flavor of C has a number of quirks that would probably require some time to figure out.

• The Mac environment, although based on Linux (now), has a number of peculiarities that would have to be worked through.

• We don't know anything about the Mac P2P environment, whether Mac workstations can coexist and share files on a Windows LAN, etc. Probably they can.

• The GUI environment is totally different. Since A-Shell's GUI is based on the WIN32 API, that isn't an easy nut to crack. And my guess is that since the Mac is mostly of interest as a workstation, users would likely want some GUI capabilities. Rewriting the GUI to use some higher-level, more portable framework (perhaps more HTML based) might have a lot of benefits, but is obviously a big job.

• In 25 years or so, this is about the fifth time we have been asked about the Mac. So while that may not be a good indicator, my guess is that the total sales would be a tiny sliver of the Windows sales. AMOS-type business applications don't seem to overlap very much with the Apple world, but perhaps that is self-limiting.

In summary, we could probably get a plain text (UNIX-like) A-Shell/ATE working in a hundred hours or so. Networking and coexistence with Windows PCs would probably double that. And GUI would be ten times that.


Security

In July 2008, some security problems with a Linux system required a trip to the customer's site. Following are some notes from that time.

I'm about to make an unscheduled trip to beautiful Omaha, all because a Linux system got compromised by Internet attack. Fortunately, the system is running well enough to keep the application going (A-Shell being nearly invincible!), but it's otherwise nearly crippled. Can't execute simple commands like ps, rpm, vi (vue works!), all the networking commands are broken, the backup program user interface is broken, etc. To compound matters, the problem started happening so long ago that it isn't even clear how far back we need to go (or just reload the OS). But I thought it might be nice to share a few warnings/thoughts/reminders about how to avoid this kind of situation:

• Don't expose TELNET to the Internet. Use SSH instead. Same goes for FTP; use SSH (SFTP) instead and block the TELNET and FTP services from the Internet. (You need to leave TELNET running for local connections in order to use SSH tunneling though.)

• Make sure that you don't have obvious login/passwords (like user/user, staff/staff, etc.) We're not actually sure if this is how they broke in, but we can see from the logs hundreds of attempts to log in with various typical usernames (user, staff, admin, john, fred, etc.) It should go without saying that the root password better be secure.

• Use a firewall, and configure it properly. In this case, they had a Cisco firewall, and it was supposed to be blocking outside incoming connections except for a few special IP addresses (like mine), but apparently a lightening strike caused it to lose its rules and revert to wide-open incoming access. If possible, require all the remote users to come from fixed IP addresses (which are easy to configure in even the simplest Internet routers).

• Employ some kind of log-checking mechanism. RHEL includes a thing called LogWatch, which can be used to display or output a semi-consolidated listing of all or selected log activity, but you still have to arrange to have it execute on a daily basis and for someone to review the logs. Better still would be to use software to dynamically look for exceptions, but there doesn't seem to be clear, obvious, and simple-to-configure choice that I can see. There are commercial utilities such as TripWire, and there are open source utilities such as swatch, but they all require a fair amount of time spent figuring out what you want them to look for and how to get them to do it. (In this case, merely reporting failed login attempts would probably have been sufficient to raise the red flag.)

• Use a "real" backup tool (I still like BackupEdge) that allows you to fully restore the root filesystem. This is probably what I will end up using. But even this is not helpful if you don't have a good rotation of backup tapes, including week-end or month-end tapes going back at least a couple of months. (In this case, we know the problem started more than a month ago, but aren't sure because that's how far back the logs go.)

• Tip: edit /etc/logrotate.conf to change the default rotate 4 to a higher value to increase the number of archived copies of the logs).

• Configure your disks so that the application is in a separate filesystem (e.g. /vm or /u). Not only does this isolate the application and the root from problems originating in the other, it also makes it a lot easier to do an emergency restore (or reload) of the root filesystem, without exposing the application to risk of unwanted over-writing.

• Install security patches. There was a time when Linux was considered reasonably immune from exploitable security flaws (and still is much much better than Windows, which requires updates on a near daily basis to remain secure), but if your server is exposed to the Internet, you need to think about updates. This is one of the advantages of going with a commercial distribution, like RHEL, which comes with a subscription for patches.

• Turn off any services you aren't using - such as httpd, etc.

This discussion was originally posted on the A-Shell bulletin board, and may have been updated more recently than the version here.


Accessing Serial Ports

Some AlphaBASIC applications access serial ports directly for output (e.g. OPEN #1, "TRM0:LASER1", OUTPUT), or even in some cases for input. The typical reason for this is to bypass the spooler to obtain better control over a particular printing operation. Another reason may be to communicate with some kind of non-terminal, non-printer device (such as a temperature sensor, mechanical counter, voice mail system, etc.) A-Shell does not emulate the "TRM" device, but it does allow you to open raw device files, provided you use the proper syntax and that the underlying operating system supports file I/O operations on ports. Since the details vary significantly between Windows and UNIX, each case is discussed separately.

Subtopics

Windows Serial I/O

UNIX Serial I/O


Windows Serial I/O

Under Windows, it is possible (but not recommended) to open a serial port for output by using the following syntax:

open #1, "COM1\", output

Note that you must replace the normal colon in COM1: with a backslash. Otherwise, A-Shell thinks COM1: is an AMOS-type logical disk.

Unfortunately, it is not possible to open serial ports as input files.

The recommended approaches to serial I/O under Windows are either to use AutoLog (see above), or COMIO.SBR.


UNIX Serial I/O

You can generally treat serial ports as sequential files under UNIX, opening them for either INPUT or OUTPUT (or both) as shown below:

open #1, "/dev/tty1a", output

open #2, "/dev/tty1a", input

Once open, you can use the normal PRINT or INPUT statements, although they may not work exactly as you might expect due to the large number and complexity of configurable parameters which affect serial port operations under UNIX. The typical method of setting these parameters (after opening the port) is to use HOSTEX.SBR to invoke the UNIX stty (or equivalent) command. (Refer to the UNIX "man" page or other documentation for further details on serial port settings, a subject which exceeds the scope of this discussion.)

Note that if you are going to use the xcall HOSTEX, "stty..." approach, you must do so after you open the port. Otherwise your changes may be lost when the port is opened.

To output to the port, you can use the PRINT command. Beware, however, that under the UNIX default buffering scheme, the characters may not be "flushed" to the device until a line terminator is output. To input, you can use INPUT or INPUT LINE, but here the subtleties of the port parameters can cause considerable confusion. For character-oriented, rather than line-oriented input, use GET.SBR.

You can turn off output buffering on UNIX or Linux devices by opening the device as an output file and then executing xcall MIAMEX,MX_NOBUF,87,CH where CH is the file channel. Similarly, you can use xcall MIAMEX,MX_FLUSHBUF,8,CH to immediately flush any buffered characters on that channel.

You can do character-level input from a serial port using GET.SBR:

xcall GET, buf, chan, bytes'req, bytes'rcv, timeout

For a more sophisticated approach for serial communications, contact Soft Machines (www.softmach.com) for information on their AutoLog communications package, which, among other wonderful features, includes a subroutine interface from A-Shell. Under Windows, there is also the COMIO.SBR which offers capabilities somewhere in the middle between simple file-oriented I/O and the full feature set of AutoLog.


Locking Users Out

You can lock users out of A-Shell by creating a file ashell.lok in the directory where the miame.ini is. You can create this file manually, or you can use LOKOUT.SBX. File details are as follows:

Line 1: <# of seconds to wait before exiting, or 0 for unlimited>

Lines 2-N: <Any text that you want to display>

An example will make this more clear:

0

A-Shell is currently locked for maintenance by the Big Kahuna

(starting at 5:30 PM and expected to last until 6 PM).

You can wait here, or hit ESC at any time to exit and try again later.

In the above example, the 0 on the first line indicates that A-Shell will wait indefinitely (until the user hits ESC, in which case it exits, or until the ashell.lok file is removed, in which case it proceeds as normal). If the 0 had been, say, 10, then the message would appear for 10 seconds but then A-Shell would exit.

While waiting, the process had not been assigned a job, but it is using the ashell (or ashw32.exe) executable, and has the jobtbl and qflock files open, so if your maintenance requires exclusive access to those files, you may want to set the wait to just a few seconds (just long enough to see the message) so that you'll get an opportunity at exclusive access (even if it takes a few tries). On the other hand, if the maintenance does not require exclusive access to those files, you may want to allow the users to just wait indefinitely in this mode until you signal that it is ok to proceed by removing the ashell.lok file.

Note that the message should indicate the ESC option (unless the wait time is set to just a few seconds), since it isn't otherwise obvious. (This scheme allows for the maximum in site/language customization.)

To force the existing users to exit, you may be able to use KILL.LIT or FORCE.LIT, and SEND.LIT (to send a message), although this will soon be simplified via an SBX. Or, you could modify your application to check for the existence of the ashell.lok file periodically and handle its own graceful shutdown.

This function was added to A-Shell in build 952 of 8 March 2006.


File Access Privileges

Historically, the typical AMOS approach to limiting access to sensitive application programs was to group them within a password-protected menu program. This works reasonably well in simple cases, but obviously breaks down as the complexity of the application or of its security needs increases. For example, if several people need access to the protected programs, then they all need to share a password. If one of those users leaves the company, then you probably need to change the password, which can be a pain if many other users are involved. The problem gets worse when you have groups with overlapping privileges. To accommodate this, you may need to implement several sets of passwords and allow one or more passwords to unlock particular programs. But again, if a user is transferred from say, payroll to general ledger, you would probably have to reissue new passwords to the payroll group.

The ultimate solution to these problems is to implement a custom security mechanism within the application that allows both programs and functions within programs (such as delete vs. add), to be restricted by user (or perhaps even category of user), which many applications have done. The problem with the latter solution is simply that it involves significant modifications to all of the programs in the application. And to some extent, it requires duplicating a lot of engineering which has already gone into the operating system, as well as requiring the maintenance of two sets of user logins and passwords (one for the operating system and one for the application).

For those seeking something in the middle, i.e. more flexibility than the former approach and less effort than the latter, A-Shell offers a capability which leverages the file access privilege mechanisms of the host operating system and requires minimal programming. The first step is to issue individualize logins and passwords to all users. Then, define groups which correspond to access privileges, such that a user’s ability to run a particular program can be controlled by whether the user is a member of a particular group. Finally, change the access privileges on all of the programs in the application so that each program is owned by the appropriate group, and that read access is denied except to members of that group.

Under UNIX, use the chown or chgrp utilities to change group ownership, and the chmod utility to set individual access bits on a file. (Note that directories must have the execute bit set! RUN and LIT programs need only read access. Data files need read and write access.) Under Windows, you can set the privileges by right-clicking on the file.

When A-Shell attempts to access a RUN or LIT program for which the current effective user does not have read privileges (i.e. which is owned or associated with a group to which the user is not a member), it will abort to the "dot prompt" with an "access denied" error. This fact alone provides the necessary security for the scheme just described to work, but aborting to the dot prompt with an error message is hardly a graceful way to deny unauthorized access. A better approach would be to automatically redirect the user to another program, perhaps the main menu of the application, or better yet, an error recovery program, which explained that the user was not authorized, and then chained to a central menu. MX_CHAINTO, set/get chain-to on priv error, allows you to define just such a program. Since this definition persists for the duration of the A-Shell session, it can be established in a startup program within touching any of the application’s existing programs.

To illustrate this, consider the case of an application that starts from a command file MAIN.CMD, which logs the user in and starts the main menu, MENU1.RUN. We’ll create a simple standalone program, called ACCERR, to implement the access trap, and insert it into the MAIN.CMD as follows:

;MAIN.CMD - Application startup

;Log to the application directory…

LOG APP:

;Set up a handler for access violations…

RUN APP:ACCERR INIT

;Start the application main menu

:R

RUN MENU1

The program, ACCERR, might look something like the sample below. Note that to combine its two modes into a single program, we allow the use of a single command line argument ("INIT", as shown in the command file above). When the argument is specified, the program just initializes the access trap using MX_CHAINTO and then exits. Otherwise, we assume we have been called because a user tried to run an unauthorized program, in which case we display a message before chaining to the main menu.

!ACCERR.BAS - Handler for unauthorized attempts to run programs

map1 CLINE,S,80

map1 X,F

!Pick up the command line (program name and argument).

xcall LSTLIN,CLINE ! (e.g. "APP:ACCERR INIT")

!If "INIT" arg specified, initialize access trap to point to

!this program (whose name is the first arg on command line)

X = instr(1,ucs(CLINE)," INIT")

if X > 0 then

xcall MIAMEX,MX_CHAINTO,1,CLINE[1,X-1]

END

endif

!Otherwise, we came here because the user tried to run a program

!which was unauthorized. Display a message and chain to the menu

print "Sorry, you do not have access to run that program."

input "Hit ENTER to return to the main menu: ",A

chain "MENU1"

By taking advantage of the operating system’s capabilities for assigning users to groups and relating file access rights to group membership, the simple scheme just described provides a sophisticated access controls within the application, without requiring changes to the application. For many applications, this will be sufficient, and may even eliminate the need to implement a login capability within the application. (You can retrieve the user’s operating system login via GETUSN.SBR.)

Note, however, that this scheme cannot, by itself, provide a way to limit access to functions within a program (such as to permit anyone to add a record but only certain people to delete.) However, it can simplify the implementation of such a capability. For example, rather than define a database of which users have access to which functions within the application, and a special data entry program to manage that database, you might instead simply create a series of dummy control files associated with function names (e.g. "add.sys", "delete.sys", etc.) and use the access system described above to set appropriate privileges for those files. The application could then determine if a user has access to a particular function by seeing if the user can open the corresponding control file. (This would require that you use an ON ERROR GOTO to trap the error that would occur when attempting to open a file to which you didn’t have access rights.)


Determining Your Platform

Reviewed January 2011

Despite all efforts at cross-platform compatibility, it is often desirable to determine which platform you are running on in order to take advantage of its peculiar features (or, less positively, to avoid performing a program operation that will blow up in your face.) Fortunately, this is relative easy, and there are several ways to do it. In the simplest (and most typical) case, you probably just want to know whether you are on a Windows platform or not. An easy way to do that is just to check what the directory separator character is. If it is "\", then you can assume Windows. Otherwise you can assume some form of UNIX or Linux. The call to get the directory separator is:

xcall MIAMEX, MX_DIRSEP|document=2zconref\3xcall.docx;bookmark=MX_DIRSEP, dirsep$ ! returns dirsep$ = "\" or "/"

Alternatively, you can get more details and specific information about both the currently running operating system version and the platform that the running copy of A-Shell was compiled for, by using:

xcall MIAMEX, MX_OSVER|document=2zconref\3xcall.docx;bookmark=MX_OSVER, osname {,osver, osrel, asplatform}

Also See

• ZTERM Escape Sequences for instructions on detemining if the terminal emulator is ZTERM, ATE or something else,

• AUI_ENVIRONMENT subroutine for another way of detemining the characteristics of the environment or platform (particularly as they relate to its GUI capabilities).


File Sizes

In older versions of A-Shell, random files were limited 2GB. This NOT the case now and the new limit is too large to worry about. Note, however, that sequential files, as well as old ISAM files, remain limited to 2GB.

Also BASORT remains limited to 2GB. (You can, however, use the third-party Optech sort routine, which is much faster anyway; contact us for details if you have large files to sort, or complex sorting requirements not handled by BASORT.)

Implemented at this time was a runtime option to allow random files to grow record by record, sort of like sequential files, or like ISAM-A files. The motivation for this was initially just to get around the 2GB limit on sequential files for ISMUTL dump/load operations, but it may be useful in a variety of situations. Notes:

• Enable the mode by setting bit GOP_EXTFIO (&h02) in the first bank of options and GOP2_AUTOX_RAN (&h01000000) in the second bank, using MX_GETOPTIONS and MX_SETOPTIONS:

xcall MIAMEX, MX_GETOPTIONS, options1, options2

OPTIONS1 = OPTIONS1 or GOP_EXTFIO

OPTIONS2 = OPTIONS2 or GOP2_AUTOX_RAN

xcall MIAMEX, MX_SETOPTIONS, options1, options2

• Once set, the mode is available to all random files. (You can also set EXTFIO using SET EXTFIO or OPTIONS=EXTFIO.)

• Since files grow record by record, you must use span'blocks mode to open the file, i.e.:

OPEN #1, FNAME$, RANDOM, RECSIZE, RECVAR, span'blocks

• To create the initial file, you can use CREATE.LIT or ALLOCATE (to create a 1 block file) or MAKE.LIT to create a 0 block file. Or you can open the file for sequential output, then close it (also creating a 0 block file).

• To write to the file, use the normal random file WRITE statements. If you attempt to write past the current end of the file, the file will be extended as needed (on a record by record basis).

• To read from the file, use the normal random file READ statements. If you attempt to read past the end of the file, you will get the normal illegal record error (#31).

• To determine exactly how many records are in the file, use XCALL SIZE, file, bytes and divide the size in bytes by the record size. (Using LOOKUP may be misleading since it returns the size as an integer number of blocks, although the actual size may not be an even multiple of 512 bytes.)

• Since fundamentally (from the OS point of view) there is no difference between our "random" and "sequential" files, there is nothing preventing you from later accessing the file as a sequential file. However, you cannot change from random to sequential access without closing and reopening the file.

• See the test program AUTOX.BP in [908,39] for an example.

Old File Size Limits

Prior to removing the 2GB limit, this is what the docs said about file sizes:

Most versions of A-Shell, being a 32 bit application, have a file size limit of 2 GB. But we do offer a special version of A-Shell/Linux which eliminates that limitation, provided the kernel also supports the LFS (Large File System) option. Contact MicroSabio for details.

To determine if your version of A-Shell/Linux supports large files, launch it with the –d switch. If Large File Support is available, a message to that affect will be displayed.


Opening Native Files

In most cases, wherever you could use a AMOS filespec in A-Shell Basic, you can also use native operating system file specifications, including long filenames (even those containing spaces) and UNC names (or Windows sharenames.) If the filespec contains a forward slash or backslash, A-Shell assumes that it is a native filespec and does not try to translate it. Examples:

open #1, "c:\Program Files\WIERD.STUFF\myfile.xyz", input

open #2, "\\SERVER01\VM$\abcde\wxyz.dat", output

open #3, "/tmp/this is a strange filename.x_y.z", input

You can also embed Environment Variables in filespecs, using the syntax %VARNAME% (where VARNAME is the environment variable name). For example:

Lookup "%TEMP%\junk.dat",X

Lookup "%HOME%/.profile",X

Most of the A-Shell LIT commands, and in particular those that support wildcards, can also use native filespecs, but there you must enclose them in quotes. For example:

.copy hosts.txt="/etc/hosts"

or:

xcall AMOS,"dir hash.lst=""/vm/miame/miame.ini""/h/k"

Note that environment variables are only translated in file specifications when the file is accessed. So it doesn't work in a PRINT statement, but would in an OPEN or ALLOCATE or KILL statement.


Transcending Filename Size Limit

A-Shell supports AMOS-style filenames up to ten characters long (plus a three character extension). But if that is not enough, since ASB automatically recognizes as native any filename containing a slash, you can easily transcend the ten-character limitation as long as you can establish the absolute or relative directory name. For example, a common requirement is to archive files by date (e.g. transaction batches, posting journals, report images, etc.) Coming up with a sensible naming scheme can be a challenge even using the expanded "10.3" format. But it becomes much easier when you eliminate the name length restrictions entirely. For example, you can retain the original filenames and just prepend a date, e.g. "20030408-journl.dat". If the file was known to be in the current directory, you could later reference it with:

Open #1, "./20030408-journl.dat", input ! (UNIX)

Open #1, ".\20030408-journl.dat", input ! (Windows)

Of course if you are planning on archiving a lot of files, putting them all in the current directory wouldn’t be wise. Instead, you could use MX_MKPATH to create arbitrarily named subdirectories (perhaps based on the file type and/or date) and then store the files in those subdirectories. Under Windows, you could take this one step further and use a Windows File Open dialog box (MX_GETOFD) to allow the user to select (and create) arbitrary directories, returning the directory names to the application, which would then remember and use them for storing and retrieving these archived files. A variation of this approach to the use of native directory names would be to make them subdirectories of a particular AMOS-style directory, which you could retrieve the native equivalent of using MX_FSPEC .

The main problems to watch out for when using native directory and file names have to do with the DIR command and case sensitivity. In the default display modes, DIR only displays the first six characters of a filename, and it folds them to upper case. (With the /L switch, or if SET LONGDIR is established, it displays the full ten characters, plus the extension, but still folds them to upper case.)This can be confusing and annoying if your directories have a mixture of upper and lower case files and/or long filenames. Fortunately, there is a DIR switch (/D) which forces it to display fully qualified native filespecs in their proper case, which pretty much eliminates the problem.

When referencing native filenames within your programs, the simplest approach is to stick with all lower case. This will work under Windows (where it doesn’t matter) and UNIX (where it does). If you use a mixture of upper and loser case, you can run into the extremely frustrating situation where DIR shows one (or more) copies of the file present, but OPEN (and other file access statements in BASIC) cannot find it.

Filename case can be altered during transfer between systems, so pay particular attention when transferring files to UNIX. Many file transfer programs have an option to fold filenames to lower case during the transfer, which would be wise to use. If you end up with upper case filenames on your UNIX system anyway, see Folding Filenames to Lower Case for information on converting them in place.

Note that files with names longer than 10.3 or containing more than one period are recognized as native. Prior to A-Shell build 5.1.1143 of March 2009, if there were no other clues, these were assumed to be AMOS specs, but that resulted in them being truncated at 10.3.


Creating a Native Directory

To create AMOS-style PPN directories, you can use SYSACT.LIT. To create an arbitrary native directory that doesn’t fall within the emulated AMOS format, you need to access native operating system functions. However, you can still do that without leaving A-Shell or your AlphaBASIC program.

Under UNIX, you could just use xcall HOSTEX, "<create directory command>" where the <create directory command> is a valid UNIX command for creating a directory in your flavor of UNIX (or Linux.) A typical example would be:

xcall HOSTEX, "mkdir /vm/miame/xyz0"

However, under Windows this will not work. The recommended approach then is to use MX_MKPATH, which works equally well under both Windows and UNIX/Linux.


Scanning Native Directories

You can scan a native directory to build a list of files in one of two ways. The first way would be to use HOSTEX.SBR to launch a native operating system utility to build such a list and output it to a file, and then open the file for input to read it in. This works better in UNIX than in Windows, which doesn’t have a standard way of generating a directory list in a file.

The second way is to use MX_FINDFIRST and MX_FINDNEXT to scan the directory. Start with MX_FINDFIRST to position your "directory cursor" at the start of a specified directory, and then use MX_FINDNEXT repeatedly until it returns a non-zero status, indicating it has hit the end of the directory.


PPN Numbering

Beginning with A-Shell build 897 of August 2004, PPNs are based on decimal rather than octal notation, and may range to [999,999] instead of the previous limit of [377,377]. The octal scheme was a holdover from days of yore, when bytes were precious and real programmers worked in binary. (The very idea that the disk would be divided into "projects" and "programmers" gives some idea of the amount of dust accumulated on this concept over the years.) As modern programmers have tried to make use of PPNs as a way of organizing real-world categories of things (location numbers, store IDs, client numbers, etc.) they have increasingly found the range of 1-377 octal both limiting and annoying. So when a certain A-Shell dealer dangled an 85 node license in front of us which needed decimal PPNs, we decided it was time to do something about it. Specifically, the new PPN system allows for decimal numbers ranging from 000-999, a nearly four-fold increase over the previous range (or 16-fold if you consider all the combinations of P and PN on a single device.) Not that we recommend subdividing a device into a million (or even a thousand) PPNs, but you can now do so if you so desire. (In fact, the LIT utilities continue to recognize only 512 unique PPNs per device.)

Initially, the theory was to make the octal/decimal choice an option, but it became apparent that it was so entrenched in the code that it seemed best to just do it and get it over with. For the most part, the changeover should be transparent. No changes are needed to existing disk directories or ini files. However, the conversion does have some ripple effect on LITs and possibly applications, the ramifications of which we dedicate ourselves to discussing here.

First, a large number of LIT utilities (essentially any that deal with PPNs) had to be updated, and regrettably, the updated versions are not backward compatible. To provide an easy escape valve, we packages the older versions (with .48A extensions) on the beta page as lit48a.zip, to be downloaded, unzipped, and renamed to .LIT if you decide to revert to an earlier version of A-Shell.

To make it easy to recognize the new LITs, they are all version 3.0 or higher.

(It should go without saying that this is one of those updates you'll want to perform cleanly, i.e. with no users running the old version.)

Second, and most important, is the question of what effect this will have on existing applications. The answer here is "hopefully none". That is to say, we've tried (and may even have succeeded) in making the new version backwards compatible with existing subroutines that retrieve or set PPN values. However, we cannot completely rule out the possibility that an application does some kind of internal manipulation of PPN information using octal conversion utility code. Before worrying about that, we'll first review the general approach we used to upgrading existing subroutines, and then list all that have changed. Based on that, you can probably quickly determine if you have anything to be concerned about.

General principles relating to PPN arguments in subroutines:

• Any PPN values represented in a pair of B,1 (or a single B,2) parameters have been kept backwards compatible. That is, they will work as before for the existing range of octal PPNs. They will not, however, accomodate new PPNs which require decimal digits or go beyond the previous limit of 377,377.

Note that these B,1 parameters were always a bit awkward, due to the fact that the binary representation only made sense if reformated as octal. If you used a PRINT statement to print out the B,1 parameters returned from a subroutine such as GETPPN, they would have appeared strange converted to decimal. (For example, [377,100] stored in a pair of B,1 variables and displayed using PRINT would come out as 255,64.)

• PPN values represented as strings (S,3 or more) are both backwards and upwards compatible. They will work as before and also accomodate PPNs such as [999,888].

• Any other storage format (for example, a pair of B,2 or F,6) will now use the straightforward decimal representation. (Fortunately, there is only one commonly used subroutine that used one of these formats for PPNs: XPPN.SBR.)

Here is the complete list of subroutines affected by this change (with comments) for your review. (Watch out for ALIASes though!)

Subroutine | Impact
DSKPPN | Returns PPN as a string, fully compatible up to 999,999.
GETJTB | Returns PPN info in both B,1 and S,3 formats. The B,1 values continue to be treated octally as before, whereas the S,3 values are unaffected. (Recommendation: use the S,3 versions and ignore the B,1 versions.)
GETJOB | Returns the PPN in a pair of B,1 values, which continue to be supported as before (i.e. octal).
GETPPN | Same as for GETJOB.
LOG | Supports various argument lists, but all PPN parameters are strings, so there it should be backwards and forwards compatible.
MX_GET ERSATZ (return ersatz info) and MX_GETDEV (return device info) | Both continue to support the B,1 versions of PROG and PROJ to preserve backwards compatibility. Any new programs using these routines should upgrade the PROG and PROJ values to B,2 which will cause them to come back in decimal (ready for printing without the need for octal conversion.) (If you decide to make this change, obviously you should do it thoroughly and systematically to avoid confusion and incompatibilities between programs.)
PLYJOB | Returns PPN info in S,3 format, so no problem here.
PPNSWP | Uses a pair of B,1 fields, so backward compatible.
SETJTB | Allows you to log to a new PPN by setting either the B,1 or S,3 fields. As before, it uses the S,3 fields if the B,1 fields are both 0, so that is the way you'll want to use it.
SETPPN | Companion to GETPPN. Uses B,1 parameters. Backwards compatible.
XPPN | Returns PPN info in B,2 format. Previously, you had the option (SBR=XPPNOCT) of getting the returned PPN values in decimal equivalent format so that they printed as you expected. The new version always works this way (i.e. SBR=XPPNOCT is effectively forced on and may be removed from the miame.ini). As such, it is perfectly backwards and forwards compatible.


Rounding of Floating Point Variables

Following are two discussions on the problems of rounding floating point variables. The first section was written when OPTIONS=FPROUND was added to the MIAME.INI file. The second accompanied the introduction of the subroutine MX_ROUND in A-Shell build 878 of April 2004.

Subtopics

FPROUND

MIAMEX MX_ROUND


FPROUND

When set, this option causes A-Shell to apply a rounding factor of .000005 (5 millionths) to the INT() and FIX() functions, and to the floating point comparison operators =, <>, <=, and >=. This fudge factor can be useful in programs that use floating point variables for dollars and cents computations without taking into proper account the fact that whenever floating point values are manipulated, they begin to accumulate tiny errors in precision. If the results of such expressions are not carefully rounded to the nearest penny, the errors can add up to the point that they become noticeable. This is particularly true with non-integers, which is why the SCALE option was invented in the original AlphaBASIC.

The problem of precision is inherent with all floating point numbers and affects A-Shell as well as AMOS. In fact, since A-Shell uses 64 bit floating point internally and converts back and forth to AlphaBASIC 48 bit format as needed, it may end up with slightly different results when you go way out to the right of the decimal point. In some cases, even though the result is more "precise" due to the higher number of bits used during computation, the greater rounding effect of 48 bit versus 64 bit representation may in some cases cause the A-Shell result to appear to be less precise than the AMOS equivalent. This difference may cause A-Shell to come up with different results than AMOS in programs that are not written to take the problems of floating point precision into account.

For example, the following test, which would appear to always be TRUE, may succeed under 48 bit floating point representation and fail under 64 bit, since the loss of precision is only apparent with the extra bits:

A = 777.77

IF (A*100) = INT(A*100) ? "EQUAL"

There are two ways for this statement to fail or to act differently with different levels of floating point precision. First, the actual result of A*100 may be 77776.99999999. Under the 11 digit significance of 48 bit floating point, this may be the same as 77777, but not under the 14+ digit significance of 64 bit representation. Thus INT(77776.99999999) would be 77776 rather than the expected 77777, making the test fail (by a lot.) Secondly, even if the error was on the high side (i.e. 77777.00000001) and thus didn't affect the INT() operation, the comparison would still fail in 64 bit arithmetic since 77777.00000001 <> 77777.

OPTIONS=FPROUND will eliminate both parts of the problem. First, by rounding the argument of the INT() function to the nearest integer if within .000005 of it, and second by considering two expressions equal if they are within .000005 of each other.

Note that since feature applies to <= and >= comparisons, you could have the apparently illogical result of A <= B and A > B both being true (if A was .000001 greater than B.) Any program that relied on this kind of precision probably wouldn't work reliably anyway, but it is worth noting.

Also note that the preferred way to deal with the problem of floating point representation of dollars and cents is to either use SCALE 2, or to store everything as integers, dividing by 100 only for display purposes, or if you prefer to store dollars and cents unscaled, then round your results explicitly as shown here:

A = <expression> using "#######.##"

At the very least, be wary of comparing two floating point expressions for equality, since the chance of perfect equality of two 64 bit floating point results is practically nil. Assigning the expressions to variables and then comparing the variables would at least reduce the precision to 48 bit and thus give you about the same results as you would have gotten on the Alpha.

To review, consider the following three cases:

X: if <expr1> = <expr2> (bad idea)

Y: A = <expr1> : B = <expr2>

if A = B (better)

Z: A = <expr1> using "#######.##"

B = <expr2> using "#######.##"

if A = B (best)

If you are using the form in case X: or possibly even Y:, then you may benefit from OPTIONS=FPROUND.


MIAMEX MX_ROUND

A new tool, clumsily called "The Floating Point Variable Rounding Factor", has been introduced in the ongoing battle between floating point imprecision and expected accounting precision.

The feature consists of the ability to declare a rounding factor for all floating point variables, that is applied whenever the variable is accessed. As an example, if your application stores all monetary figures in pennies (always dividing by 100 to convert to dollars and cents), and has no interest in fractions of pennies, then you could set the rounding factor to 1, which means that all floating point variables would be rounding to the nearest integer whenever they were accessed. On the other hand, if you store some of your amounts in dollars and cents, then you might want to set your rounding factor to .01, meaning that all variables would be rounded to the nearest .01 whenever accessed. The default factor is 0, which means that no rounding is applied (just as it has been up to now). You can set the factor to anything, not just numbers 1 or smaller. For example, a financial statement program for a Fortune 100 company might set it to 1000, which would round every variable to the nearest 1000. Or a point-of-sale program in a country whose monetary system is in transition might set it to the denomination of the smallest common current unit (perhaps 25). The important thing to remember is that the factor, once set, applies to every floating point variable accessed from memory, until it is reset to some other factor. It is not automatically reset at the end of each program. However, it does not apply to LIT programs.

The concept is somewhat similar to the OPTIONS=FPROUND, but obviously much more drastic. FPROUND operates on expressions rather than variables, generally adding or subtracting a "fudge factor" of .000005 or less, depending on the expression, in order to coerce numbers like 1.9999999997 or 2.00000000001 to "stick" to the nearest integer. (But as you can see from the number of patches to the way it works over the years, the technique is difficult to manage, and sometimes results in making the "problem" seem worse rather than better. The new variable rounding feature is much more blunt, but also more uniform and easy to understand, and thus might actually serve as a magic bullet for some applications which have not conquered the floating point precision problem through other means (such as manually rounding the results of calculations before storing them).

To query or set the rounding factor, use:

xcall MIAMEX, MX_ROUND, opcode, factor

where opcode is 0 to retrieve the current setting and 1 to update it. Factor is the rounding factor.

The following test program will be useful for testing and experimenting with the feature.

SIGNIFICANCE 11

map1 F1,F

map1 F2,F

map1 FPROUNDFACTOR,F

map1 A$,S,1

xcall MIAMEX, MX_ROUND, 0,FPROUNDFACTOR

? "FP Rounding factor is ";FPROUNDFACTOR

input "Change it? ",A$

if ucs(A$)="Y" then &

input "Enter new factor (0,1,.1,.01 etc): ",FPROUNDFACTOR :&

xcall MIAMEX,MX_ROUND,1,FPROUNDFACTOR

LOOP:

input "Enter a value: ",F1

? "Value = ";F1

F2 = F1 / 3

? "Value/3 = ";F2;" (";F1/3;")"

F2 = F1 * .01

? "Value*.01 = ";F2;" (";F1*.01;")"

goto LOOP

The program illustrates that the variable rounding factor only affects the variables F1 and F2, but does not show up when an expression is printed directly (such as F1/3).

At the risk of running this topic into the ground, it is worth saying a few words about why the problem exists, why it seems worse (to some people) under A-Shell than under AMOS, and why it sometimes surfaces in programs that were "working" for many years. First, the problem is inherent when floating point values are represented in the computer with a finite number of bits. Even a simple calculation like 7/2 might result in 3.499999999998 rather than the 3.5 you were expecting. In this example, with the 48 bit floating point format used by the Alpha, the effective number of significant digits is about 11, and thus 3.499999999998 would be internally rounded to 3.5 and you wouldn't notice the problem. But with the 64 bit IEEE format used by virtually every other machine outside of the Alpha, you get about 16 significant decimal digits and thus 3.499999999998 would remain as is. As long as you printed it with a mask, e.g. "######.##", it would always appear as "3.50" but if you didn't round it before storing it, subsequent use of the variable would carry the imprecision into other calculations. For example, if you added up several hundred thousand of these kinds of values, each with a slight rounding error, the cumulative error could easily grow to the point that it made a difference in the pennies column.

The reason why the problem seems worse under A-Shell is simply due to the seemingly paradoxical fact that the more bits of precision, you have in the internal floating point calculations, the more likely your result will be off by a significant digit. For example, if the floating point format could only represent about 2 decimal digits, then the result of every calculation would effectively be rounded to the nearest hundredth. (Which is effectively the "capability" that the new variable rounding factor feature provides.)

The reason why the problem sometimes suddenly appears in programs that have been working for years, is that as businesses grow and computers get faster, there is a tendency to deal with greater amounts of data and for the computations to increase in complexity. For example, in 1980, a company might have had a payroll of 100 and only a couple of simple deduction types. Now, through mergers and other growth, in both the economy and the tax code, it might have 1000 employees and several more deductions. As the number of calculations increases, the internal rounding errors can accumulate to the point that one day, a paycheck is off by a penny. And suddenly there is a panic. Or, in a more insidious variation of this problem, results from calculations may be stored in files without the rounding errors being first corrected. (For example, a product history file might contain a record of the dollar amount of each sale of that product. Assuming the dollar sale amount was the result of a calculation (qty times price, perhaps with a discount), it might well contain a slight rounding error. As in the example above with 7/2 = 3.499999999998, it may take a long time before this your history file grows big enough for the error to become visible. And since the errors will, on average, split evenly on both the low and high sides, they might tend to cancel themselves out, on average. But one day, you select the right combination of dates or other reporting factors and voila, the report is off by a penny.

(One way that careful programmers have dealt with this problem is to always use a rounding mask before storing a result, for example, RESULT = <calculation> USING "#########.##". But if you haven't done that all along, you might find it a bit daunting to start now.)

Going back and fixing a problem like the one just described may not be easy, especially if the application now contains thousands of programs. For this kind of situation, the variable rounding factor might provide a near miracle solution. Even if you couldn't be sure whether you might have some variables that are supposed to contain tenths, or hundredths, or thousandths, you can still benefit by setting the rounding factor to, say, .00001 or even .000000001. Since the rounding errors tend to start out in the vicinity of .00000000000001, this would be more than enough to eliminate them as they occur.

The main thing to watch out for is situations where you really do want to have a precise representation of factions like 1/3. For example, if you wanted to apply a discount of 1/3 to some vary large number, then you probably wouldn't want your 1/3 to be rounded to .33333 (instead of .33333333333). After all, 1/3 of a million is 333,333.33 but if your representation of 1/3 was merely .33333, then the result would be 333,330.00. Note, however, that the rounding factor is only applied to variables, so it would not stop you from getting a precise result for 1000000/3; it would only cause a problem if you set F=1/3 and then multiplied 1000000 by F.

The final word then, is that if you fear that you have this problem and want to try the new variable rounding factor, start small (perhaps .000000001) and work up if that isn't sufficient. But it goes without saying that this kind of technique should not be applied without some diligent analysis and testing of your application.


Pop-Up Utilities

The A-Shell implementation of INFLD supports a built-in hot-key mechanism allowing you to "pop up" utility programs (also known as Desk Accessories) of your own design. When enabled, the designated hot key will launch a child session (or window) of A-Shell which runs ASHPOP.RUN, a simple-minded menu program intended to be modified by you to contain items of interest to you. The source is provided, in [7,376], exactly for this purpose. We also provide a ready-to-use pop-up calculator in a program called ASHCAL. You can use these as is or as templates to put a lot of extra capability at the fingertips of your users.


Screen Capture

INFLD supports the keyboard command (Control-P) to capture a picture (or "snapshot") of the screen; see Screen Pictures. To use this capability under program control, use MX_SCRNPIC.

Having INFLD Generate Automatic Snapshots

If you specify the TYPE code |S (vertical bar, capital S) in an INFLD call, it will automatically generate a screenshot (appending it to the current BUF file) on exit from the field. By adding SBR=INFDEF:|S to the MIAME.INI, you can arrange to create a "slide show" of an entire session. This can be helpful for creating documentation, or for monitoring background processes, or for "snooping" on users (or simply for filling up the disk and creating useless system overhead.)


Setting the Window Title

In addition to the AG_MINTITLE (Set Minimized Window Title) and WINTITLE (Set Normal Window Title) commands, which work only under Windows, you can use the SET TITLE command under any A-Shell platform to define variable text which dynamically updates the title bar when any of the control variables specified in the title definition change. Under non-Windows platforms, it requires ZTERM or ATE in order to actually write to the title bar of the terminal emulator. See SET.LIT for details.


A-Shell Screen Elements

Shown below are the various screen elements that are or can be used in A-Shell. Click on the numbered items for details.

Status Line - sessionToolbar - topStatus Line - topStandard Menu BarWindow Title BarMargin - TopToolbar - bottomMain Display AreaToolbar - rightStandard ButtonsMargin - LeftStatus Line - bottomToolbar - left

Note: As of A-Shell 1359.0, the bottom toolbar (6) is now above the status (9) and session (10) lines.


HOWTO: RTF Printing

How do I print RTF files (a) in general, and (b) so that they the interpret RTF commands instead of printing them?

There are three ways to print files containing RTF commands:

1. Create a print filter that uses MX_SHELLEX or HOSTEX to force it to be printed by some RTF-aware application (like Wordpad). This of course only works if the entire printfile is RTF, and will not work if you want to include this RTF text in a larger report which contains plain text.

2. Use the internal XTEXT print function. This is similar to option one, but needs to be invoked by the user while looking at the text.

3. Use the //XTEXT GDI printing command. This is the only option that would allow you to combine XTEXT/RTF within a larger printfile, but it does require that the the entire printout file be printed through the GDI printing mechanism. This would rule out direct printing from Linux to the printer; you'd have to instead use the AUXLOC: device to route the printing through ATE. And also would eliminate the use of escape sequences to set printer functions. So it may require some other modifications to your printing logic. But fortunately, GDI reports accept plain text, so it isn't necessary to convert the entire thing to RTF.

You may also want or need to use MX_GDICALC to calculate the space needed for a particular XTEXT chunk, so that you can decide whether to start a new page first. See the EXLIB program MMOGDI for an example of that.

As of A-Shell 5.0, //XTEXT printing only works in portrait mode. This will be changed in 5.1.


Introduction to Subroutines

AlphaBASIC programs rely heavily on the use of subroutines to perform functions from the simple STRIP (strip trailing spaces from a string) to the more complex BASORT (sort sequential and random data files). Subroutines under AMOS have the extension SBR, and traditionally live in DSK0:[7,6] (BAS:). When a program calls a subroutine, AlphaBASIC locates the SBR file, loads it if necessary, and then calls to the start of it.

Subroutine handling under A-Shell is functionally identical: your program invokes a routine, and A-Shell calls to its start. Because of the structural differences between AMOS/AlphaBASIC and A-Shell, however, A-Shell subroutines do not (normally) exist as separate SBR files; they are, instead, linked into the A-Shell object module and are therefore always available.

A-Shell comes with several hundred subroutines, including nearly all of the so-called Alpha Accounting routines from [7,60] and the so-called "standard AlphaBASIC subroutines" from [7,6]. It also includes the most popular MicroSabio subroutines for AMOS, (INFLD, INMEMO, EZSPL, MSBOXX), plus a variety of routines that have been written specifically for A-Shell. In addition, A-Shell includes many third-party subroutines that have been converted over the years as more firms and developers have migrated to A-Shell and we have converted their AMOS routines.

This document lists the most commonly used routines, and provides detailed documentation for most of them. Those not listed were skipped because they are too obscure or are specific to individual users. Recently-added routines, which come around fairly often, are usually documented even if they are obscure and/or for specific users.

If there is a function that you need and do not see, be sure to inquire about it before writing your own.

Subtopics

Calling External Routines

Subroutines by Name

Subroutines by Type

Limits and Capacities

Creating Subroutines

Configurable Subroutines


Calling External Routines

An interesting feature in AlphaBASIC is the XCALL statement which provides the capability to call routines that are external to the current program. The feature was included in the original AlphaBASIC to allow calling of subroutines written in assembler, which could perform low-level or CPU-intensive actions that were not otherwise possible in BASIC. In the A-Shell environment, no one writes code in assembler any more, but the feature is widely used for:

• Calling one of the hundreds of subroutines written in C by MicroSabio which are embedded in the A-Shell run-time environment. Many of these are rewritten versions of assembler SBR routines which were popular in the AMOS environment, such as BASORT, INFLD, SPOOL, etc.

• Calling subroutines written in ASB by independent developers, which are compiled into .SBX modules that are loaded from disk on demand and subsequently cached in memory.

A-Shell supports the following syntax variations of the XCALL statement:

XCALL name {,arg1, arg2, ... argN}

XCALL name (arg1, arg2, ... argN)

VXCALL strname$ {,arg1, arg2, ... argN}

The first variation, with the parameter list separated from the subroutine name by a comma, is the original syntax supported all the way back to AlphaBASIC 1.3. The second variation, with the parameter list enclosed in parentheses, is an A-Shell extension; see History, below. The third variation, VXCALL, is another A-Shell extension that differs from XCALL in that the subroutine name is a string variable interpreted at run-time, rather than a literal interpreted at compile-time; see Calling Variably-Named Routines for more information.

Parameters

name

The literal name of the subroutine, made up of one to ten characters alphabetic and numeric characters. The first character must be alphabetic, case insensitive. Must match the name of a subroutine embedded within A-Shell, or the name of an external subroutine with an SBX extension. Traditionally, subroutine names were limited to six characters and were compiled into 4 rad50-encoded bytes in the RUN file. A-Shell 5.1.1186 extended the limit to ten characters. The standard search path for SBX modules is: current [p,pn], then [p,0], then dsk0:[7,6]. An alternate search path variation can be enabled with the SBX_RUNDIR flag (current [p,pn], .RUN location, then dsk0:[7,6].) Once the SBX is located on disk, its modification timestamp is compared to the previously-cached version in memory (if present), and the file is loaded from disk if necessary. Otherwise, the cached version is reused, reducing the calling overhead for subsequent calls dramatically.

strname$

A string literal or variable, one to ten alphabetic and numeric characters, case insensitive, containing the name of the subroutine, resolved at runtime.

arg1, arg2, ... argN

From 0 to 125 expressions passed as arguments to the subroutine. Any arguments passed in the form of variables may potentially be updated by the routine, although it is impossible to know which ones just from looking at the XCALL statement syntax.

See Also

• Introduction to Subroutines

• SBX Subroutines

• Call SBX as a Function

History

2014 October, A-Shell 6.1.1392, compiler edit 718: You may now optionally use procedure-style syntax with the XCALL statement. In other words, instead of: XCALL NAME,ARG1,...ARGN, you can instead use XCALL NAME(ARG1,...ARGN). The advantage of the alternate syntax is perhaps mainly aesthetic, but will seem more natural to programmers coming from other language backgrounds. Another potential advantage is that it would allow APN call tips to be set up for common XCALLs, since the feature is triggered by typing the "(" which normally signals the start of a procedure parameter list.


Subroutines by Name

The following table alphabetically lists A-Shell’s most generally useful routines. Most of these routines are embedded in A-Shell, but some are written in BASIC and are provided as separate files. In the "Origin" column abbreviations are used for Alpha Accounting ("AA"), Alpha Accounting UK ("AA UK") and MicroSabio ("MS"). Most of these routines, including all of the commonly-used ones, are described in significant detail in the body of this documentation. See also Subroutines by Type. Remember to add new routines to the "ByType" list.

Routine | Origin | Function
ABOX | Unknown | Draw a box
ACCEPN | AlphaBASIC | Input single character (F,6 or S,1) with no echo
ACCEPT | AlphaBASIC | Input single character with echo
ACCESS | Misc | Display one-line menu, accept one-character input
AMBTOA | AM Belgium | Miscellaneous functions including timed input.
AMOS | MS | Execute AMOS command
ANYCN | AA / MS | Input "Any change?" number
ASCEBC | Unknown | ASCII-EBCDIC conversion
ASFLAG | MS | Set A-Shell runtime flags: read-only, sync-write, etc.
ASQL | MS | See SQL.
ATEAPX | MS | Transfers a file from application server to ATE client PC.
ATEGFK | MS | Retrieves a file from the PC via the ATE terminal connection.
ATSYNC | MS | Synchronize directories between server and PC. See ATSYNC.LIT .
ATHTTP | MS | A variant of HTTP.SBR, which see for details.
AUI | MS | A-Shell's GUI interface and toolkit.
AUTLOG | Soft Machines | Interface to AutoLog
B64ENC | A-Shell | Base 64 encoding (for email attachments)
BASORT | AlphaBASIC | Sort sequential and random data files
BITOPS | HMOpro | Bit field operations
BLOCKS | AA UK | Return number of free disk blocks
BOX1C | Debug plc | Various box drawing functions
BUTTED | Unknown | xcall butted, string removes all but 0-9 and A-Z
CCOFF | AA UK | Disable Ctrl+C interrupts
CCON | AA UK | Enable Ctrl+C interrupts
CGIUTL | A-Shell | CGI programming utilities
CHKKBD | Misc | Check keyboard; optionally input char if available: xcall chkkbd, flag (B,1), {char (S,1)}
CHKONE | Unknown | Check keyboard to see if character is available
CHKSPL | Unknown | Checks if spooler exists; must use ALIAS =CHKSPL:PRTCHK; similar to PRTCHK
CMDR | Debug plc | Put command file in :R mode
CISAM | MS | Interface to CISAM file system
COMIO | MS | Serial port I/O under Windows
COMMON | AlphaBASIC | Inter-program communication; configurable
CONDEV | A-Shell | Get IP address, console device or machine name
CRC16 | ERS | Calculate 16 bit CRC on block of data
CREMLX | ADGAP | Build multi-level index used by SEARCH
CRYPTO | MS | Provides a collection of cryptographic-related functions
DATES | Unknown | Many date conversions, Julian, etc.
DELCHR | A-Shell | xcall DELCHR, chrlst, string removes all the characters that are specified in the string variable chrlst from the string variable string. See the BASIC Plus function EDIT$ for related functionality.
DERR | A-Shell | See ERRMSG
DEVCHK | AA UK | xcall DEVCHK, dev, status checks whether an AMOS logical device is defined to A-Shell. The dev parameter should contain the name of the device (e.g. DSK0); on return the status parameter (F,6) will be set to 1 if the device exists or 0 if it does not.
DIGEST | A-Shell | Returns various cryptographic digests of strings or files.
DSKPPN | Unknown | Return disk and ppn
DSKCOM | A-Shell | Disk-based equivalent of COMMON
DSPLY | AA | Display variables with various formats
DSTOI | A-Shell | Convert separated date to Julian
DYNLIB | A-Shell | Loads, unloads, calls routines in external function libraries
EBCASC | Unknown | ASCII-EBCDIC conversion
ECHO | AlphaBASIC | Enter line mode. Turn on terminal echo
EFS | ERS | Encrypted file service
EMAILP | MS | Email a report
EMAILX | MS | Send email.
ERRMSG | MS | Error trap reporting routine; must alias to DERR
EVTWIN | MS | Event tracing; see Event Tracing
EZSPL | MS | Send file to printer with enhanced options
EZTYP | MS | Display file with paging, 80/132 switching
EXTRAI | Celibec |
F2HOST | A-Shell | Convert F,6 to IEEE format
FIFO | MS | Named pipe communications under UNIX
FILL | Unknown | Variation of AlphaBASIC Plus FILL$() function: xcall fill, var, pattern {,length}
FILNAM | Unknown | Returns file name for the specified channel
FILOCK | AA UK | Front-end to FLOCK.SBR
FINB | Debug plc | Input 1 byte from file: xcall finb, chan, byte, status
FLOCK | AlphaBASIC | File/record locking control
FORCE | A-Shell | Force characters into another job’s input
FTPDLX | A-Shell | FTP file transfer, standard version.
FTP2 | A-Shell | FTP file transfer, modified version.
FUNKEY | MS | Display function key line message
GDIPRT | MS | Send report to AshLite client for printing
GET | AlphaSoft | Get single character from keyboard or file
GETADR | MS | Return address and size of variable
GETBYT | Unknown | Read raw bytes from a sequential file
GETDEV | AA UK | Get current device
GETDSK | AA UK | Get current device
GETJOB | AA UK | Get job name, program, ppn, job number
GETJTB | Debug plc | Get job table information
GETLOG | Unknown | Get jobname, number, and ppn; must use ALIAS =GETLOG:GETJOB)
GETMAC | MS | Get MAC (hardware) address of Ethernet controller
GETPPN | AA UK | Get current PPN
GETPRG | MS | Get current program or SBX name
GETTRM | MS | Get current terminal name: xcall gettrm, trmdef$
GETUSN | Custom | Get user login name
GETVER | MS | Get current program version
GETX | A-Shell | Get single character with function key translation
GRECNV | SSCI | Various Julian date manipulations
GTJBNO | A-Shell | xcall gtjbno, jobnam, jobno returns job number for specified job name (0 for error)
GTLANG | AlphaBASIC | Return current language information
HASH | A-Shell | Generate a hash code from a string of characters.
HOST2F | A-Shell | Convert IEEE 4 or 8 byte float to BASIC 6 byte
HOSTEX | A-Shell | Execute host operating system cmd as a subroutine
HTMLP | MS | View report in browser
HTTP | MS | Handle various kinds of HTTP requests
IDTIM | AlphaBASIC | Input date
IMAGE | A-Shell | Display images of common image file types.
INCOM | MS | Variation of COMMON
INFLD | MS | Extended Alpha Accounting input routine.
INIX | Steve Evans | Read and write to INI files.
INMEMO | MS | Memo/Jotter editing/handling routine
INPUT | UK | Identical to INFLD.
INPUTC | AA UK | Input variation used in the UK
INVUE | Foxware | Requires ALIAS=INVUE:INFLD
ISMBLD | MS | Create ISAM 1.0 file.
ISMROK | DMSI | Return information from ISAM 1.0 "rock"
ITC | MegaSoft | Send message to another process (UNIX only)
JOBCMD | MS | Set command to be executed whenever at "AMOS" command level (dot prompt)
JOBDAT | inSight | Get information about your job
JOBNAM | Unknown | Equivalent to GETJOB
JOBNUM | AA UK | Return unique job number
JOBTRM | Unknown | Return jobnam, trmdef, tdvnam
JULCVT | Unknown | Julian date conversions
KDAY | AA UK | Calculate elapsed days to given date (b,2)
LAPSED | AA UK | Calculate elapsed days to given date (F,6)
LOKOUT | MS | Lock users out of A-Shell
LOG | MS | Log to a new PPN or retrieve PPN info.
LOGRIO | MS | Logical record i/o (any size records)
LSTLIN | A-Shell | Return last command line
MATCH | HMOpro | Compares a data field to a list of values or ranges
MESAG | AA | Display message on bottom line of screen
MIAMEX | A-Shell | Large library of A-Shell interface functions
MMENU | AA | Display file maintenance menu
MOUNT | AA | Display device mount message
MPSCOM | Custom | Interface to MacDonald PartSelect catalog
MSBOXX | MS | Box and window utility
MSGBOX | MS | Displays a message in a dialog box format
MSGLOG | AlphaBASIC | Output coded message to SYSLOG.SYS
NFIND | AA UK | Perform string search forwards or backwards
NOECHO | AlphaBASIC | Enter image mode. Turn off terminal echo
NOEKO | MS | Same as NOECHO
NUMCHK | MS | Checks a string for numeric only characters
ODTIM | AlphaBASIC | Output formatted time and date
PACK | A-Shell | Pack three character string to B,2 RAD50: xcall pack, str, rad
PCKLST | HMOpro | Display a pop-up pick list.
PGMID | MS | Display screen header with program name, time, etc
PGMND | AA | Display end of program message
PLYJOB | MS | Return detailed job info about current or other job
PPNSWP | Unknown | Log to a new device:[p,pn]. Must use ALIAS= PPNSWP:SETPPN
PRINT | AA | Build formatted print file.
PRIV | AA | Dummy routine (not necessary to log to 1,2 here)
PRTCHK | AA UK | Check printer name and printer queue
PUTBYT | Unknown | Write raw bytes to a sequential file
RDATE | AA | Get system date
REGEX | MS | Regular expression processor.
RENAM | MS | Same as RENAME
RENAME | AlphaBASIC | Rename a file
ROUND | Custom | Round argument to nearest integer
RVCOMN | Custom | Like COMMON.SBR with one 1024 byte packet
RXPCHK | MS | Checks a string for unprintable characters
RXTERM | MS | Check input buffer for function key (Windows only)
SBRC | UK | Misc functions used by the R/W and P/G packages
SBXINP | Firmaware | INFLD wrapper that simplifies some INFLD operations.
SCGINP | Unknown | Variation of INPUT.SBR
SCRN | Willowtree | Willowtree Screen Handler
SCRSTS | MS | Scrolling status window handler
SEARCH | ADGAP | Enhanced (disk optimized) variation of SERCH
SEND | A-Shell | Send a message to another terminal
SERCH | AA | Search random data file
SETDEV | AA UK | Change current device: xcall setdev, « dsk2 »
SETJTB | Debug plc | Set job table information
SETPPN | AA UK | Change current PPN: xcall setppn,b2
SIZE | A-Shell | Returns size of specified file in bytes
SLEEP | AlphaBASIC | Stall processing for number of seconds
SORTIT | MegaSoft | Sort array in memory
SPOOL | AlphaBASIC | Send file to printer. See EZSPL.
SQL | MS | Provides access to SQL databases.
SRCH2 | AA | Search random data file
STALL | AA | Stall processing for number of seconds
STENO | AA | Input starting/ending numbers
STIME | Dalcon | Return current time in formatted string
STRIP | AlphaBASIC | Strip trailing spaces from string
STRTOK | MS | Parse strings
SUBMIT | Custom | Launch a background task (UNIX only)
SWPSBR | Swap | Various Swap-related functions
SYS000 | Misc | Like COMMON (one packet, passive read): xcall sys000, sr (b,1), packet (x,100)
TBOX | Misc | Draw box around specified SR,SC,ER,EC
TCKI | MS | Check to see if an input char is available without inputting it; xcall tcki, flag; flag (Num) returns 0 if no char is available, 1 if one or more chars are available.
TCPCLI | MS | Socket communications (client interface)
TCPSRV | MS | Socket communications (server interface)
TCPX | MS | Socket communications
TIMES | MS | Returns high-precision time information
TINKEY | AlphaSoft | Check for terminal input
TMEN2 | AA | Display reduced transaction menu
TMENU | AA | Display transaction menu
TRIM | Debug plc | Strip trailing and leading spaces from string
TRMCHR | AlphaBASIC | Return terminal characteristics
UNIQUE | Unknown | Generate unique temp filename
UNPACK | AA UK | Unpack RAD50 word, e.g. xcall unpack,b2,s3
USPSBS | MS | Creates an encoded bar string for the US Post Office intelligent bar codes.
USRCNT | MS | Get current user count and number of nodes licensed
USRTBL | Custom | xcall usrtbl, name, code, opcode
VUESCR | Swap | Edit a rectangular array of text
WAIT | AA | Output "Please wait...." message
WAKNO | MS | Wake up a sleeping job (UNIX only)
WHOAMI | AA UK | Get job name
WINFLG | inSight | Get inSight information about your job.
XDEFLT | MS | Insert text into the type-ahead buffer
XFOLD | HMOpro | Intelligent folding of names
XFRMMO | MS | Move or copy an INMEMO logical memo
XLOCK | AlphaBASIC | Shared resource control
XLSUTL | MS | Used internall by APEX, not suitable or intended for use in programs. (Do not use!)
XCALEN | MS | Enhanced calendar control.
XMOUNT | AlphaBASIC | Mount a device. Dummy routine.
XPAINT | MS | Execute an AlphaPAINT 2.0 screen display
XPPN | Unknown | Get ppn, device, job, term
XSHLEX | MS | Platform-independent "Shell Execute"
XSTRIP | MS | Perform various string manipulations
XTEXT | MS | Windows text control.
XTREE | MS | Windows tree control.


Subroutines by Type

The MIAMEX routines (MX_xxx) are shown with a shaded background.

Disk and File Operations

ATEAPX.SBX | ATEGFK | ATSYNC | BASORT | BLOCKS
CGIUTL | CISAM |  |  |
CREMLX | EFS | ERRMSG | EZSPL | EZTYP
FIFO | FILNAM | FILOCK | FINB | FTPDLX
FTP2 | FLOCK | GET | GETBYT | IMAGE
INIX | ISMBLD | ISMROK |  |
LOGRIO | MSGLOG | PCKLST | PRINT |
PUTBYT | RENAME | RENAM | SEARCH | SERCH
SIZE | SRCH2 | UNIQUE | XLSUTL | XFRMMO
MX_ASHLOG | MX_ATEFILEXFR |  |  |
MX_CHKPPN | MX_COPYFILE | MX_EXPFIL | MX_GETSHELLPATH | MX_FILECHINFO
MX_FILEPOS | MX_FILESTATS | MX_FINDEND | MX_FINDFIRST | MX_FINDNEXT
MX_FILEHOOK | MX_FLINES | MX_FLSET | MX_FLUSHBUF | MX_FSPEC
MX_FTFORMAT | MX_GETDEV | MX_GETERSATZ | MX_GETHASH | MX_GETOFD
MX_HASHFILE | MX_HTMLHELP | MX_LITMSG | MX_MKDIR | MX_MKPATH
MX_NOBUF | MX_PRFSPEC | MX_RMPATH | MX_SETEXT | MX_SETHASH
MX_USRDEL | MX_USRLOD | MX_USRIO | MX_USRSAV | MX_WEBCACHE

Job Environment

AMOS | CCOFF | CCON | CMDR | CONDEV
DSKPPN | ECHO | ERRMSG | FILNAM | FORCE
GETDEV | GETDSK | GETJOB | GETJTB | GETLOG
GETPPN | GETPRG | GETTRM | GETUSN | GETVER
GTJBNO | GTLANG | JOBCMD | JOBDAT | JOBNAM
JOBNUM | JOBTRM | KILJOB | LOKOUT | LOG
LSTLIN | PLYJOB | PPNSWP | PRIV |
SETDEV | SETJTB | SETPPN | TRMCHR | WHOAMI
WINFLG | XPPN |  |  |
MX_CALLSTACK | MX_CHAINTO | MX_CLIPBOARD | MX_CLRSIG | MX_CMDKBD
MX_CMD_STATUS | MX_CSVDELIM | MX_DEBUG | MX_GETCMDINP | MX_GETCTRLC
MX_GETECHO | MX_GETGDO | MX_GETHEX | MX_GETLOKSER | MX_GETPID
MX_GETPROMPT | MX_GETSIG | MX_GETTRACE | MX_GETENV |
MX_GETUMSK | MX_HOTKEY | MX_INSTNUM | MX_LASTLNO | MX_MEMORY
MX_NXTCMD | MX_SETERR | MX_SETUMSK | MX_SETCMDINP | MX_SETGDO
MX_SETHEX | MX_SETMEMFLAGS | MX_SETPROMPT | MX_SETUSRNAM | MX_SETTRACE
MX_SETLOKSER | MX_SYNC_CWD | MX_USRDEL | MX_USRLOD | MX_USRMAP
MX_USRIO | MX_USRSAV |  |  |

Message Handling

DERR

MX_ASHLOG

MX_ERRNOMSG

MX_LITMSG

MX_PRINTERR

Data Manipulations

ASCEBC | B64ENC | BASORT | BITOPS | BUTTED
COMMON | CRC16 | CRYPTO | DIGEST | DYNLIB
EBCASC |  |  |  |
F2HOST | FILL | FILNAM | HASH | HOST2F
MATCH | NFIND | NUMCHK | PACK | REGEX
ROUND | RXPCHK | SORTIT | SQL | STRIP
STRTOK | SYS000 | TRIM | UNPACK | XFOLD
XSTRIP | MX_FTFORMAT | MX_OCVT | MX_PWCRYPT | MX_ROUND
MX_STRCMP | MX_USRIO |  |  |

Display / Screen

ABOX | BOX1C | DSPLY | ERRMSG | EVTWIN
EZTYP | FUNKEY | IMAGE | MESAG | MMENU
MOUNT | MSBOXX | MSGBOX | PGMID | PGMND
SCRN | SCRSTS | STENO | SWPSBR | TBOX
INMEMO | TMEN2 | TMENU | VUESCR | WAIT
MX_DEFTABXYZ | MX_GETRC | MX_INICLR | MX_SCRNPIC | MX_SINK
MX_TITLE | MX_WSET_STATUS |  |  |

Keyboard Operations

ACCEPN | ACCEPT | ACCESS | AMBTOA | ANYCN
CHKKBD | CHKONE | GET | INFLD | SBXINP
GETX | INPUT | INPUTC | INVUE | NOECHO
NOEKO | PCKLST | RXTERM | SCGINP | INMEMO
STENO | TCKI | TINKEY | TMENU | XDEFLT
MX_GETFKW | MX_GETPFK | MX_GETSW | MX_HOTKEY | MX_RELEASEKBD

Networking

CGIUTL | CONDEV | CRYPTO | EMAILP | GDIPRT
GETMAC | HTMLP | HTTP | TCPX |
MX_CHKPCNET | MX_GETIP | MX_GETLOKSER |  |

Time and Date

DATES | DSTOI | GRECNV | IDTIM | JULCVT
KDAY | LAPSED | ODTIM | STIME | TIMES
MX_FTFORMAT | MX_GETTIME |  |  |

Printing

CHKSPL | EZSPL | EMAILP | EZTYP | GDIPRT
HTMLP | PRTCHK | RDATE | SPOOL | USPSBS
MX_WINPTR | MX_GDICALC | MX_LASTPRTFIL | MX_LASTPRTFIL |

Inter-program and Inter-job Matters

COMMON | DSKCOM | FLOCK | FORCE | INCOM
ITC | PLYJOB | RVCOMN | SEND | SYS000
WAKNO | XLOCK | KILJOB |  |
MX_KILL | MX_READJCB | MX_WRITEJCB | MX_AGINTERPROC |

SBX-related

MX_EXITSBX

MX_FLSET

MX_IXCALL

MX_XCBDATAX

MX_XCBINFOX

ATE-related

MX_AGWRAPPER

MX_CLRINBUF

(and most routines in the Graphic User Interface section)

OS = UNIX

MX_GETPID

MX_GETUMSK

MX_SETUMSK

MX_VERINODE

OS = Windows

MX_BROWSEFOLDER | MX_CHOOSECOLOR | MX_CHOOSEFONT | MX_FINDWINDOW | MX_GDICALC
MX_GETOFD | MX_GETREG | MX_INSTNUM | MX_MAPI | MX_NUMASH
MX_PLAYSOUND | MX_REGISTRY | MX_RELEASEKBD | MX_SHELLEX | MX_SHOWWINDOW
MX_SYSBCLR | MX_TELSER | MX_TITLE | MX_WINPTR | MX_WINSETTINGS

OS = All

USRCNT |  |  |  |
MX_CLRSIG | MX_DIRSEP | MX_ERRNOMSG | MX_GETENV | MX_GETSIG
MX_GETUMSK | MX_INSTNUM | MX_KILL | MX_OSVER | MX_SETUMSK
MX_SETUSRNAM | MX_SHELLEX | MX_SYNC_CWD | MX_VERINODE |

A-Shell Environment Info and Control

MX_ABOUT | MX_ASHFILE | MX_CLFLAGS | MX_GETCISAM | MX_GETFKW
MX_GETLOKSER | MX_GETOPTIONS | MX_GETSW | MX_GETTRACE | MX_SETFKW
MX_SETLOKSER | MX_SETOPTIONS | MX_SETSW | MX_SETTRACE | MX_WINSETTINGS
MX_BEVEL | MX_GETQUEUE | MX_QRBLD | MX_ZAPQUEUE |
MX_IATIMEOUT | MX_QUNLOK | MX_PREBAS | MX_COMPIL | MX_INFDEF
MX_READJCB | MX_PRINTERR | MX_WRITEJCB | MX_EXIT | MX_IXCALL
MX_MALLOCLIMIT | MX_VUE | MX_QLOCK | MX_WSET_STATUS |

Graphical User Interface

GDIPRT | HTMLP | IMAGE | INFLD | MESAG
MSGBOX | PCKLST | SBXINP | XTEXT | XTREE
MX_WINSETTINGS | MX_AMOUSEXLT | MX_AUTOPARENT | MX_BEVEL | MX_CHOOSECOLOR
MX_CHOOSEFONT | MX_CLIPBOARD | MX_DEFTABXYZ | MX_GDICALC | MX_GETOFD
MX_GUIFLG | MX_MCRS | MX_RELEASEKBD | MX_SHOWWINDOW | MX_SINK
MX_SYSBCLR | MX_WINCTL | MX_WINMNU | MX_WINPTR |

System

AMOS | ASFLAG | BLOCKS | CGIUTL | DEVCHK
EMAILP | EZSPL | FIFO | FORCE | GETADR
HOSTEX | SLEEP | STALL | SUBMIT | USRCNT
MX_ABOUT | MX_ASHFILE | MX_ASHLOG | MX_CLFLAGS | MX_CLIPBOARD
MX_CLRSIG | MX_COMPIL | MX_DIRSEP |  |
MX_ERRNOMSG | MX_EXIT | MX_GETCISAM | MX_GETENV | MX_GETFKW
MX_GETLOKSER | MX_GETOPTIONS | MX_GETPFK |  |
MX_GETPID | MX_GETQUEUE | MX_GETREG | MX_GETSIG | MX_GETSW
MX_GETTIME | MX_GETTRACE | MX_GETUMSK |  |
MX_GETVER | MX_KILL | MX_LASTLNO | MX_MAPI | MX_PLAYSOUND
MX_PREBAS | MX_PRINTERR | MX_QLOCK |  |
MX_QRBLD | MX_QUNLOK | MX_READJCB | MX_RELEASEKBD | MX_RENAMERR
MX_SETFKW | MX_SETLOKSER | MX_SETOPTIONS |  |
MX_SETPFK | MX_SETSW | MX_SETTRACE | MX_SETUMSK | MX_SHELLEX
MX_TELSER | MX_VUE | MX_WRITEJCB | MX_ZAPQUEUE | XSHLEX

Communications

AUTLOG | COMIO | EMAILP | EMAILX | HTTP
TCPX |  |  |  |

Deprecated and Un-recommended

TCPCLI

TCPSRV


Limits and Capacities

Subroutines > Introduction to Subroutines

Limits and Capacities note: this is subset of other bigger table in other doc

Item | Size / limit / capacity / description | Updated in A-Shell build...; old value
Number of parameters than can be passed to a subroutine | 100 | A-Shell 5.1.1135 of 22 Jan 09; 30
Subroutine Name Length | Ten characters | A-Shell 5.1.1186 of June 2010
Maximum size of a parameter passed in or out of a subroutine | 2**24-1 (16,777,215) bytes |
Number of subroutines on disk or called in a single program | No inherent limit |
Number of modules that can be loaded into user memory | 96 (per job). Note that subroutines are modules. | A-Shell 4.0.854 of Nov 03; 32

Subtopics

Subroutine Name Length


Subroutine Name Length

Subroutine (XCALL) names may be up to 10 characters long; see History, below. This is accomplished by automatically converting XCALL statements with names between seven and ten characters long to VXCALL statements. This feature requires /X:2 and is not supported by /RC.

Note the potential for a backwards compatibility problem if you start using longer names in your XCALL (or VXCALL) statements and then try to RUN the resulting RUN files on an earlier version of A-Shell, which will only be looking at the first 6 characters. (Presumably that would cause an SBX not found error, unless there happened to be an existing routine that matched the first six characters.) For this reason, when using seven to ten character SBX names, you should avoid picking names for which an existing SBX would match the first six characters.

History

2010 June, A-Shell 5.1.1186: XCALL names increased from six to ten characters; compiler edit 455


Creating Subroutines

A-Shell also supports external, dynamically-loaded subroutines which you can write in BASIC and which are called in the exact same way from within your program. These routines have an extension of SBX, so named to avoid confusion with the SBR extension used under AMOS. See SBX Subroutines for information on writing your own routines.


Configurable Subroutines

Some of the routines have been modified by developers for their own purposes. In order to make those changes and improvements available to all A-Shell users, many of the more common and useful modifications have been implemented as configurable patches. These are specified using the SBR command in the system configuration file. The subroutines which have configurable functionality are:

INFLD | MESAG | COMMON | BASORT | XLOCK | ODTIM
SERCH | LSTLIN | JOBNAM | PRINT | TRIM | PRTCHK
XPPN | AMOS |  |  |  |

The subroutines GETJTB, SETJTB and PRTCHK are supplied for use under AMOS in the AMOS subdirectory. It is hoped that this will ease the writing of portable code. In particular, use of GETJTB can eliminate the need for many of the GETxxx routines to get information about your job, terminal, ppn, etc.


ABOX

xcall ABOX, srow, scol, height, width {,opcode}

ABOX.SBR is one of the many routines which draw boxes (among which, MSBOXX would be the most sophisticated and generally preferred). Note that ABOX draws the box at the specified position rather than around it.

Parameters

srow, scol [in]

starting row and position

height, width [in]

(not ending row/column)

opcode [in/out]

Without an opcode, the default, ABOX will just draw the box border. If opcode is specified and non-zero, the interior of the box will also be cleared. On return, opcode will be set to the number of bytes written, or less than zero for errors


ACCEPT, ACCEPN

xcall ACCEPT, key {,xlt}

xcall ACCEPN, key {,xlt}

ACCEPT.SBR is an enhanced version of the AlphaBASIC subroutine of the same name which inputs a single character from the keyboard. One of the enhancements is that the key parameter, in addition to the normal floating point type, can also be a one byte string. Two additional enhancements relate to the optional xlt parameter, which must be of type String. If you pass it as a three-character string, such as "IFX", then the routine will translate any input sequences using the function key translation table DSK0:<tdvname>.<XLT string>[7,0]. For example if xlt is "IFX" and the current terminal driver is "AM62A", then it would use DSK0:AM62A.IFX[7,0]. If you pass xlt as a null string, then there will be no function key translations, but it will still use the "cooked" input routine, which operates at a higher level than the "raw" routine used when xlt is not specified at all. The "cooked" routine, for example, will return characters left over from prior function key translations. In no case, though, will ACCEPT (or ACCEPN) return input from a command file.

ACCEPN.SBR is the same as ACCEPT.SBR, except that it does not echo the character input. ACCEPT will echo the character, unless it is an unprintable character.

History

2009 September, 5.1.1159: Changed to support returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized.


ACCESS

xcall ACCESS, mnustr, char, extflg {,row, col}

ACCESS.SBR is a handy utility for implementing single-line, single-character selection menus. The menu is made up of one or more choices, where each choice is displayed as a single upper case character followed by a close parenthesis and one or more lower case characters. The upper case characters are used to make the selections, and must be unique. A typical menu might look something like this:

A)dd C)hange D)elete Q)uit

Parameters

mnustr (null terminated String of appropriate length) [in]

must be formatted exactly as displayed (see example above) except that the spaces between the items are optional. Also, the string may begin with one or more of the following shortcut letters (with no following parentheses):

Shortcut | Displays as
A | A)dd
C | C)hange
D | D)elete
S | S)can
I | I)nquiry
X | X)ternal
L | L)ist

For example, if mnustr = "ACDLP)ostQ)uit" the menu would appear as:

A)dd C)hange D)elete L)ist P)ost Q)uit

char (String,1) [in/out]

may be loaded with the character corresponding to the default option, and will be returned with the character entered by the user to make a selection. The user must enter one of the upper case characters in the list, or use Backspace, Escape, or a function key to exit.

extflg (F,6) [out]

will return 0 if a normal menu selection was made, or 1 if Backspace or Escape was hit, or a number in the range of negative 1 to negative 32 if a function key is hit. In order for the function keys to be accepted, you must have a <tdvname>.IFX file in the LIB: account which maps function keys according to the INFLD scheme (e.g. F1 = (Ctrl+G)+(Ctrl+A), F2 = (Ctrl+G)+(Ctrl+B), etc.).

row, col [in]

may be optionally used to specify the starting position to display the menu. If row is 0 or not specified, the menu will be displayed starting from the position of the cursor at the time of the call.


AMOS

Updated February 2014; see History

xcall AMOS, cmd {,qflag, pflag, chainto}

AMOS.SBR allows a program to execute a command (e.g. DIR, LOG, COPY, etc.) or BASIC program (e.g. RUN XYZ) almost as if it were a subroutine. It is similar to HOSTEX except that instead of executing host operating system commands, (which differ from one operating system to the next, it executes AMOS commands, which are emulated by A-Shell and behave identically among A-Shell's different platforms.

Parameters

cmd (String) [in]

A-Shell command to be executed

qflag (Any) [in]

If non-zero and non-blank (i.e. 1 or "Q"), it causes the subroutine to run "quietly"—i.e., generally invisibly.

pflag (Num) [in]

If 1, forces the subroutine to run as if the AMOSRUNSBR flag had been set. If pflag is 2, it forces the subroutine to run as if AMOSRUNSBR had NOT been set.

Value (+4) allows the child RUN program to pass its updated command file status to the parent. There are two main consequences. The first is that any command file inputs that were absorbed by the child program will not be available to the parent. (This is almost always preferable.) The second is that any attempt by the child program to CHAIN will effectively pass the chain information back to the parent, so that when the parent ENDS, it will then execute the chain requested by the child. This may or may not be desirable, but it is the only way that an attempted CHAIN by the child will have any effect.

Value (+8) prevents the normal reset of the auto parent setting at the start of the called program. This makes it easier to launch programs designed to operate in the default or main window and instead force them to operate within a dialog created by the calling program.

Any other value causes the normal AMOSRUNSBR setting as specified in the miame.ini file or SET.LIT command to prevail.

chainto (String)

May be specified (along with the +4 option in the pflag parameter) to return the command line that the child program attempted to chain to. The CHAIN operation is always trapped by XCALL AMOS, forcing the child to return to the parent; this feature allows the parent to effectively carry out the requested CHAIN operation via a subsequent XCALL AMOS call. Chainto is a string of sufficient length to retrieve the CHAIN statement argument. If the +4 option in pflag is not specified, or if the child program does not CHAIN, chainto will return "". Also note that this is only possible when the child executes in-process, so unless you have that option forced on globally, you should also specify the +1 option in pflag.

Operations

AMOS.SBR may work in one of three ways, depending on whether the SBR=AMOS_RUNSBR switch is set, and depending on the command line specified.

• If SBR=AMOS_RUNSBR is not set (in miame.ini), or if the command does not begin with "RUN" or "ORUN", or the pflag parameter is specified as 2, then unless it is one of the special cases listed below, AMOS.SBR will spawn a new instance of A-Shell with the -e (exit-upon-completion) switch, forcing the new instance to execute the specified command. The calling instance of A-Shell is suspended until the second instance completes the command, as you would expect for a subroutine call. This is essentially the same as using HOSTEX and passing it a command line starting with "$ASHELL -e " (see Launching A-Shell with HOSTEX). Note that under Windows, any screen output within the subroutine will not affect the calling process, since they have separate screen windows, but under UNIX, even though the subroutine executes as a separate process, it shares the screen device with the caller and thus any output by the subroutine will remain on the caller's screen—although the calling program will not be aware of it and its cursor will not be advanced as you might otherwise expect.

• If the pflag parameter is set to 1, or if SBR=AMOS_RUNSBR is set and the command begins with "RUN" or "ORUN", then the command will be executed as a true subroutine within the current instance of A-Shell. The current program is suspended, as you would expect for a subroutine call, and a new memory partition is allocated for the subroutine, but it shares the calling job's process and job environment. Any screen output, and any changes to the job environment, such as the current ppn, will remain when the command completes and the subroutine returns. See the AMOS_RUNSBR switch for important information on limitations and tricks related to this switch.

• If a second instance is going to be launched, then if the optional second argument is specified, an attempt is made to execute the second instance "quietly." Under A-Shell/Windows, this is accomplished by making the new instance run in minimized mode. Under UNIX, it uses the –q startup switch.

In most cases, the A-Shell implementation of AMOS.SBR will achieve the same result as the typical implementation under AMOS. Actually, there are several versions of this subroutine created and distributed by various parties in the AMOS community. But most if not all work by making the child instance run as if it were a subroutine called by the parent. If you do not set the AMOS_RUNSBR switch, or if the command cannot otherwise be run within the current process, then the fact of it running in a separate process can lead to some subtle differences in the outcome which may be significant to some applications. For example, if the purpose of the child process is to make some change to the job status (e.g. via the SET command) then any such change will be discarded when the subroutine returns if the subroutine ran in a separate process. Another example would be where the child process uses its job name to generate a file or key, assuming that its job name is the same as the parent.

To minimize the chance of misunderstanding, the A-Shell implementation of AMOS tries to be smart by looking at the command and deciding if it is possible or more desirable to execute that command in-process (as a true subroutine) rather than by launching a new process. Some examples of this are:

xcall AMOS,"LOG <dev:[p,pn]>"

Since this is clearly a case where the intent is to change the PPN of the calling job, A-Shell intercepts this and turns it into xcall LOG,"<dev:[p,pn]>."

xcall AMOS,"LOOK <fspec>"

This one could be handled as a separate process with little harm, but since the new process would just turn around and use xcall EZTYP,<fspec> (MicroSabio’s EZTYP utility being deemed the appropriate replacement for Micro Concept’s LOOK.LIT), it seems more efficient to just call it directly.

xcall AMOS,"VUE <fspec>"

The reasoning here is similar to that used above. Under A-Shell, VUE.LIT is actually just a front end to the VUE function which is embedded within the A-Shell executable, so it makes just as much sense to call that function within the current instance as it does to start a new one.

Comments

AMOS.SBR will launch the new instance of A-Shell (if necessary) using the same initialization file and executable command pathname with which the current instance was launched.

The child job can determine its parent jobname from the JOBATT parameter of either GETJTB or PLYJOB.

The configuration file option switch, SBR=AMOSJOB1, will cause JOBNAM.SBR to return the name of the parent job rather than the child job.

Despite the name AMOS, you are still limited to executing commands that are recognized by and compatible with A-Shell. You cannot, for example, take AMOS machine language executables and execute them this way; the A-Shell LIT commands have been rewritten to emulate their AMOS counterparts, but have a completely different internal format.

History

2014 February, A-Shell version 6.1.1377: Add chainto

2014 February, A-Shell version 6.1.1374: Add pflag =8.

2010 May, 5.1.1182: Add pflag =4.

2006 May, 4.9.956: AMOS.SBR now replicates more switches from the parent to the child:

• -o <settings file>

• -nm

• -m, -mx (provided no -m or -mx is specified in XCALL command line)

• -z, -zt, -zi (provided no -z, -zt, or -zi is specified in XCALL command line)


ANYCN

xcall ANYCN, cngctl, whatno

ANYCN.SBR is used in many AlphaAccounting-derived programs to ask if the operator wants to make any changes before updating a record, and if so, which field number. The A-Shell implementation of ANYCN is pretty faithful to the AMOS one, except for a couple of extensions: support of foreign languages via the SBRMSG.lan file, and support of function key response codes. For convenience a complete summary of the functionality follows.

Parameters

cngctl [in/out]

Controls variations of the function as described below:

Value | Meaning
1 | Display the message "Any Change?" on line 24; allow the input of affirmative, negative, or a number. If an affirmative response given, the operator is then prompted for "What Number?" If a number is entered, it is treated as if an affirmative response was first given and then the number was entered at the "What Number?" prompt.
2 | Same as for 1, except that there is no option to input a number – only negative and affirmative responses are allowed.
3 | Display the message "INVALID SELECTION" and then proceed to prompt as if CNGCTL was set to 1.

On return from the routine, cngctl will be set to –1 if escape was entered, 0 for a negative response and 1 for an affirmative response.

whatno [out]

If cngctl is one, whatno will be set to the number entered. If a function key is entered and the <tdv>.IFX function key translation file has been set up using the INFLD standard for function keys (i.e. F1 = (Ctrl+G)+(Ctrl+A), F2 = (Ctrl+G)+(Ctrl+B), etc.) then the negative of the function key number will be returned in whatno (e.g. F1 returns –1, F2 returns –2, etc.).


ASCEBC, EBCASC

xcall ASCEBC, record

xcall EBCASC, record

ASCEBC.SBR and EBCASC.SBR convert the specified record from ASCII to EBCDIC and from EBCDIC to ASCII, respectively. The single parameter is a string or unformatted record of any size, which will be converted in place.

History

2011 March, A-Shell 5.1.1210: EBCDIC Lives! ASCEBC.SBR and EBCASC.SBR, ASCII to EBCDIC conversion routines, are now included in the A-Shell/Linux and A-Shell/Windows. They were previously available only in A-Shell/AIX.


ASFLAG

Updated March 2015; see History

xcall ASFLAG, flag

ASFLAG.SBR allows a program to set various internal A-Shell options that do not fall conveniently under another category.

Parameters

flag (Num) [in]

One or more flags to set from the following table. Note that if flag is mapped as B,2 (or B,4, see History note below), then the previous flag settings will be returned in the variable; this is useful when you want to temporarily change the flags and then restore them.

Symbol | Value | Meaning
 |  | Same as 1 if omitted (i.e. xcall ASFLAG equals xcall ASFLAG,1)
 | &h00000 | Turn off all flags
AF_READONLY | &h00001 | Turn on Read Only
AF_SYNCWRITE | &h00002 | Turn on Synchronized Write mode for D-ISAM
AF_DIVIDEBY0 | &h00004 | Allow divide by zero. Treats a division by zero as equal to zero, rather than generating a BASIC error. This is the runtime equivalent of the BASIC Plus compile-time source directives DIVIDE’BY’0 and NO’DIVIDE’BY’0.
AF_EXITSBX | &h00008 | Force exit to dot from SBX.
AF_MMAP | &h00010 | Memory Mapping
AF_NOIDXLOK | &h00020 | No IDX Lock
AF_LOCALCOPY | &h00040 | Make Local Copy of file (Windows only)
AF_SETCTRLC | &h00080 | May be used within an SBX subroutine to force a Force Ctrl+C to Parent program (on return from the SBX)
AF_NOMMAP | &h00100 | Turn off memory mapping (overriding the MMAPLIST in the miame.ini) for any files subsequently opened in the current program.
AF_CRYPT | &h00200 | Encrypt on allocate, disam create. Only applies to versions of A-Shell which support the Encrypted File System (EFS). Contact MicroSabio for more info.
AF_NOCRYPT | &h00400 | Override m1.crypt flags. Only applies to versions of A-Shell which support the Encrypted File System (EFS). Contact MicroSabio for more info."
AF_CSVNOQUOTE | &h00800 | Disables all special handling of double-quote characters (ASCII 34, or "), treating them as ordinary data characters.
AF_CSVSMARTQUOTE | &h01000 | Obsolete as of A-Shell 5.1.1163 of October 09. In prior versions: Enables "smart" handling of double-quote characters. A-Shell looks at the context of the line to guess whether a double-quote character is being used to enclose a field (that may contain special characters, including line breaks), or it is simply an ordinary data character.
AF_ISAMNODUPERRS | &h08000 | Modifies the behavior of the ISAM-A CREATE'RECORD statement. Normally, if the record already exists (and duplicates not allowed), it returns BASIC error 208 (attempt to add duplicate key). With the AF_ISAMNODUPERRS flag set, CREATE'RECORD will instead just return FSTAT=2 but no BASIC error. The motivation is mainly to improve performance of certain specialized file build operations where you want to add a record if it doesn't exist but do nothing if the record does exist. Setting the flag allows the program to eliminate a FIND operation prior to each CREATE'RECORD, which may significantly increase the build speed.
AF_SBXASRUN | &h10000 | Set SBX as Run.
Definition file: ashell.def

Comments

• This subroutine was first introduced as SETRO since its only function was the "Set Read Only" mode. ASFLAG is backward compatible with SETRO, so you can either change the name in your source code or alias it in miame.ini (e.g. ALIAS=SETRO:ASFLAG).

• A technique related to the memory mapping and local file schemes described above for speeding up single-user or read-only access to a file is that of loading a file into user memory (with LOAD.LIT or MX_USRLOD) and then accessing it via the MEM: device.

• If the flag parameter is mapped as B,2 then the previous flag settings will be returned in the variable. This is useful when you want to temporarily change the flags and then restore them.

• All flags are reset at the start of each RUN program. Otherwise, unless modified by a subsequent ASFLAG operation, they remain set for the duration of the current program.

• The ASFLAGs are not cleared at the start of SBXs. Thus changes during the execution of a RUN or SBX will be passed down to lower level XCALLs, but they do not percolate back up.

History

2015 March, A-Shell 6.1.1405: Previously, the ASFLAG options were cleared at the start of each SBX. They are now passed from the current program (parent) to the SBX (child). As before, flags set within the SBX do not affect the caller, except for AF_EXITSBX and AF_SETCTRLC.

2012 October, A-Shell 6.1.1319: ASFLAG now supports both B,2 and B,4 for the flags argument, returning the current flags in either case. Also add flags AF_ISAMNODUPERRS and AF_SBXASRUN.


Read Only

This mode causes any files opened subsequently for Random’Forced access within the current program to be treated as if the Read’Only open flag had been specified. (Since Read’Only was not introduced into the AMOS version of AlphaBASIC until late in the game, some developers use ASFLAG.SBR instead to maintain source code compatibility with early versions of the AlphaBASIC compiler, supplying a dummy ASFLAG.SBR under AMOS.)

The motivation for Read'Only under AMOS was strictly to avoid file locking conflicts in a program that was merely reading records and did not care whether they were locked (such as in a report). Under A-Shell/UNIX, this is the default behavior anyway, so the original motivation is only applicable to Windows platforms. However, there is another motivation for this mode, which applies to all networked A-Shell platforms: it can dramatically speed up file access, even if there are no other users accessing the same file. The reason has to do with eliminating the need for communication between the client process and the locking daemon on the server, which is especially slow under NFS and some Windows networks. Experimenting with this is relatively simple, since you can always "remove" the ASFLAG calls by simply aliasing ASFLAG to a null subroutine, like PRIV (e.g. ALIAS=ASFLAG:PRIV).


Synchronized Write

This mode only applies to ISAM-A files implemented under D-ISAM. When activated, it forces any write operation to wait until the data has actually been committed to disk before returning to the program. This will dramatically slow down access but might be useful in certain networked situations where you want to eliminate the possibility of a user on another CPU reading an outdated copy of the data due to buffer synchronization problems. It may also be useful in extremely critical applications where you cannot afford the possibility that a system crash will leave a lot of uncommitted updates stranded in memory.


Memory Mapping

This activates automatic memory mapping for any files subsequently opened within the current program. Option 16 (Memory Map) causes the subsequently opened random files to be "memory mapped." Memory mapping is a technique used very effectively on UNIX/Linux systems to greatly speed up file access. Essentially it makes the file act like virtual memory, such that you can then access it with memory (rather than disk) operations. This eliminates most of the overhead of disk service calls (which under UNIX require a context switch to supervisor mode, and under Windows networks may require machine-to-machine messaging). The advantage is most pronounced in files which are accessed very frequently and have small record sizes. For this reason, A-Shell uses memory mapping on the qflock.sys and jobtbl.sys files under UNIX/Linux.

There are, however, two downsides to memory mapping. The biggest one only affects Windows, where the memory "view" of a file is not kept coherent with the disk "view" of the file. Thus it is not a good idea to use this technique in multi-user mode, unless you are only planning to read from a file.

The second downside is that it causes a lot of memory to be allocated, which may decrease overall efficiency of the system if it is used too much. (If the total size of memory mapped files exceeds available memory, the system will begin to "thrash", which is not a pretty sight.)


No IDX Lock

This was implemented mainly as a test to see if ISAM access in a non-LOKSER environment could be significantly improved by not bothering to place a lock on the IDX "rock" when performing an ISAM operation. In theory, this simulates the way it works under AMOS when LOKSER is not on. In our experience so far, it does not seem to have that much of an effect. It was implemented as a file-oriented switch rather than a global option (like OPTIONS=ISAM_IDXLOK) because it is probably only practical, if at all, with files that are only going to be scanned and not updated. WARNING: using this option with a file that is being updated may lead to IDX corruption, unless you have some other mechanism in place to make sure two users are updating the IDX at once!

History

2006 March, A-Shell 4.9.952: In ISAM 1.0, when ASFLAG,32 is used to turn off all locking of the IDX file, if an error other than key-not-found (erf 33) occurs, A-Shell now retries the operation after doing a normal index lock. The theory here is that it may make it safer to use the no-lock mode in certain read-only situations (mainly in a peer-to-peer LAN environment) where normal locking has a high overhead and speed is the main consideration.


Local Copy

This only applies to Windows, and provides yet another way of speeding up access to a file that is only going to be read. When turned on, all random OPEN file operations result in a local copy being made of the file in the workstation's "TEMP" directory. (It uses the TEMP environment variable definition to locate this directory.) The local copy is then accessed, rather than the network copy. When the file is closed, the local copy is deleted (and any updates to the file are lost!)

The Local Copy option provides nearly as much performance improvement as memory mapping and even loading files into memory, and has the advantage of not requiring any extra physical memory. So it can work just as well with a 100MB file as with a 500K file (provided you have sufficient disk space). As with all of the related schemes for getting around the performance penalty of peer-to-peer shared file access, it makes the most sense in situations where you are going to be accessing a large part, or all, of the file. (It would not make much sense to transfer a 100MB file from the server to the workstation and then only access a few records from it.) Unlike memory mapping and the MEM: device, this technique works with ISAM files as well, and is immune to concerns over how well Windows supports it (since all we ask out of Windows here is the ability to copy a file).


Force Ctrl+C to Parent

This allows SBX subroutines to mimic a common behavior in traditional (AMOS) SBRs which do not do their own handling of Ctrl+C. The trick is to add the following to the error trap routine of the SBX module:

TRAP:

if err(0)=1 then

xcall ASFLAG,128 ! set ^C in parent

END ! exit SBX

Endif

If the flag argument is supplied as a 2 byte binary variable, then the previous flags settings will be returned in the variable, after the new settings are updated from the variable. This technique would be important when using ASFLAG.SBR to change the settings for just one file, returning to the original settings thereafter.


SBX as Run

Added October 2012

When set within an SBX, any files opened subsequently within that SBX will be auto-closed when this SBX returns. The flag name comes from the idea that in some kinds of menu architectures, you may use SBXs to execute programs that might otherwise have been executed with RUN. The difference is that in the case of a RUN, on exit, all files (and most other resources) are automatically closed or released, whereas with SBXs, files opened in the SBX remain open and accessible to the parent, as well as to other SBXs called by the parent or by the original SBX.

See Also

• File Handling...File Auto-Close Behavior

History

2012 October, A-Shell 6.1.1319: Flag added to ASFLAG


ATEAPX

New documentation May 2016

xcall ATEAPX, hostspec, pcdir, pcfile, flags, status

ATEAPX.SBX transfers a file from application server to ATE client PC. It supports multiple protocols, pre/post verification, logging, etc.

Parameters

hostspec (String) [in]

File spec of source file on server; AMOS-style or native; may contain embedded %env% variables)

pcdir (String) [in]

Destination directory on PC using Windows native syntax; default %ate%\dsk0\001004

pcfile (String) [in]

File.ext for destination. May be left blank to use same file.ext from source. May also contain complete path, in which case pcdir should be empty. Note that if pcdir blank, and pcfile contains format file.ext and file is longer than 10 characters, you should prepend a ".\" to eliminate ambiguity.

flags (Num) [in]

One or more of the following options. Symbols are defined in ashinc:ateapx.def.

Symbol | Value | Description
APXF_BINARY | &h0000 | binary transfer
APXF_ASCII | &h0002 | ascii transfer
APXF_NULL | &h0004 | 'null' printer mode, always set; see Comments
APXF_FTP | &h0008 | use FTP if server not Windows
APXF_NOPOSTVERIFY | &h0010 | skip post-transfer verification
APXF_PREVERIFY | &h0020 | pre-verify; skip transfer if destination already matches source
APXF_NOVER | &h0040 | ignore version 0 when comparing versions
APXF_LOGCURDIR | &h0080 | write ateapx.log entries to current ppn rather than opr: directory

status (signed num) [out]

Value | Description
>0 | file transferred / number of bytes transferred
0 | File transfer not needed or applicable
-1 | ATE required
-2 | host file doesn't exist
-3 | file transferred but failed to verify afterwards
-4 | FTP transfer error
-98 | A-Shell version on server not high enough for binary transfer
- 99 | ATE version not high enough

Comments

If running in a local Windows environment—i.e. A-Shell/Windows standalone, P2P or remote desktop— then ATEAPX does nothing and returns status 0; file transfer not applicable.

If the ATXF_PREVERIFY flag set, ATEAPX uses the MX_FILESTATS function to compare the source and destination files to determine if the transfer is actually needed. The small overhead of the pre-verification is almost always worth the chance to omit the transfer, except when the file to be transferred is very small or the chance of the destination matching the source is very slim.

If APXF_FTP flag set and the server is not Windows/ATSD, then ATEAPX first attempts to transfer the file using FTP protocol via the AG_FTP command sequence. If the FTP operation fails, it will retry one time before giving up and returning status -4.

If not using FTP, then instead it uses the existing ATE terminal channel to transfer the file—aka the 'null' auxiliary printer protocol.

The ATEAPX.LOG file in OPR: or the current directory, depending on the APXF_LOGCURDIR flag, provides useful information about the success or failure of transfers. To increase the level of detail in the log file, use SET DEBUG prior to the transfer.

Source to ATEAPX available in the [907,33] of the SOSLIB repository.

See Also

• ATSYNC.LIT to transfer/sync many files from server to client

• AG_FTP: invoke FTP from client directly

• FTPDLX.SBR or FTP2.SBR: invoke FTP from server directly

• ATEGFK.SBR: retrieve file from ATE client via keyboard channel

• Source, samples and related functions can be found in SOSLIB:[907,33].


ATEGFK

Added May 2016

xcall ATEGFK, hostspec, pcspec, flags, status

ATEGFK.SBX retrieves a file from the PC via the ATE terminal connection. This is useful in situations where FTP isn't available or isn't practical.

Parameters

hostspec (String) [in]

is the destination (native or AMOS-style)

pcspec (String) [in]

is the source (PC native)

flags (Num) [in]

may contain zero or more of the following:

Value | Definition
16 | skip post-transfer verification
32 | pre-verify (skip transfer if destination matches source)
64 | ignore version 0 in pre-verification
128 | put ATEGFK.LOG in current directory rather than OPR:

status (signed num) [out]

returns status of operation:

Value | Definition
>0 | file transferred
0 | transfer not required
-1 | ATE required
-2 | source file doesn't exist
-3 | file transferred but failed to verify afterwards
-4 | transfer failure

Comments

ATEGFK.SBX may work with ATE 6.1.1357+ but will be much better with ATE 6.1.1370.0+.

See test program TSTATEGFK.BP. Both are included in [907,33] of the SOSLIB along with other ATE file-transfer related utilities.

See Also

• MX_ATEFILEXFR

• ATEAPX.SBX

• Source, samples and related functions can be found in SOSLIB:[907,33].

History

2016 April, A-Shell 6.3.1510: Routine added to A-Shell


ATELGI

xcall ATELGI, name, pw, status, pkpw, host, cfg

ATELGI.SBX provides the means for creating a customized ATE login script. If BAS:ATELGI.SBX exists and the automatic login doesn't succeed, ATE will call it instead of the internal generic login dialog to get the login credentials. Source, samples and related functions can be found in SOSLIB:[907,50].

Parameters

Name | Type | I/O | Description
login | String | in/out | login name
pw | String | out | password
pkpw | String | in/out | private key passphrase
status | Num | in/out | status: OK/CONNECT=1, CANCEL=0
host | String | in/out | host{:port}
cfg | String | in | name of current ATE configuration


AUI

The AUI subroutine serves as a organizing wrapper for most of the primary classes of functions of the AUI Toolkit.

xcall AUI, CLASS, parameters

We use the object-oriented "class" terminology not to claim that these meet every definition of an object class, but to promote an object orientation to the understanding and use of the functions. Adopting this mind set early on in a text-to-GUI conversion project will reinforce good design and contribute to better results.

CLASS is a string which names the class of interface "object" from the following table.

Class | Description
AUI_CONTROL | Display and input controls. Properties include the control type (button, checkbox, etc.), size and position (using the row/col coordinate system), etc. Methods include create, modify, delete, save, restore, clear, etc. Same as MX_WINCTL.
AUI_EVENTWAIT | Abstract class whose purpose is to provide methods for waiting for an interface event (typically a button to be clicked). Used as an alternative to INFLD or other input routine. Same as MX_EVENTWAIT.
AUI_ENVIRONMENT | Properties related to the interface environment.
AUI_MENU | Menu items. Methods for adding, deleting, and enabling/disabling items. Same as MX_WINMNU.
AUI_IMAGE | Special case of control for images. Same as IMAGE.SBR.
AUI_WINDOW | Main display window configuration. Properties include number of rows and columns, status lines, colors. Methods include PRINT and Tab.
AUI_HTMLHELP | Interface with HTML/CHM help files.
other | Other classes can be implemented as SBX modules. xcall APL,CLASS$,... will be treated internally as VXCALL CLASS$,...

Note that there are some other class-level objects which could probably be in this table but are not. These controls were either developed before those noted in the table, or were deemed sufficiently important enough to have their own stand-alone function and documentation. Those topics are:

• INFLD, the control for handling data input and output.

• XTREE, the control for managing trees and listboxes.

• XTEXT, the control for managing text functions.


AUI_CONTROL

xcall AUI, AUI_CONTROL, opcode, ctlid, ctext, cstate, ctype, cmd, func, cstatus, srow, scol, erow, ecol, fgc, bgc, fontattr, fontscale, fontface, tooltip, parentid, winclass, winstyle, winstylex, ctype2

The AUI_CONTROL class provides methods for creating a wide range of Windows GUI "controls", such as buttons, static text objects, listboxes, etc.

Currently this class is supported under Windows (and ATE) only, although there is nothing prohibiting an ambitious programmer from implementing a "super class" that provides similar capabilities in a text environment. In fact, it is generally recommended that developers create their own wrappers for these low level functions in order to standardize and accelerate their development.

Subtopics

AUI_Control Parameters

Control Types

Other Control Topics


AUI_Control Parameters

All of the parameters are optional except for the first two, opcode and ctlid, which together are sufficient to delete the control. Even when adding a new control, the last several parameters are only needed when you want to do something slightly unusual or fancy. Refer to the documentation on the individual parameters below for deciding how many you need to specify for a particular effect.

In the case of opcode CTLOP_INFO, all of the parameters besides opcode may be updated. The indicators in the I/O column ignore this case and apply only to the opcodes other than CTLOP_INFO.

Parameter | Type | I/O | Description
opcode | Num | in | Determines the "method" or operation to perform.
ctlid | String or Num | in/out | Control ID: an integer starting from 1, or an alphanumeric name, that uniquely identifies each control.
ctext | String | in/out | Text associated with the control. For most typical controls (buttons, static text, checkbox, etc.) this is the text that appears in the control.
cstate | B,4 | in | State of the control (enabled, disabled, hidden, etc.).
ctype | B,4 | in | Control type and attributes. For more exotic controls, leave this zero and use winclass, winstyle, winstylex.
cmd | String | in | Specifies the command or keyboard string which is invoked when the control is clicked.
func | String or B,1 | in/out | When the cmd type is DLL, this can specify a function within the DLL to execute. For checkboxes, func is a 1-byte binary which gets set and cleared along with the display state of the checkbox.
cstatus | signed Num | in/out | Returns status indicating success of operation. For some opcodes, it is used as an input also.
srow, scol, erow, ecol | Num | in | Coordinates of the control.
fgc, bgc | Num | in | Foreground and background color palette numbers for the control.
fontattr | Num | in | Used to override the default font attributes for the control.
fontscale | Num | in | Scales the font to the specified percentage.
fontface | String | in | Overrides the default font selection.
tooltip | String | in | Defines a "tooltip" (popup message)
parentid | String or Num | in | If specified, new control becomes child of specified control.
winclass winstyle winstylex | String | in | May be used as an alternative to ctype to create a control using the standard Windows control classes and styles.
ctype2 | B,4 | in | Extension of ctype; control type and attributes.


opcode

Updated November 2013; added opcodes 13, 14

Opcode specifies one of the "methods" or operations from the following table.

Symbol | Value | Description
CTLOP_INFO | 0 | Query Control
CTLOP_ADD | 1 | Add Control
CTLOP_CHG | 2 | Change Control
CTLOP_DEL | 3 | Delete
CTLOP_CLR | 4 | Clear Control
CTLOP_QRYCB | 5 | Query Checkbox
CTLOP_SVA, CTLOP_RSA | 6, 7 | Save/Restore Controls
CTLOP_SBCH, CTLOP_EBCH | 8, 9 | Batch Operations
CTLOP_GETID | 10 | Get Control ID
CTLOP_PANE | 11 | Set Current Tab Pane
CTLOP_REPL | 12 | Internal use only.
CTLOP_TABSET, CTLOP_TABCLR | 13, 14 | Set/Clear MBF_TABSTOP Property
Definition file: ashell.def


Query Control

Use CTLOP_INFO to query the details of a control by its ctlid. This is mainly useful in three kinds of situations:

• You need to determine if a control (with a specific ctlid) still exists (perhaps upon return from a subroutine that may or may not have cleared the screen).

• You have a ctlid (perhaps returned from the BTNMNU.SBX or AUI AUI_EVENTWAIT) but your program does not keep track of controls by their ctlids, so you need to find out more information about the control to decide what to do.

• You have a ctlid and you know what control it is, but the control has changeable text and you want to determine what the current text associated with the control is. This would mainly apply to a control designed to be modified by the user (such as an edit control), and in that case, you would probably use INFLD and keep track of the text a different way, but this capability may be useful in an advanced situation.

To query a control, you need to specify the ctlid. The contents of all the other parameters are ignored on input, and are returned with updated values based on the control specified. If the control exists, cstatus will be set >= 0. If the control is not found, it will set to –2. Other negative values correspond to errors (see cstatus above for a table of error codes). You must specify at least the parameters up to cstatus (and it must be a real variable); all others are optional (but will be updated if passed).

Example

ctlid = "btnTest" ! id of control to query

xcall AUI, AUI_CONTROL, CTLOP_INFO, ctlid, ctext, cstate, ctype, cmd, func, cstatus, srow, scol, erow, ecol

if cstatus >= 0 then

! control exists; ctext, cstate, etc. will be updated

else

! control doesn't exist

endif


Add Control

Rewritten Feburary 2013

To add or create a control, use CTLOP_ADD and specify at least all the parameters up through the ecol parameter. The rest are optional.

The following simple example creates a button occupying the rectangle from 5,10 to 6,20 (in the grid units of the current parent window), displaying "Process", and transmitting exitcode -107 when clicked:

xcall AUI, AUI_CONTROL, CTLOP_ADD, ctlid, "Process", MBST_ENABLE, MBF_BUTTON + MBF_KBD, "VK_xF107", "", cstatus, 5, 10, 6, 20

In this slightly more complex example, we create a clickable static text control, specifying an alphanumeric id and a variety of other attributes. See Comments.

fontattr = FS_ITALIC + FA_HEAVY

fontscale = 250

fontface$ = "Impact"

tooltip$ = "Click for more information"

parentid$ = "gbMessages"

xcall AUI, AUI_CONTROL, CTLOP_ADD, "txtWarning", "Warning! Meltdown Imminent!", MBST_ENABLE, MBF_STATIC + MBF_LFJUST + MBF_AUTOGROW + MBF_KBD, "VK_xF108", NUL_FUNC$, NUL_CSTATUS, 2, 10, 3, 20, &h0000ff, RGB_TRANSPARENT, fontattr, fontscale, fontface$, tooltip$, parentid$

Comments

• If the ctlid parameter is numeric, it is ignored on input and set to the new control's numeric id on output. But if ctlid is alphanumeric, it is used as-is, and does not change. The numeric equivalent (or an error code < 0) will be returned in the cstatus parameter, assuming the parameter is numeric. The second example uses NUL_CSTATUS, defined as "" in ashell.def, which eliminates the return status; this is a significant performance optimization in the case of ATE where each control created would otherwise require waiting for the client's return status packet to arrive before the next control could be created.

• If the parentid parameter is not specified, as in the first example, the new control will be a child of the current window: either a modal dialog, if one exists, or else the main window. The coordinates specified will be taken as relative to the parent control.

• For most child controls, if the new control has the same starting position as an existing child control, the existing control will be removed. In the case of the GUI_SPC_IND system option, this rule is expanded slightly to allow a new control to replace a pre-existing one that overlaps the new one. In both cases, the intent is to simplify automated strategies for migrating from plain text to GUI. See AUTOTPRINT, MX_DEFTABXYZ, and INFLD's type |G).

• Normally, the control type is determined by the ctype parameter, but in certain circumstances you can set ctype to 0 and specify the control type in the winclass, winstyle, and winstylex parameters. This technique is generally only useful for control types that do not require any interactivity -besides a click action), with the main example being Lines, Rectangles and Frames, although it may also provide a way to create a control type for which no ctype flags have been defined.


Change Control

Rewritten February 2013

CTLOP_CHG (opcode 2) can be used, in conjunction with various MBST_xxx flags in the cstate parameter, to change virtually any of the attributes of an existing control (such as the displayed text, state, command, etc.) For example, consider the following sample dialog:

this is a linked image

The Connect button is disabled because the user hasn't entered enough information to even justify attempting a connection. Once they do so, we want to enable the Connect button, which we can do with something like the following:

xcall AUI, AUI_CONTROL, CTLOP_CHG, btnid, NUL_CTEXT, MBST_ENABLE

this is a linked image

The key parameters here were the button identifier and the MBST_ENABLE flag. We're not changing the button text, so we just supply NUL_CTEXT (defined as "" in the ashell.def) for the ctext parameter, and none of the other parameters are required. If we wanted to know what the prior state of the control was, we could pass the cstatus parameter (and those prior to it), but in most cases, we don't care about the prior state.

To take another example, let's say we want to change the label associated with the second field, depending on the Database Connector - for MySQL, "Host/Server" seems appropriate, but for ODBC, "Data Source" might be better. To accomplish that, we can use a slight variation of the CTLOP_CHG operation:

xcall AUI, AUI_CONTROL, CTLOP_CHG, btnid, "Data Source", MBST_CHANGE + MBST_TEXTONLY

this is a linked image

The combination of the MBST_CHANGE and MBST_TEXTONLY flags in the cstate parameter causes the operation to only affect the text of the control, for which we supplied the new string "Data Source".

Depending on which MBST_xxx flags are specified, you may need to specify more parameters, with the extreme case being MBST_CHANGEX which replaces all of the attributes of the control (essentially deleting and recreating it). Virtually all of the MBST_xxx cstate flags can be used with CTLOP_CHG, but the following ones apply uniquely to CTLOP_CHG and are therefore worth noting:

Symbol | Description
MBST_CHANGE | Change ctext and cmd.
MBST_TEXTONLY | Add to MBST_CHANGE to limit the changes to the ctext
MBST_STYLE | Change the style and alignment flags (ctype)
MBST_POS | Change the position (coordinates)
MBST_CHANGEX | Change everything
MBST_NORMALIZE | Change a maximized dialog back to normal state


Delete Control

Updated February 2014

CTLOP_DEL (opcode 3) is used to delete a control or set of controls. Typically you only need to specify the ctlid, e.g.

xcall AUI, AUI_CONTROL, CTLOP_DEL, CTLID

As a special convenience, you can delete the current dialog without even knowing its id by specifying a ctlid of 0 and putting MBF_DIALOG in the ctype field:

CTLID = 0

xcall AUI, AUI_CONTROL, CTLOP_DEL, CTLID, NUL_CTEXT$, NUL_CSTATE, MBF_DIALOG

You have to specify the ctext and cstate parameters prior to the ctype parameter, but since we don't care about them, we use the symbols NUL_CTEXT$ and NUL_CSTATE [defined in ashell.def as "" and 0, respectively] as placeholders.

The other way to delete controls is by setting ctext to "*" and using the srow, scol, erow, and ecol parameters to specify a region. In this case it is essential to specify the parentid (typically a dialog) unless referencing controls directly in the main window. ctlid should be set to 0. For example, to delete all of the controls within the region bounded by 1,1 and 3,30 within the dialog whose id is "dlgOne":

CTLID = 0 : DLGID = "dlgOne" : srow = 1 : scol = 1 : erow = 3 : ecol = 30

xcall AUI, AUI_CONTROL, CTLOP_DEL, CTLID, "*", cstate, ctype, cmd, func, cstatus, srow, scol, erow, ecol, NUL_FGC, NUL_BGC, NUL_FONTATTR, NUL_FONTSCALE, NUL_FONTFACE$, NUL_TOOLTIP$, DLGID

As mentioned above, the various NUL_ symbols are defined in ashell.def as 0 or "", and are used here for clarity as placeholders for the "don't care" parameters.

A third way to delete controls is with TAB(-1,0), which deletes everything, including dialogs, unless the MX_AUTOPARENT is set, in which case the action is confined to the children of the specified parent.

To delete all the controls but leave untouched the plain text in the main window, specify ctlid 0 without any other parameters:

xcall AUI, AUI_CONTROL, CTLOP_DEL, 0

Comments

Deleting a control will automatically delete any child controls of that control.If you want to delete just the children but leave the target control alone, you can use opcode 4 (see Clear Control) or by specifying the parentid with all of the other parameters set to null, e.g.:

xcall AUI, AUI_CONTROL, CTLOP_DEL, NUL_CTLID, NUL_CTEXT$, NUL_CSTATE, NUL_CTYPE, NUL_CMD$, NUL_FUNC$, NUL_CSTATUS, NUL_SROW, NUL_SCOL, NUL_EROW, NUL_ECOL, NUL_FGC, NUL_BGC, NUL_FONTATTR, NULL_FONTSCALE, NUL_FONTFACE$, NUL_TOOLTIP$, parentid

History

2014 February, A-Shell 6.1.1377: Several improvements and doc modifications.

2012 October, A-Shell 6.0.1261: Support ctlid=0 to clear all of the controls, leaving plain text alone:

xcall AUI, AUI_CONTROL, CTLOP_DEL, 0


Clear Control

Updated October 2012

CTLOP_CLR (opcode 4) is just like opcode 3, except for the following differences:

• If ctlid is specified, then only the children of that control are deleted. This is most useful with Tab controls, where, as you change panes, you need to remove the children previously displayed on the old pane and create the ones corresponding to the new one. If ctlid does not refer to a control with children, then it is ignored (i.e. treated as if zero), in which case it identifies the controls to be deleted by the coordinates (assuming ctext = "*"). See XTREE/XTEXT Tab Performance for an alternative to clearing and recreating XTREE and XTEXT controls within Tab panes.

• It only deletes "unprotected" controls. By default static text controls are unprotected (as are those created with EPRINT), while most other types are protected. (You can, however, remove protection from protected controls by adding MBF_UNPROTECTED when the control is created.) To add protection to text controls, you have to add the dim attribute and also enable protection just like you would with regular text, using Tab(-1,13). For text controls created with AUI_CONTROL, you add protection by specifying MBF_DIM when creating the control. For text controls created via TPRINT commands, the MBF_DIM attribute is set automatically if the current text mode is dim (i.e., if Tab(-1,11) was issued previously.) The point of all this is to allow you to perform the same "trick" that is possible with dumb terminals, whereby you can protect the background of a form and clear the foreground with just a couple of commands. If it just seems confusing, you can probably ignore it.

Tab(-1,10) (clear to end of screen) and Tab(-1,9) internally perform an opcode 4 for the region in question.

History

2012 October, A-Shell 6.0.1261: CTLOP_CLR with MBST_TEXTONLY now ignores buttons and other controls types where the idea of clearing the text contents doesn't seem to make much sense.

2012 October, A-Shell 6.0.1261: AUI_CONTROL refinement: When using opcode CTLOP_CLR, you may now set the MBST_TEXTONLY flag in the cstate parameter to cause it to clear the text from any affected control, rather than delete the control entirely. This is mainly useful with controls containing data in a form, where you want to clear the data but leave the form. Note that in such a case, you will probably want to protect the label controls from being cleared, which you can do by creating them with the MBF_DIM attribute set, and using TAB(-1,13) to enable protection immediately prior to the AUI_CONTROL, CTLOP_CLR operation. Use TAB(-1,14) afterward to disable protection.

For example, to clear the text from the unprotected controls, and leave the protected controls alone (in the region of rows 1-24 and cols 1-80):

? tab(-1,13); ! enable protection

xcall AUI, AUI_CONTROL, CTLOP_CLR, NUL_CTLID, "*", MBST_TEXTONLY, NUL_CTYPE, NUL_CMD$, NUL_FUNC$, 1, 1, 24, 80

? tab(-1,14); ! disable protection

Note that the "*" in the ctext parameter is required to select all the controls.


Query Checkbox

CTLOP_QRYCB (opcode 5) may be used to query the current value of a checkbox or radiobutton. The value (returned in the cstatus parameter) may be one of: 0 (unchecked), 1 (checked), or 2 (indeterminate, for MBF_3STATE checkboxes).

The ability to query the value of a checkbox is useful when you want to present a bunch of checkboxes and let the user click on them in any order, or TAB around them, without having to code the INFLD logic necessary for handling individual field exitcodes and immediate validation. Instead, you can just let EVENTWAIT handle the operation until the user triggers the event requiring that you retrieve the values.

Note that in the local A-Shell/Windows environment, a special operation to query a checkbox isn't really necessary, since the AUI system will automatically and immediately update the checkbox value variable (specified in the func parameter when the checkbox was created). But in the ATE environment (where the checkbox is on the client and the variable is on the server), direct updating of the value variable isn't possible. The CTLOP_QRYCB method described below, will work in all environments and thus is recommended.

As an example, consider the following simple dialog containing several checkbox options:

The program creates the dialog, then waits in an EVENTWAIT loop to either click the green button (which triggers the checkbox query routine and displays the results in the trace window), or to close the dialog (by clicking the red X or hitting ESC).

Source code for above dialog.

program qrycb,1.0(100) ! simple example of querying checkboxes

++include ashinc:ashell.def

define MAX_CB = 7 ! number of checkboxes

define DLG_ID$ = "dlg1" ! id of main dialog

map1 cb(MAX_CB)

map2 cb'id$,s,20 ! control id

map2 cb'dsc$,s,20 ! display text

map2 cb'val,b,1 ! checkbox value

map1 misc

map2 i,f

map2 row,b,4

map2 col,b,4

map2 evw'parentid$,s,24

map2 evw'ctlid$,s,24

map2 evw'flags,b,4

map2 exitcode,f

map2 status,f

data "cbAPEX", "APEX"

data "cbASQL", "ASQL"

data "cbATE", "ATE"

data "cbATS", "ATS"

data "cbISAMA", "ISAM-A"

data "cbPDFX", "PDFX"

data "cbPolyShell", "PolyShell"

! create the dialog

xcall AUI, AUI_CONTROL, CTLOP_ADD, DLG_ID$, "A-Shell Options", &

MBST_ENABLE, MBF_DIALOG + MBF_ALTPOS + MBF_SYSMENU, &

NUL_CMD$, NUL_FUNC$, NUL_CSTATUS, 2000, 5000, 8000, 25000

! create the checkbox controls

for i = 1 to 7

read cb'id$(i), cb'dsc$(i)

! divide into two columns

if i <= 4 then

row = (i + 1) * 1000 ! millirows

col = 3000

else

row = (i - 3) * 1000

col = 12000

endif

cb'val(2) = 1 ! (initialize one of the checkboxes to checked)

xcall AUI, AUI_CONTROL, CTLOP_ADD, cb'id$(i), cb'dsc$(i), &

MBST_ENABLE, MBF_CHKBOX + MBF_LFJUST + MBF_TABSTOP, &

NUL_CMD$, cb'val(i), NUL_CSTATUS, row, col, row+1000, col+7000, &

NUL_FGC, NUL_BGC, NUL_FONTATTR, NUL_FONTSCALE, NUL_FONTFACE$, &

NUL_TOOLTIP$, DLG_ID$

next i

! create qry/exit buttons

xcall AUI, AUI_CONTROL, CTLOP_ADD, "btnQry", "checks::ashico1", &

MBST_ENABLE, MBF_BUTTON + MBF_ICON + MBF_KBD, &

"VK_xF101", NUL_FUNC$, NUL_CSTATUS, 5500, 14000, 6500, 16000, &

NUL_FGC, NUL_BGC, NUL_FONTATTR, NUL_FONTSCALE, NUL_FONTFACE$, &

"Query the current checkbox values", DLG_ID$

xcall AUI, AUI_CONTROL, CTLOP_ADD, "btnExit", "delete::ashico1", &

MBST_ENABLE, MBF_BUTTON + MBF_ICON + MBF_KBD, &

"VK_ESC", NUL_FUNC$, NUL_CSTATUS, 5500, 17000, 6500, 19000, &

NUL_FGC, NUL_BGC, NUL_FONTATTR, NUL_FONTSCALE, NUL_FONTFACE$, &

"Exit dialog", DLG_ID$

! wait for user to click Query or Exit

evw'parentid$ = "dlg1"

evw'ctlid$ = cb'id$(1)

evw'flags = 0

do

xcall AUI, AUI_EVENTWAIT, evw'parentid$, evw'ctlid$, exitcode, evw'flags

switch exitcode

case -101 ! clicked ok

trace.print "Querying checkboxes..."

for i = 1 to MAX_CB

xcall AUI, AUI_CONTROL, CTLOP_QRYCB, cb'id$(i), NUL_CTEXT$, &

NUL_CSTATE, NUL_CTYPE, NUL_CMD$, NUL_FUNC$, status

cb'val(i) = status

trace.print "CB #"+i+" : "+cb'dsc$(i)+" = "+cb'val(i)

next i

exit

endswitch

loop until exitcode = 1 ! (escape)

xcall AUI, AUI_CONTROL, CTLOP_DEL, DLG_ID$ ! close dialog

end

Comments

The program above uses alphanumeric IDs for the checkbox controls, which eliminates the need for the CTLOP_ADD operation to return the numeric ID of each newly-created checkbox. This speeds up creation of the dialog in the ATE environment (where otherwise the server would have to wait for the return status of each checkbox before creating the next one). But it doesn't help the CTLOP_QRYCB operation, which would require a round-trip (server to client and back) for each checkbox queried. For a small dialog like this it wouldn't be an issue, but if you have a dialog with hundreds of checkboxes, you may want to consider optimizing the ATE performance either using Batch Operations or perhaps organizing the checkboxes into an XTREE.

See Also

Get Control ID for an example scenario involving the need to query a radio button in order to enable/disable another control.


Save/Restore Controls

CTLOP_SVA (opcodes 6 and 7) are normally only used internally by A-Shell, in conjunction with command which save and restore full or partial screen areas (e.g. TCRTs 148, 149, 202, 203, plus pop-up subroutines like MSBOXX, INMEMO, etc.) If for some reason you wanted to do this directly, note the following:

• You must specify up through the ecol parameter.

• The func parameter should be set to the string representation of a numeric ID (e.g. "1"). The same ID must be specified on the restore operation as for the save (this is how the correct set of saved controls is located.)


Batch Operations

Note: Batch operations are now deprecated, as the original motivation (improved ATE performance) has been satisfied in a simpler way by using alphanumeric Control names. The remainder of the discussion below is retained here for historical purposes only.

CTLOP_RSA (opcodes 8 and 9) offer increased efficiency for creating many controls at a time, and may be of interest when the application server and workstation are not the same machine. In that environment, for each control created, the application server sends the request to the workstation, which creates the control and sends back the control ID and status. Although the amount of information transferred is minimal, the delay introduced by the server having to wait for a response to each command before issuing the next can add up to noticeable delays, particularly on a slow network.

There are two general techniques for minimizing those delays: activating the "ATE Reverse Channel" (described elsewhere), and creating controls in a batch. When controls are created in a batch, the return information (ID and status) for each control is buffered on the workstation until the batch is complete, after which it sends all the return information in a single packet. The main drawback of this approach is simply that it takes two extra steps for each batch – one command to start the batch and another to finish it.

To start a batch, use opcode 8, as follows:

xcall AUI, AUI_CONTROL, CTLOP_SBCH, cstatus

The normal return cstatus is 0. If a batch has already been started, cstatus will be set to –12. Other values all correspond to errors.

Once the batch is started, you can proceed to issue commands to create or query controls as you normally do, but do not bother checking for returned ctlid or cstatus values, as they are buffered by the ATE client. (You do need to specify valid ctlid and cstatus parameters, just as if you were getting those parameters back on every call; otherwise the return status is not added to the buffer for later return.)

To complete the batch and retrieve the buffered values, use opcode 9:

COUNT = <maximum number of controls in batch>

XCALL AUI, AUI_CONTROL, CTLOP_EBCH, CSTATUS, COUNT, ID(1), CB(1)

If CSTATUS # <number of controls requested> then goto Error

The parameters should be mapped something like the following:

MAP1 ID(20),B,2 ! array of control IDs (sized large enough for the batch)

MAP1 CB(20),B,1 ! array of status codes (or checkbox values)

MAP1 CSTATUS,F,6 ! returns number of controls actually created in batch

MAP1 COUNT,B,2 ! number of controls expected (max)

The count parameter must be set to the maximum number of controls in the batch (and no larger than the arrays.) Typically you would set this to the actual number of controls you attempted to create in the batch, although it might also be set to the maximum size of the arrays. (It just sets an upper limit on the amount of information returned.)

cstatus will be updated to the actual count of controls created in the batch. If it does not agree with the number you tried to create, then there was a problem.

The id() array receives the ctlid values of the controls created in the batch.

The cb() array receives the status codes that would have otherwise been returned in the cstatus parameter for each control creation operation. Note that it must be mapped as an array of B,1 (as shown above), so negative cstatus values will appear as 255 (-1), 254 (-2), etc. (Mainly you only care if the status is 0 or not.)

Note that you normally specify the first element of each array in the parameters passed to the subroutine as shown in the example above. But if you have one large array of control Ids, yet for some reason you use multiple batches to create your controls, you could specify a different starting value for a subsequent batch, e.g. cb(10) instead of cb(1), as long as the array is big enough.

As an example of using a batch, we will recode the example given for opcode 5 above, this time using a batch operation to create the checkboxes, and another to query them. See the sample program TSTBMN in the EXLIB for a complete working version of this logic.

MAP1 CID(7),B,2 ! control Ids for the checkboxes

MAP1 CB(7),B,1 ! chkbox state (0=unchecked, 1=checked)

MAP1 OPTDLGID,B,2 ! ID of dialog box

MAP1 STATUS,F,6

MAP1 NOSTATUS$,S,1,"" ! use when we do not care about status or ID

CREATE'DIALOG:

OPTDLGID = 0

xcall AUI, AUI_CONTROL, CTLOP_INFO,OPTDLGID, "Eventwait Option Flags", MBST_ENABLE, MBF_DIALOG + MBF_SYSMENU, "", "", STATUS, 2, 2, 11, 23

if OPTDLGID = 0 then goto ERROR'OUT

!(assume that CB(7) values have been initialized appropriately)

! Start a batch:

xcall AUI, AUI_CONTROL, CTLOP_SBCH, STATUS

if STATUS # 0 goto ERROR'OUT

xcall AUI, AUI_CONTROL, CTLOP_INFO, CID(1), "Start on next control (1)", MBST_ENABLE, MBF_CHKBOX + MBF_LFJUST, "", CB(1), STATUS, 2, 3, 2, 21, -2, -2, 0, 0, "", "", OPTDLGID

xcall AUI, AUI_CONTROL, CTLOP_INFO, CID(2), "Do not wait for event (2)", MBST_ENABLE, MBF_CHKBOX + MBF_LFJUST, "", CB(2), STATUS, 3, 3, 3, 21, -2, -2, 0, 0, "", "", OPTDLGID

xcall AUI, AUI_CONTROL, CTLOP_INFO, CID(3), "Do not wrap (4)", MBST_ENABLE, MBF_CHKBOX + MBF_LFJUST, "", CB(3), STATUS, 4, 3, 4, 21, -2, -2, 0, 0, "", "", OPTDLGID

xcall AUI, AUI_CONTROL, CTLOP_INFO, CID(4), "Do not set focus (8)", MBST_ENABLE, MBF_CHKBOX + MBF_LFJUST, "", CB(4), STATUS, 5, 3, 5, 21, -2, -2, 0, 0, "", "", OPTDLGID

xcall AUI, AUI_CONTROL, CTLOP_INFO, CID(5), "Allow numeric input (16)", MBST_ENABLE, MBF_CHKBOX + MBF_LFJUST, "", CB(5), STATUS, 6, 3, 6, 21, -2, -2, 0, 0, "", "", OPTDLGID

xcall AUI, AUI_CONTROL, CTLOP_INFO, CID(6), "Descend into child groups (32)", BST_ENABLE, MBF_CHKBOX + MBF_LFJUST, ", CB(6), STATUS, 7, 3, 7, 21, -2, -2, 0, 0, "", "", OPTDLGID

xcall AUI, AUI_CONTROL, CTLOP_INFO, CID(7), "Allow focus on siblings of parent control (64)", BST_ENABLE, MBF_CHKBOX + MBF_LFJUST, ", CB(7), STATUS, 8, 3, 8, 21, -2, -2, 0, 0, "", "", OPTDLGID

! finish the batch

COUNT = 7 ! number of controls in the batch

Xcall AUI,AUI_CONTROL, CTLOP_EBCH,STATUS,COUNT,CID(1),CB(1)

If STATUS # 7 then goto ERROR'OUT

! Add the buttons (they could have been part of the batch, but

! here we decided to leave them out because we do not need to

! reference then directly later anyway)

xcall AUI, AUI_CONTROL, CTLOP_INFO, 0, "OK", BST_ENABLE, MBF_BUTTON + MBF_KBD, %VK_F2%", "", NOSTATUS$, 9, 4, 9, 10, -2, -2, 0, 0, "", "", OPTDLGID

xcall AUI, AUI_CONTROL, CTLOP_INFO, 0, "Cancel", BST_ENABLE, MBF_BUTTON + MBF_KBD, %VK_ESC%", "", NOSTATUS$, 9, 13, 9, 19, -2, -2, 0, 0, "", "", OPTDLGID

To query the checkboxes later, we can also use a batch operation:

xcall AUI,AUI_CONTROL, CTLOP_SBCH, STATUS ! start a batch

If STATUS # 0 goto ERROR'OUT

COUNT = 7 ! send 7 query commands...

For I = 1 to COUNT

xcall AUI, AUI_CONTROL, CTLOP_QRYCB, CID(I), "", 0, "", "", STATUS

Next I

xcall AUI,AUI_CONTROL,CTLOP_EBCH,STATUS,COUNT,CID(1),CB(1) ! finish batch

If STATUS # COUNT then goto ERROR'OUT

! CB(I) array is now set with the status of each checkbox


Get Control ID

CTLOP_GETID retrieves the ctlid of a control by its coordinates. This is useful when you know a control's coordinates, but not its ID, and you need the ID to perform some operation on it (like enable/disable). For example, you might have a form which includes INFLD fields depending on certain radio buttons, as in the example below. Here is the initial form, with the INFLD controls enabled:

this is a linked image

And here, after we change the radio button to the XLS option, we disable the controls associated with the printer:

this is a linked image

The code sample below illustrates the creation of the "Cópias" edit control (using INFLD) and obtaining its ID:

COPIES:

xcall INFLD,2,8,XMAX,XMIN,TYPE$,ENTRY,INXCTL,1,GRPID2+1,OPCODE,EXITCODE

! now get ID by its coordinates

xcall AUI,AUI_CONTROL, CTLOP_GETID,0,"",0,0,"","",CSTATUS,2,8,2,8+XMAX-1

IF CSTATUS > 0 THEN

COPIES'ID = CSTATUS

ELSE

PRINT "UNABLE TO OBTAIN ID OF COPIES EDIT CONTROL"

ENDIF

Note that the only parameters of interest in the AUI AUI_CONTROL opcode 10 are the CSTATUS (which returns the ID of the control, if found), and the coordinates. Furthermore, the control will be matched if either the starting coordinates (2,8) or the ending coordinates (2,8+XMAX-1) match the actual control.

The fact that the control can be matched by either the starting or ending coordinates is useful with INFLD controls, whose ending coordinates may be automatically adjusted due to the nature of the control type, and also with controls whose position may be based on some alignment logic, i.e. where you only know the position of the left or right edge.

Note that for debugging purposes, you can determine the internal coordinates and other parameters of all the controls by positioning the mouse on an empty spot in the current dialog or main window and using Ctrl+Shift+Double-Right-Click. This will create and launch a spreadsheet containing the details of all the controls currently defined to A-Shell.

In the above example, as the radio buttons change in the first group, we query the "Impressora" radio button to see if it is selected. If so, we enable the related INFLD controls; if not, we disable them. The logic for this (focusing just on the Copies edit control) would be similar to the following:

UPDATE'CONTROL'STATUS:

! first, query the Impressora radio button, whose ID happens to be RBID(1)

xcall AUI,AUI_CONTROL, CTLOP_QRYCB, RBID(1), "", 0, "", "", CSTATUS

! if checked (CSTATUS=1) then enable the copies edit, else disable

If CSTATUS = 0 then CSTATE = MBST'DISABLE else CSTATE = MBST'ENABLE

xcall AUI,AUI_CONTROL, CTLOP_CHG, COPIES'ID, "", CSTATE

Comment

While the example above does effectively illustrate the use of CTLOP_GETID to retrieve the ctlid of an INFLD control, the need for it could be eliminated by assigning an alphanumeric ctlid for the INFLD control when it is created (via INFLD's parentid parameter).


Set Current Tab Pane

Rewritten January 2013

CTLOP_PANE (opcode 11) is only used with Tab controls, in order to select the current pane. There are two variations, one for the traditional (standard Windows) Tab control, and one for the TabX control.

Traditional Tab (or TabX) Control:

xcall AUI, AUI_CONTROL, CTLOP_PANE, tabid, "", pane

TabX Control:

xcall AUI, AUI_CONTROL, CTLOP_PANE, tabid, paneid, cstate, NUL_CTYPE, NUL_CMD$, NUL_FUNC$, cstatus

Parameters

tabid (Num or String) [in]

id of the Tab or TabX control

pane (B,4) [in]

is the pane number (starting with 1)

paneid (String) [in]

the alphanumeric identifier for the desired pane, which may be either the pane's command string (e.g. "VK_xF302"), or the pane's label text (e.g. "&History"), or the pane number (e.g. "2"). Note that with TabX, since it is possible to insert and delete panes after the control has been created, the pane number could be subject to change, and thus the command string or label text is a more robust identifier.

cstate (B,4) [in]

may specify the optional flag MBST_SAVRES (&h80000000) in which case the current panel's controls will be saved; if there is a previously saved set of controls for the new panel, it will be restored, and the number of restored controls will be returned in the cstatus parameter, allowing you to conditionally recreate the controls. For backwards compatibility, if paneid = "", you can specify the new panel number in the low word of the cstate parameter.

Note: Since the MBST_SAVRES flag signals both the save operation (for the current panel) and the restore operation (for the new panel), if you only want one of the operations, you'll have to use the two step method (CTLOP_CLR followed by CTLOP_PANE) so that you can specify the MBST_SAVRES flag on just the one operation.

cstatus (signed numeric) [out]

will return the number of controls restored if MBST_SAVRES was specified and there was a previously saved set of controls for the new panel. Otherwise it will return 0 for success, or < 0 for an error. See Comments for more details about using cstatus with MBST_SAVRES.

Comments

In the traditional Tab control, clicking a new pane automatically selected it, so that the CTLOP_PANE operation is technically redundant, except for the need to clear the old controls from the panel. The click operation only highlights the new panel label; since all the labels share the same panel, it doesn't actually do anything to the panel itself). You may use CTLOP_CLR to clear the controls from the pane, but CTLOP_PANE also clears the controls, and thus is a better choice for compatibility with the TabX control.

In the TabX control, clicking a new pane does not automatically select it or change the display in any way. It only sends the click string, leaving it to your application to decide whether to follow through or take some other action. Unlike the traditional Tab control, the TabX control supports different colors on each panel, so auto-selecting the panel on click would cause visual confusion if the application decided to delay or prevent the panel switch (due to some data validation issue on the current panel). To follow through the with panel switch, the application must use the CTLOP_PANE operation.

In the standard/traditional scenario, switching panels always involved recreating all the controls for the new panel. However, for panels with many or complex controls, this can slow down the panel switching operation. The MBST_SAVRES option streamlines the panel switch operation by automatically restoring the controls if the target panel had previously been displayed. Rather than trying to keep track of which panels have been displayed and saved, the easiest programming approach is use the returned cstatus value to determine whether the controls need to be recreated, e.g.:

xcall AUI, AUI_CONTROL, CTLOP_PANE, tabid, paneid$, MBST_SAVRES, NUL_CTYPE, NUL_CMD$, NUL_FUNC$, cstatus

if cstatus < 1 then ! (no controls restored)

< (re)create controls for the new panel >

endif

This way, the first time you switch to a panel, the application will have to create the controls, but subsequently if you switch back to that panel, the controls will be automatically restored, allowing the application to skip recreating them.

If you don't want to use the restored controls and prefer instead to recreate them from scratch, you can use the CTLOP_CLR operation after CTLOP_PANE to remove the restored controls, then recreate them.

Since the MBST_SAVRES flag triggers both the save operation for the current panel, and the restore operation for the new panel, in order to use the save/restore feature on only some of the panels, you would have to break up the panel switch operation into two parts: CTLOP_CLR followed by CTLOP_PANE. Both operations support the MBST_SAVRES flag, but in the case of CTLOP_CLR, it only performs the save operation, while in the case of CTLOP_PANE, if the panel is already clear, the save operation is ignored and only the restore operation is attempted. So for example, to switch from a panel whose controls you do want to save, to a panel whose controls you want to recreate from scratch (i.e. not restore), use this sequence:

! save controls and then clear panel

xcall AUI, AUI_CONTROL, CTLOP_CLR, tabid, NUL_CTEXT$, MBST_SAVRES

! switch to new panel without restore

xcall AUI, AUI_CONTROL, CTLOP_PANE, tabid, paneid2$

To reverse the sequence, i.e. to switch back from the panel whose controls are not being saved, to the one whose controls you do want to restore:

! clear panel without save

xcall AUI, AUI_CONTROL, CTLOP_CLR, tabid

! switch to new panel, requesting restore

xcall AUI, AUI_CONTROL, CTLOP_PANE, tabid, paneid1$, MBST_SAVRES, NUL_TYPE, NUL_CMD$, NUL_FUNC$, cstatus

if cstatus < 1 then ! if no controls restored

<recreate controls>

endif

History

2013 January, A-Shell 6.1.1333: CTLOP_PANE now supports one-step panel switch, with optional save/restore.


Set/Clear MBF_TABSTOP Property

Added November 2013

The opcodes CTLOP_TABSET and CTLOP_TABCLR are used for setting and clearing the MBF_TABSTOP property of a control:

xcall AUI, AUI_CONTROL, CTLOP_TABSET, ctlid ! set MBF_TABSTOP for ctlid

xcall AUI, AUI_CONTROL, CTLOP_TABCLR, ctlid ! clr MBF_TABSTOP for ctlid

AUI_EVENTWAIT should skip over controls that do not have the MBF_TABSTOP property when using the keyboard navigation controls.

Note: the rules for auto-initializing the MBF_TABSTOP property when creating new controls are a bit vague; these opcodes allow you to be explicit.

Also note: the control dump contains a column making it more obvious which controls have the tabstop property, which show up with a numeric value of the control number offset by 5000. Currently there is no way to change this table order, which generally matches the order in which the controls were created.

History

2013 November, A-Shell 6.1.1368: Added opcodes to A-Shell.


ctlid

When a control is created (CTLOP_ADD), an internal numeric ID is assigned to it and returned to you. For all other operations on the control (change, delete, etc.) you typically need to specify the ID value in order to identify the control. The standard data type for a control ID is B,2. For controls that are never manipulated after creation, such as static text controls, and which will be deleted indirectly by deleting the parent dialog or group, or by using Tab(-1,0), you may not have any use for the control ID and can just specify a literal zero in its place when creating the control.

It is also possible to use alphanumeric control identifiers, in which case you can pre-establish your own ID's, possibly eliminating the need to save the ID returned from the control creation operation. Alphanumeric ID's can be up to 23 characters long, are case-sensitive, must start with a letter, and may contain letters, numbers, dashes and apostrophes. They also must be unique across all controls that exist at one time.

When you specify an alphanumeric control identifier in the ctlid parameter, the value is not updated on return from the CTLOP_ADD operation. But a numeric control ID is nonetheless assigned internally. Subsequent uses of the alphanumeric ID are internally converted to the equivalent numeric ID. Although most routines allow either the numeric or alphanumeric ID, there are some which only support the numeric ID. In that case, you can get the numeric ID by one of these methods:

• On return from the CTLOP_ADD operation, the cstatus variable will be set to the numeric ID. If successful; a value less than zero indicates an error.

• Opcode CTLOP_INFO may be used: specify the alphanumeric ID in the ctlid parameter; the corresponding numeric ID will be returned in the cstatus parameter.

See Control names for additional information on this topic.


ctext

Updated September 2010

Specifies the primary text (and/or an image specification) that will appear on or in the control. This applies mainly to simple controls like buttons, static text controls, checkboxes, edit boxes, etc. Some controls have no text (such as a rectangle or image), or have so much text (like a Tab control or dialog), that ctext or may used for some other purpose, such as to specify a title or an encoded string of additional parameters. Refer to the topics on specific control types for ctext specifications relative to those controls, in particular:

• Image Control

• Button Icon Control

• Command Link Button

• Progress Bar Control

• Tab Control

Also see the opcode table for other specific exceptions based on the opcode.

As a convenience when deleting or clearing controls, you may set ctext to "*" to delete or clear all within the specified srow, scol, erow, ecol coordinates. Or you may specify the control purely by its ctlid and omit all the remaining parameters.

To assign an Accelerator to the control, precede the desired character with an & (e.g. ctext = "Self &Destruct")

The limit on size of the CTEXT parameter is approximately 3500 bytes (1024 prior to A-Shell 1140 of March 2009). The actual limit is about 4K, less the space used for all of the other AUI_CONTROL parameters. The larger limit will be mainly useful with very large Tab controls (i.e. having many tab panes).

If ctext does not contain a trailing null byte, and it is followed immediately in physical memory by the func parameter, the last byte of ctext will be truncated.


cstate

Updated June 2016; see History

This indicates the initial state of the control (when adding) and flags which affect the change operation. The symbols come from ashell.def.

Symbol | Value | Description
MBST_ENABLE | &h000000 | Enabled.
MBST_DISABLE | &h000001 | Disable (grayed out).
MBST_HIDE | &h000004 | Hidden (invisible).
MBST_SHOW | &h000008 | Make visible (if hidden).
MBST_MINIMIZE | &h000010 | Create minimized modeless dialog. See Dialog Positioning Tip. Works with CTLOP_CHG and CTLOP_ADD.)
MBST_CENTER | &h000020 | Equivalent to MBST_HCENTER + MBST_VCENTER, which see below.
MBST_MAXIMIZE | &h000040 | (For MBF_ALTPOS dialogs only) Maximize dialog. Also see MBF_MAXBUTTON.
MBST_CHANGE | &h000080 | Change ctext and cmd. Use this with opcode 2 to update the ctext and cmd parameters associated with an existing button. Otherwise, only the button state is updated.
MBST_TEXTONLY | &h000200 | May be added to MBST_CHANGE to cause only the text of the control to be modified. This can eliminate the "flicker" that might otherwise appear as all of the attributes of the control are reset, especially when updating the title bar of a dialog.
MBST_CLREDITS | &h000400 | Operate on edit controls only.
MBST_PLAY | &h004000 | Start an AVI playing. See Animated Graphics.
MBST_STOP | &h008000 | Stop an AVI playing.
MBST_POS | &h010000 | Causes the position and size of the specified control to be updated.
MBST_STYLE | &h020000 | Used with CTLOP_CHG to change the style and alignment flags for an existing control.
MBST_CHANGEX | &h040000 | This is related to MBST_CHANGE, MBST_POS and MBST_STYLE. It affects those attributes (font, color, etc.) that were not covered by the other bits, and permits changing virtually everything about most controls (tooltips, associated images, and in most cases even the control type).
MBST_SELECT | &h080000 | This "selects" the control if the control has the design mode flag set. (Just ignore this comment as "design mode" is a long way from being usable.) Note that to unselect a control, use CTLOP_CHG with MBST_CHANGE and don't specify the MBST_SELECT flag.
MBST_ZTOP | &h200000 | These may be used to force the control to be at the top or bottom, respectively, of the "Z-order." (The "Z-order" determines the display order of controls that otherwise have the same precedence. In general, controls created later are farther down the Z-order than those created earlier. These flags would mainly be of use in situations where you have overlapping sibling controls.)
MBST_ZBOTTOM | &h400000
MBST_HCENTER | &h0800000 | These allow controls to be centered just horizontally or just vertically. (Specifying both is equivalent to MBST_CENTER.) Note that this kind of centering positions the current control relative to its parent control, or, in the case of a dialog without a parent, relative to the desktop. For example, MBST_HCENTER specified on a button within a dialog would horizontally center the button within the dialog, effectively using the scol and ecol parameters only to determine the button width. See the MBF_?CENTER flags in ctype for options controlling the centering of text (or image) displayed within the control—as opposed to the centering of the control relative to its parent. Note that for many control types, particularly image controls, effective centering generally requires both the MBST_?CENTER and MBF_?CENTER flags, i.e. centering of the image within the control and centering of the control within the parent.
MBST_VCENTER | &h1000000
MBST_CHGTIPMNU | &h02000000 | May be used with CTLOP_CHG to change just the context menu for the control. You could also do this with MBST_CHANGEX, but it effectively deletes and re-adds the entire control, creating a possible "flicker", and also requiring that you pass all of the parameters. With MBST_CHGTIPMNU, other parameters such as the coordinates, type, etc. are ignored and left alone. See sample program ICOMNUBAR[908,27] for an example of using the feature to change the enabled/disabled state of icon context menus.
MBST_NOREDRAW | &h04000000 | May be specified in a CTLOP_CHG operation to prevent the normal refresh/redraw of the client area of the TabX control. This is mainly useful for eliminating "flicker" when enabling/disabling panels other than the current one, since those operations do not really require a full refresh.
MBST_NORMALIZE | &h10000000 | May be used with CTLOP_CHG to change the state of a minimized or maximized window back to normal.
MBST_SAVRES | &h80000000 | Improve performance when switching between panels.

Hex-Decimal Values

History

2016 June, A-Shell 6.2.1427: Centering of caption-less (MBF2_DLGNOCAP) dialogs within a parent dialog now supported.


Dialog Positioning Tip

When MBST_MINIMIZE flag is specified (to create a minimized dialog), the normal position for the minimized dialog will be at the bottom left of the parent window. However, you also can force the minimized dialog to appear at the same position as the normal sized dialog by also setting the MBST_POS flag and putting the desired coordinates of the upper left corner of the minimized dialog into the upper 16 bits of the SROW and SCOL parameters. For example, if the normal position of the dialog is 8500,15 to 16500,60, but you want to initially display it minimized at 2500,62, then set your coordinates as follows:

SROW = (2500*65536) + 8500

SCOL = (62*65536) + 15

EROW = 16500

ECOL = 60

CTYPE = MBF_DIALOG + MBF_MODELESS + MBF_SYSMENU

CSTATE = MBST_MINIMIZE + MBST_POS

Note that this technique is mainly relevant for modeless dialogs with the sysmenu option (for minimize/normalize/exit buttons).


MBST_SAVRES

Added January 2013; see History

The cstate flag MBST_SAVRES (&h80000000) can be applied to the CTLOP_CLR and CTLOP_PANE operations operations when operating on TabX controls to have the client module save the contents of the panel being cleared, and restore the previously saved contents of the new panel (if available).

When switching from one TabX panel to another, the traditional protocol is to first call CTLOP_CLR to clear the controls from the current panel, then call CTLOP_PANE to establish the new panel, and finally (re)create the controls on the panel. The new feature doesn't change that logic, except as follows:

To request that the existing contents of the panel be saved before the panel is cleared, specify the cstate parameter with the MBST_SAVRES flag in the CTLOP_CLR call:

xcall AUI, AUI_CONTROL, CTLOP_CLR, tabid$, NUL_CTEXT$, MBST_SAVRES

To request that the previously saved controls for the new panel be restored, specify the cstate parameter with the MBST_SAVRES flag in the CTLOP_PANE call. To confirm whether any controls were actually saved, you should also specify up to the cstatus parameter (which will return the count of the number of controls restored):

xcall AUI, AUI_CONTROL, CTLOP_PANE, tabid$, paneid$, MBST_SAVRES, NUL_CTYPE, NUL_CMD$, NUL_FUNC$, status

if status <= 0 then ! if no controls restored

<(re)create the controls for the new panel>

endif

Notes

• You need to identify the panel to switch to by putting the panel's label text or cmd string into the paneid$ parameter (i.e. ctext), rather than putting the panel number into the cstate parameter (as in the traditional Tab control). This leaves the cstate parameter available for the MBST_SAVRES flag.

• By checking the returned status parameter, you can determine whether the restore operation was successful without actually having to keep track of whether that panel has previously been displayed and saved (or even whether the ATE client version is sufficient to support the feature).

• You must perform the CTLOP_CLR first, then the CTLOP_PANE. The reverse order is possible, but not when using MBST_SAVRES.

• The motivation behind the MBST_SAVRES feature is not to simplify your application coding; in fact, it makes it slightly more complex. Instead, the motivation is to improve the performance of switching between panels, particularly with ATE and with complex controls like XTREE and XTEXT.

History

2013 January, A-Shell 6.1.1332: Flag added to A-Shell


ctype

This specifies any valid combination of options from the following table. The symbols come from ashell.def.

Also see the ctype2 parameter.

Symbol

Value

Description

MBF_BUTTON

&h00000000

(default control type) A rectangular button, which displays a text string and is virtually always associated with a click action. See Button Control.

MBF_CMDLIN

&h00000000

(default cmd type) Clicking the control causes the contents of cmd to be executed as a Windows command line, as if it had been executed via xcall HOSTEX. See the cmd topic.

MBF_DLL

&h00000001

DLL. Clicking the button causes the function (func) with the associated DLL (defined in cmd) to be loaded and executed.

MBF_CHKBOX

&h00000004

Checkbox. Clicking on the button toggles the checkmark display, as well as the value of the one-byte parameter (0 for unchecked, 1 for checked) in func. See Checkbox Control.

MBF_3STATE

&h00000008

Three-state checkbox. Same as a regular checkbox except it has three states: unchecked (0), checked (1), and indeterminate (2).

MBF_AUTORADIOBTN

&h00000010

Radio button. Used in a group (see MBF_GROUPBOX) of two or more radio buttons. Similar to MBF_CHECKBOX except that only one may be selected at a time. Although popular in Windows forms, from a programming standpoint, they are more complex and less efficient than and INFLD combo box (which otherwise accomplishes the same task of allowing the selection of just one from a short list of choices. See Checkbox Alignment, Justification.

MBF_RADIOBTN

&h00000010

Same as MBF_AUTORADIOBTN.

MBF_VCENTER

&h00000020

Vertically center text or image within the control. Applies mainly to static text controls, which otherwise default to top alignment. Also see MBST_CENTER in cstatefor centering an entire control on its parent, and Control Alignment.

MBF_LFTEXT

&h00000020

For controls such as checkboxes, that contain a text element and some other element, specifies that the text element appear to the left of the other element. (Default is to the right.)

MBF_DLGNOPARENT

&h00000020

Force dialog box to be a child of the desktop (sibling of the main A-Shell window) rather than a child of the main A-Shell window (both of which involve setting the parentid parameter to 0).

MBF_LFJUST

&h00000040

Left justify text. (Default is center.) Note that for checkboxes, this affects only the justification of the text within the space allotted to it, not whether the text is to the left or right of the checkbox.

MBF_RTJUST

&h00000080

Right justify text. (Default is centered.) See MBF_LFJUST above. Note that for MBF_TOOLBAR, justifies the buttons within a horizontal toolbar (buttons are left-justified by default).

MBF_BITMAP

&h00000100

Use with buttons (MBF_BUTTON) or static text controls (MBF_STATIC) to display an image instead of text in the control. ctext is interpreted as the filespec (either AMOS or native) or a DLL bitmap resource (resname::dllname); supported types are BMP, JPG, TIF, PCX, PNG. For buttons, the image will be stretched to fill the button. For static controls, see MBF_NODISTORT, MBF_HCENTER, MBF_VCENTER and MBF_CENTER, and Image Control.

MBF_SYSMENU

&h00000100

For dialogs (MBF_DIALOG), this causes the dialog to sport an "X" (aka system menu) in the upper right corner allowing it to be closed by clicking on it. See Modal Dialog Box.

MBF_ICON

&h00000200

Icon. Applies to both button (MBF_BUTTON) and static (MBF_STATIC) control types. See Icon Control.

MBF_TABSTOP

&h00000400

Indicates that the control is part of the group of controls that may receive the focus by tabbing between them. This is automatic for MBF_BUTTON, but may optionally be applied to MBF_CHKBOX, MBF_3STATE, MBF_AUTORADIOBTN and MBF_STATIC controls. Currently this is only applicable in conjunction with the AUI EVENTWAIT class.

MBF_MAXBUTTON

&h00000400

For dialogs with MBF_ALTPOS and MBF_SYSMENU options set, enables the maximize button.

MBF_SEP

&h00000800

Separator.

MBF_DLGNOCREEP

&h00000800

Dialog No Creep applies to nested dialogs, forcing their coordinates to be interpreted relative to the main window, rather than to the parent dialog.

MBF_AUTOGROW

&h00000800

For static text controls (MBF_STATIC), causes the control to automatically grow as needed to contain the text. For left justified text (MBF_LFJUST), the left edge will be determined by scol, while ecol is treated only as a minimum size. (The actual right edge of the control will be shifted to the right as needed to contain the text.)

For right justified text (MBF_RTJUST), the right edge is set by ecol and expands to the left as needed (with scol establishing the minimum). The bottom edge of the control will also be shifted if necessary to contain the height of the text. MBF_AUTOGROW is not compatible with MBF_WRAP.

MBF_SUNKEN

&h00001000

For static text controls (MBF_STATIC), causes them to appear with an "sunken" edge.

MBF_READONLY

&h00001000

Read only (with MBF_EDIT).

MBF_UPDOWN

&h00004000

This is a special-purpose option. Generally you would not use this flag directly, unless you wanted to create an Up-Down control independent of INFLD. In that case, use MBF_EDIT + MBF_UPDOWN (+ any other relevant flags); set WINCLASS$ = "ASHEDIT", and WINSTYLE to any valid ES_xxx flags (Windows Edit control styles). Such a control will allow the user to change the value by clicking on the Up-Down buttons, independent of any signals or actions by the application. You would need to use the AUI_CONTROL CTLOP_INFO function to retrieve the current value of the field.

MBF_TOOLBAR

&h00008000

The Toolbar Control creates a Windows-typical toolbar across the top of the parent window.

MBF_KBD

&h00010000

Keyboard. Clicking on the control causes the contents of cmd to be forced into the keyboard buffer. See cmd for specifications and hints on how to use this technique effectively. Note that MBF_KBD is ignored if MBF_SHLEXC, MBF_CMDLIN, or MBF_DLL are set.

MBF_SHLEXC

&h00020000

Shell execute. Clicking the button causes the contents of cmd to be interpreted as an object (file or URL) to be opened using the associated application defined in the Windows Registry. See cmd notes.

MBF_STATIC

&h00040000

Static control, normally used for text prompts, but also may be used for graphic lines and images. For images, ctext is interpreted as the filespec (either AMOS or native) or a DLL bitmap resource (resname::dllname) ; supported types are BMP, JPG, TIF, PCX, PNG. See example under Add Control.

MBF_EDIT

&h00080000

Edit control (reserved for INFLD use). See Icon Control.

MBF_ALTPOS

&h00100000

Adjusts the way in which a control is positioned, with the specific effect varying by the type of control. For buttons (MBF_BUTTON) and group boxes (MBF_GROUPBOX) it causes a slight vertical adjustment (usually an improvement) in the way they are positioned and sized on the screen. See Groupbox + MBF_ALTPOS. For horizontal lines, it moves them from the center of the row to the bottom of the row. For dialogs, it switches the entire dialog (and all its child controls) to the Alternate Dialog Coordinate System.

MBF_WORD

ELLIPSIS

&h00200000

For static text controls (MBF_STATIC), if the text in ctext does not fit within the control, an ellipsis (...) will be displayed.

MBF_PATH

ELLIPSIS

&h00400000

For static text controls (MBF_STATIC), if the text in ctext does not fit within the control, it is interpreted as a path, and an ellipsis will be used for the middle portion of the path to shrink it to fit.

MBF_WRAP

&h00400000

Applies to buttons (MBF_BUTTON) only, causing text within them to wrap to multiple lines (assuming the button is tall enough). This is automatic for static controls.

MBF_

NODISTORT

&h00400000

Applies to images (MBF_ICON or MBF_BITMAP) within controls (MBF_STATIC or MBF_BUTTON) only, causing the aspect ratio of the original image to be preserved when scaling it to the size of the control. Otherwise, the image will be stretched to completely fill the control.

MBF_MODELESS

&h00400000

Mode-less dialog (with MBF_DIALOG).

MBF_DIM

&h00800000

For static text controls (MBF_STATIC), applies the equivalent of the "dim" attribute. This affects the interpretation of the foreground color (fgc) and also makes the text behave like normal fixed-pitch text with respect to protection and clearing.

MBF_LISTBOX

&h01000000

List box control. (Reserved for internal use by XTREE)

MBF_GROUPBOX

&h02000000

Creates a "groupbox", which can be used to group other controls. (Do not set MBF_STATIC!) See Groupbox Control.

MBF_FRAME

&h02000000

When used with MBF_STATIC, creates a variation of static control that has a "frame" edge, making it stand out from the background (sort of the reverse of the sunken effect.)

MBF_

COMBOBOX

&h04000000

Combo box control (reserved for INFLD use)

MBF_

UNPROTECTED

&h08000000

May be applied to buttons and other controls which are normally protected, to allow them to be cleared by opcode 4. See Clear Control.

MBF_

PROGRESS

&h10000000

Progress bar control. See Progress Bar Control.

MBF_DIALOG

&h20000000

Dialog box. See Modal Dialog Box

MBF_TAB

&h40000000

Tab control. See Tab Control, and the MBF2_TABX entry in the ctype2 table.

MBF_HCENTER

&h000000C0

Horizontal centering of control text (at to). Applies to static (MBF_STATIC), button (MBF_BUTTON) controls only, with text or images (MBF_BITMAP). For horizontal MBF_TOOLBAR controls, centers the buttons horizontally in the toolbar. See Control Alignment. Also see the MBST_?CENTER flags in cstate.

MBF_VCENTER

&h00000020

Vertical centering of control text (at left). See above comment for MBF_HCENTER.

MBF_CENTER

&h000000E0

Centering along both axes. See above comment for MBF_HCENTER.

Definition file: ashell.def


Dialog No Creep

This option (ctype MBF_DLGNOCREEP) applies only to dialogs, causing them to be positioned relative to the main window rather than relative to the parent dialog. Such nested dialogs with the same starting coordinates will have the same upper left corner position. Otherwise, dialogs are positioned relative to the parent, and are offset down and to the right by 2 times the thickness of the border, so that a series of nested dialogs will "creep" (or cascade) down to the right.

Note that MBF_ALTPOS causes the same effect (among others), as does selecting the "Windows desktop font size" option in the Dialog Sizing dialog.

Dialogs with the MBF_SYSMENU flag offer additional choices for how it responds to the user clicking on the "X" to close it. By default, that sends an Escape and leaves it to the application to close the dialog (using AUI_CONTROL opcode 3). This requires setting the MBF_KBD flag. If you set that flag and put something in the command parameter, then that string will be sent instead of the standard Escape. If you set the MBF_KBD flag but leave the command parameter empty, then dialog will close itself without sending anything to the application. This might actually be very convenient for status/info/debug dialogs that are just outputting auxiliary messages, perhaps via SCRSTS.SBX; in which case further output would just be thrown away.

SCRSTS.SBX 1.0(105) supports this capability; see the updated TSTSCR sample program (edit 104+) in [907,20] to experiment with it.)


Alternate Dialog Coordinate System

The standard A-Shell coordinate system is based on dividing the main window size by the currently defined number of rows and columns. To put it another way, the basic unit of the coordinate grid is the text-based coordinate cell size. This fact helps facilitate the coexistence of text and GUI elements on the same window, but it has two shortcomings for GUI development:

• The grid size is dependent on the actual size of the main A-Shell window, which can be easily adjusted, thus leading to a grid size that may be vastly too big or too small for a particular screen environment

• It is based on fixed-pitch fonts which have little to do with the proportional fonts used in GUI environments.

The problems become particularly noticeable with dialogs, which are typically designed to be a certain size relative to the information contained within, and not dependent on the size of the window that called the dialog. Yet, with the normal A-Shell grid system, the dialog, being just another control, uses the same grid as the parent window, making the dialog layout helplessly dependent on the user setting the main window to a reasonable size.

To overcome these shortcomings, the MBF_ALTPOS option may be specified when a dialog is created in order to have the dialog use a more flexible coordinate system which is independent of the A-Shell main window and which self-adjusts to provide a "constant logical size." This is accomplished by basing the alternate grid on the current standard GUI font size. In addition to being independent of the size of the main window, it also adjusts to the "DPI" of the Windows desktop.

The units of the alternate grid are still based on individual characters, which allows you to lay out the dialog almost as if it was a traditional text screen (where one character equals one column). Only here, we are using an "average character width." So while you can count the actual number of characters in your dialog labels to determine the sizes needed for the controls, as with "standard Windows dialogs", you need to allow enough room for the variability in character widths of variable text, since capital letters are on average twice as wide as lower case in the typical GUI font. So you cannot count on a 20 character string fitting in 20 "columns" of the dialog. But if you use mostly lower case, it should be a rough approximation, and if you allow a little extra space, your dialogs should be pretty resilient to local environment settings.

As an added bonus, this coordinate system is reasonably compatible with the old one, meaning that adding MBF_ALTPOS to an existing dialog will probably not break it, and may improve it.

There is one significant difference that must be noted when using the MBF_ALTPOS option, involving the way the height of the dialog is calculated. In the original dialog implementation, the total dialog height was based on multiplying the row height of the main window by the number of requested rows in the dialog coordinates. But this calculation included the dialog border and title bar, which reduced the usable number of rows of the dialog. A margin was added to the bottom, but the net effect is that normal dialogs have one less usable row than they ought to. And when the dialog gets too small, even that last row may be truncated. Arguably this should be fixed since it is confusing, but doing so now would probably affect too many programs.

However, when the MBF_ALTPOS flag is specified, the dialog height is calculated to take into account the border and title bar, so that you always get the full number of rows specified. For example, if a dialog was coded to start at row five and end at row fifteen, you get eleven usable rows.(In addition, there is a half-row margin at the bottom, which gives buttons placed on the bottom row of a dialog a little breathing room.)

TRMCHR.SBR is aware of this distinction, and returns the full number of rows in WINROWS when the MBF_ALTPOS flag was used to create the dialog. Otherwise, it returns one row less, which generally works but is still an approximation since the amount of space lost due to the border and title bar could amount to more than one row if the rows are short enough.

This "correction" to the height calculation of dialogs may cause your existing dialogs to appear to have an extra row at the bottom (or, if you used the BTNMNU. SBX option to put buttons on the bottom row, then the extra space will appear above that.) The TSTEVW sample program (see EXLIB) has been upgraded to deal with this by subtracting one from the height of the dialogs if you select the MBF_ALTPOS option. Another way to deal with the "correction" is to check the option on the Dialog Sizing dialog labeled "Included caption in dialog height." This, however, only applies to dialogs that were forced to use the alternate grid system (aka Windows desktop font size grid) by means of the radio button choice in the Dialog Sizing dialog. (The combination of the two options allow you to experiment with switching to the alternate grid without actually modifying any code. Once you decide you like it, you can explicitly add the MBF_ALTPOS option to your dialog settings in your code, and adjust the dialog height at the same time.)

Another minor difference when using the MBF_ALTPOS option, is that the starting row/col coordinates of the dialog are interpreted as relative to the main window, and not to the parent dialog. This only matters for nested dialogs, and allows you more flexibility in positioning such nested dialogs (which otherwise cannot start up or to the left of the previous dialog.) But since dialogs can be dragged around the screen by the user, it probably will not have any significant deleterious effect on existing dialogs that are converted to the new grid system.

Note that a nested dialog will automatically inherit the ALTPOS grid size from its parent dialog (if the parent dialog had the ALTPOS option). But it will not automatically inherit the alternate positioning logic or height calculation. That is, if the parent dialog uses MBF_ALTPOS, then any nested child dialog will automatically use the same spacing. But unless the child dialog also uses MBF_ALTPOS, its upper left corner will be positioned relative to its parent, and its bottom row usability will be related to the relationship between the row height and title bar height. Otherwise, if the child dialog does use MBF_ALTPOS, then its upper left corner will be relative to the main window and use the same height logic, and thus if it has the same coordinates as the parent dialog, it will exactly overlay it.

One additional advantage of the Alternate Dialog grid is that it allows you to create maximized dialogs, either under program (MBST_MAXIMIZE) or user control (MBF_MAXBUTTON). When such a dialog is maximized (or normalized), all of the controls scale accordingly. If the size difference between the normal and maximized state is more than 10% in each direction, the fonts will be scaled as well, as will the column sizes of any XTREE columns which have Dspmin or Dspwid Advanced Coldef Options. The fonts within XTREE controls, however, will not be resized.


cmd

This string, up to 199 characters, specifies the command, DLL, keystrokes, or object reference (according to ctype) associated with clicking on the control. The choices are:

• Windows Command Line

• Keyboard Commands

• Shell execute

• Subroutine (SBX)

See Also

• The discussion on how to use an Accelerator key

• The commentary in Modal Dialog Box Control about customizing the "X" button behavior.


Windows Command Line

(MBF_CMDLIN) When launching a Windows command line (unrelated to A-Shell, such as the Windows calculator), it is often problematic to know the fully qualified path. If the command cannot be assumed to be in the default PATH (like NOTEPAD or CALCULATOR) or in the Registry (typical for newer installations of Office applications), then you will probably have to use an environment variable and insist that it be defined. For example, you might put your utilities in an arbitrary folder but require as part of the installation procedure that an environment variable, say, ASHUTIL, be defined, then you can specify it in your command lines (e.g. "%ASHUTIL%\MYUTIL.EXE"). Or you can just require that the PATH environment variable be extended to include the directory where your special utilities are found.

Another idea would be to install any such custom utilities in a directory with a known relation to the DSKn directories. Then you can refer to it using relative notation, e.g. "..\..\ashutils\myutil.exe." (This would assume that the "ashutils" folder as a sibling to the DSKn folders.)

If you are using the command line to launch another instance of A-Shell, as with xcall HOSTEX, you can refer to the current A-Shell executable (and its current miame.ini file) via the macro symbol $ASHELL, and you can use the suffix characters available to HOSTEX. For example, "$ASHELL –e run armenu $" would launch a new A-Shell instance, run the program armenu, and suspend the current session until armenu exited.


Keyboard Commands

(MBF_KBD) Although you might find it convenient in menus to set your button or other control cmd strings to mimic what might otherwise be keypunched by the operator to make a menu selection, care must be taken to prevent the user from sending such "ordinary text" commands in the wrong context. The best way to avoid that problem is to define your keyboard cmd strings to send pseudo function key sequences. These will automatically be converted by INFLD (and other routines which wait for events, such as BTNMNU.SBR and AUI AUI_EVENTWAIT) into exitcodes, and can be processed relatively easily by other character-level input routines.

There are several formats for defining pseudo-function key sequences:

chr(7) + chr(n)

or

chr(7) + chr(250) + "####."

or

"VK_xF####"

or

"VK_xrF####"

The first format is limited to values of (n) from 1 (for F1) to 249. The last three provide a nearly unlimited range of pseudo-function key numbers and are therefore preferable. (The #### shown can actually be any number of digits. In the second format it must be terminated with a period, but not in the symbolic formats which start with "VK_".) So you can theoretically assign a different pseudo function key to every single control in an entire application, or at the very least to every control in a program. Note that in either case, if converted by INFLD or a similar routine into an exitcode, the exitcode will be the negative of the pseudo-function key number. So in the first case, the range is from –1 to –249, while in the others it is from –1 to –9999999. See Event-Driven Procedural Programming for more details on how to use this form of keyboard command string to allow a program to respond to a user clicking randomly on controls. Also see the highlighted note below.

The last format example above is equivalent to the third one, except that the presence of the "r" indicates that a right click on the field is also allowed, and if so, the exitcode value will be positive rather than negative. So, for example "VK_xrF421" will generate exitcode -421 for a left click, and +421 for a right click.

The symbolic notation is preferable to the chr(x)... notation, both for readability, and because in the ATE environment, certain control characters may have trouble passing through the data stream to the client without being filtered.

Besides the pseudo-function key sequences, there are also symbolic equivalents for most standard control character sequences. For example, a Ctrl+X can be represented by "^X" rather than chr(24). An escape character can be represented by "VK_ESC" instead of chr(27). See Virtual Key Symbolic Names for a table of all the symbolic control key definitions, and also for information on how to combine multiple control codes into a single command string.

When assigning pseudo-function key sequences to controls, avoid using exitcodes in the range of -100 to +100. Many of these are used for internal navigation and other event codes by routines such as INFLD, EVENTWAIT, XTREE and XTEXT. Exitcodes -1 thru -32 are possible exceptions. They are not used by A-Shell, but have been typically used in the past to represent function keys F1 thru Shift+F16. If you want to equate, say, a button to F5, then it might be appropriate to set cmd string to VK_xF5. The downside is that some users may have expectations for function key actions that don't match yours, which could cause them confusion. For example, some people expect F1 to bring up help, so defining a button which says "Cancel" with cmd = "VK_xF1" might not be the best idea.


Shell execute

(MBF_SHLEXC) For launching Windows commands, this method is often preferable to the Windows Command Line method discussed above, since it eliminates the problem of determining the fully qualified path for the command. Instead, you just specify the file or object reference (or URL) and Windows launches the necessary program (or gives the user a chance to specify what program goes with that file or object type.). For example, if cmd = "http://www.microsabio.com", then clicking it would launch the browser and go to the specified web page. If cmd = "mydata.xls", clicking the button would launch whatever the user’s preferred spreadsheet program was to open the spreadsheet.

If the file object specified in cmd does not contain a drive or directory specifier, then it will be assumed to be in A-Shell’s "DOC" subdirectory (e.g. C:\VM\MIAME\DOC). Otherwise, you need to specify a native pathspec (unless the file is in the system search PATH). See MX_FSPEC.


Subroutine (SBX)

(MBF_CMDLIN) If the command line starts with "SBX:", instead of treating it as an ordinary Windows command line, the specified SBX subroutine is called with the specified arguments. The complete syntax is as follows:

SBX: sbxnam, arg1, arg2,...argN

Example

"SBX:EVTMSG,Hello World"

Notes

Other than the "SBX:", this is essentially equivalent to the XFUNC syntax, but unlike XFUNC, the return value of the SBX is ignored.

Do not include any extra spaces before or after the colon and comma delimiters.

All arguments will be passed to the specified SBX module as strings. For SBXs that expect numeric arguments, this is usually not a problem because the standard parameter conversion routine will convert strings to numbers, but there could be some SBXs that make decisions about the calling arguments based on the types passed. (EVTMSG happens to be one of them; if the first argument is numeric, it is treated as the event level, else it is treated as the message.)

The current state of A-Shell or ATE is suspended while waiting for the SBX to return, so it is probably only a good idea to use this with modal functions that are reasonably limited in scope. (Using it to launch an entire application, which in turn may get nested by subsequent launches is likely to burn up a lot of stack space; using the traditional CMD = "$ASHELL ..." to launch a new instance would be preferable in that case.


Accelerator

Updated October 2013; see History

Controls that have a click action associated with them, such as cmd, may define an accelerator character by inserting a "&" in front of the desired character in the display text of the control. For example, if a button displays "Open", you can make the "O" be the accelerator character by setting the label to "&Open." Such an accelerator character allows the control to be "clicked" by the key combination alt+<char> where <char> is the designated accelerator character. (In the example just described, hitting Alt+O would act the same as clicking on the button.)

Accelerator characters will be indicated on the screen by underlining, although the underlines may not initially appear until the user hits the Alt key.

Note that in order for the accelerator to have a practical effect, the control must define some kind of action in its cmd parameter and its ctype flags must include MBF_KBD.

History

2013 October, A-Shell 6.1.1363: AUI_CONTROL refinement: controls without text, such as icons with no labels, can now still have an accelerator key by inserting it at the start of the tooltip string. For example, to use the accelerator key "H":

TOOLTIP$ = "&H Show History"

or:

TOOLTIP$ = ">&H Show History\<menu def>"

Note that the accelerator key will not display in the tooltip, so you may want to include some kind of textual hint, i.e.

TOOLTIP$ = "&H Show History (Alt-H)"


func

Func has two purposes. For type 1 (MBF_DLL), it must be a string containing the name of the function to execute within the DLL whose name was specified in cmd. For types 4 and 8 (checkboxes), it should be a B,1 variable whose value will be tied to the state of the checkbox (0=unchecked, 1=checked, 2=indeterminate). The initial value of func upon creating the checkbox will determine its initial check status. Thereafter, the value of the variable will change automatically and immediately as the checkbox is checked/unchecked.

The above technique of tying a variable directly to the checkbox state only works when the variable in memory is maintained in the same environment and context as the checkbox control. In the case of ATE, the checkbox control is on the client and the variable is on the server, so the link only works to establish the initial value of the control. After that, it is harmlessly broken, requiring you to query the checkbox value using opcode CTLOP_QRYCB.

A particular situation to avoid is creating a checkbox within an SBX, using a B,1 variable for the func parameter. When the SBX exits, the checkbox control will remain linked to the variable's address, even though that memory will have been relinquished by the SBX. To avoid this, just specify a null string ("") for the func parameter when creating a checkbox, and use CTLOP_QRYCB to query it.

Checkboxes can also be created and managed by INFLD, in which case it handles the details just described internally and interfaces with the application as if the checkbox were a Yes/No field.


cstatus

(F,6) returns a code indicating the result of the operation:

Value | Description
>=0 | OK, or for opcode 2 indicates control was previously enabled. For opcode 1, if an alphanumeric ctlid parameter is specified, cstatus will return the numeric ID of the new control.
1 | OK, or for opcode 2 indicates control was previously disabled
-1 | Add or delete control function failed
-2 | Button (ctlid or ctext) not found during change or delete operation
-3 | Out of memory (unable to allocate control storage buffers)
-4 | Exceeded maximum number of added controls. Note that in A-Shell 1166 of 21 Nov 09, the limit of 600 controls was eliminated; the control table expands as needed, without limit. This value should therefore not occur.
-5 | No control buffer allocated
-6 | Illegal opcode
-7 | Control already exists
-8 | Control update operation failed
-9 | Unable to load bitmap or icon file. Note the common error of mismatching the ctype flag (256 or 512) with image file type (BMP or ICO)
-10 | Incorrect control type for operation
-11 | No batch in progress
-12 | Illegal tab request or duplicate batch request
-13 | Parent dialog not found

ATE performance notes

If you do not care about the returned cstatus or ctlid, you can specify the cstatus variable as a null string ("") or eliminate it entirely if you do not need any of the other parameters. This prevents the routine from returning any information, eliminating the network turnaround latency (in the case of ATE) that would otherwise accompany each AUI_CONTROL operation. While small, these round-trip delays can add up, so that a screen consisting of many items might take seconds, as opposed to milliseconds, to display. Technically, each control creation operation could fail, but in practice, it is rare, as well as unlikely that your application would have a meaningful recovery planned anyway. So other than the case where you need the returned control ID for future reference, there is little practical value to the returned status. And even in the case of needing the returned control ID, you can eliminate that necessity by supplying an alphanumeric control name in place of the ID; see Control names.

A-Shell 5.1.1132 of 19 Dec 08 adds: to speed up a large sequence of menu operations over a slow ATE link, you can set the STATUS parameter to "" to eliminate the return of the status code. (Same idea as with AUI_CONTROL).

Update note - A-Shell 995.5 of September 07

Previously, ATE would not return any status information (as a bandwidth optimization strategy) if the cstatus parameter was specified as a string (typically "" or NUL_CSTATUS$). This rule has been tightened to allow strings of 2 or more bytes to be treated as valid return variables. This fixes an issue with in SBXINP.SBR involving the disabling of INFLD controls, and perhaps will avoid problems in other applications that mistakenly used a mapped string return variable for the cstatus parameter. Note that if you are counting on the non-return optimization, make sure you use "" or NUL_CSTATUS, or a string mapped as S,1, rather than just any old string variable.

Also note that this fix is on the server side and does not require updating ASHW32.EXE (except when using ATS in which case you need to update the ASHW32.EXE on the server side).


srow, scol, erow, ecol

Updated April 2015; see History

(Num) These coordinates determine the position and size of the control, based on the grid according to the following options and considerations. For controls in the main window, the units are normally based on the main window grid. For controls within dialogs, the units are normally based on the parent Dialog Grid Units. In either case, they may be specified in rows and columns (whole units), or for more precision, Millirows and Millicolumns. There are two notable exceptions, triggered by the MBF2_PIXCOORDS and/or MBF2_PIXSIZE flags in ctype2. In the case of MBF2_PIXCOORDS, the coordinates are interpreted in units of display pixels, and negative values for erow and ecol are taken as relative to the bottom and right edge of the parent control. MBF2_PIXSIZE (with or without MBF2_PIXCOORDS) causes erow and ecol to be interpreted as the height and width, respectively, of the control in pixels.

See History below for details on using negative grid coordinates to specify the control position relative to the right/bottom edges of the parent control, rather than the top/left edges.

Regardless of the units, child control positioning is always relative to the client area of the parent control, which may be determined implicitly or by an explicit parentid. Many different control types can serve as a parent control, including the Groupbox Control, Static Text Control, Tab Control as well as all kinds of dialog controls. For the main window and dialogs, there may be a small amount of internal margin, such that srow and/or scol values of 1 (or 1000 milli-units) may not be flush against the top or left edge of the parent client area. To rectify that, use the MBF2_STICKY flag. To make the right or bottom edge of the child control extend to the right or bottom edge of the parent, set the erow and/or ecol values slightly larger than necessary and MBF2_STICKY will adjust them as needed.

The position of dialog controls may be relative to the main window or to the physical screen; see Dialog Positioning for details.

For the Toolbar Control, the coordinates should be set to all zero for them to auto-adjust to the dimensions of the main window. The one exception is if you want to split a horizontal toolbar into left and right parts, in which case set ecol the ending column for the left toolbar and scol to the starting column for the right toolbar.

See Also

Alternate Dialog Coordinate System

History

2015 April, A-Shell 6.1.1407: AUI refinement: the logic that auto-deletes controls with conflicting coordinates now ignores controls belonging to a TAB control parent. The main purpose of the auto-deletion is to accommodate automatic conversion of text-based programs to GUI, but such program would not involve a TAB control, for which there is no text-based analog. On the other hand, some programs involving TAB controls might purposefully create child controls for multiple panels and AUI would have no way of distinguishing these because all the panels share the same effective parent ID.

2014 February, A-Shell 6.1.1377: AUI_CONTROL enhancement / behavioral change: negative grid coordinates are now interpreted as relative to the bottom/right edges of the parent control. When using grid coordinates, srow/scol values < 0, and/or erow/ecol values <=0 are interpreted as relative to the bottom and right edge of the parent control. This was already the case for MBF2_PIXCOORDS but now works for grid coordinates. Warning: this does eliminate an ancient but probably unused feature in which negative coordinate values were assumed to be pixels. If you want to use pixel coordinates, you should use MBF2_PIXCOORDS.

2013 November, A-Shell 6.1.1368: Introduce support for split toolbars, allow for negative erow and ecol values with with MBF2_PIXCOORDS.


Millirows

When the start row or end row coordinate of a control (created by AUI_CONTROL, AG_CONTROL, INFLD, etc.) is greater than 200, it is assumed to be in units of "millirows" (1000 to the row) rather than rows. This allows the vertical position and size of a control to be more finely adjusted than is possible with integer rows or even with the MBF_ALTPOS option.

In general you will get the same results whether you specify an srow value in units of rows or multiply it by 1000. There are some exceptions, though, where the default position of a row is adjusted up or down based on some internal logic, and in such cases, switching to millirows may defeat the internal logic, causing the line position to change more than expected. For example, with single row horizontal line controls, the default position is in the middle of a row. If you switch from, say, row 5 to millirow 5000, the second line will be half a row higher than the first. In general though, if you want to move a control up or down by a slight amount, multiply the srow value by 1000 and then offset it by some fraction of 1000. To convert erow to millirows, first add 1 and then multiply by 1000 (e.g. erow 5 is equivalent to millirow 6000).

In order for a control to occupy a single "row", its erow coordinate should be 1000 millirows higher than the srow coordinate. Some examples will make this clear:

Coordinates | Result
srow=2 : erow=2 | Control is one row high.
srow=2000 : erow=3000 | This is equivalent to the previous example. Note that when converting erow from standard rows to millirows, add 1 and then multiply by 1000. When converting srow, just multiply by 1000.
srow=2100 : erow=3100 | This is equivalent to the previous example, except that it is shifted down by 1/10 of a row (100 millirows).
srow=2400 : erow=2400 | This control is only 1 millirow high, which only makes sense in the case of lines, i.e. (SZCLASS="STATIC", DWSTYLE=SS_BLACKRECT or SS_GRAYRECT or SS_WHITERECT).

The system used here makes millirows logically analogous to pixel coordinates, except for the fact that the external leading is still subtracted from the bottom coordinate of the control. For example, consider two controls in adjacent rows. The first is specified as srow=3000 : erow=4000 and the second is srow=4000 : erow = 5000. Do the two controls touch? Normally, no. This is because we subtract the external leading from the resulting bottom coordinate. So if the external leading was 6, the two controls would still be separated vertically by 6 pixels, even though the bottom coordinate of the top control matches the top coordinate of the bottom control. This is a bit strange perhaps, but is very handy if your purpose in using millirows is simply to shift an object up or down by a small amount.

To cancel the automatic adjustment of the bottom coordinate to account for the external leading, specify the MBF_ALTPOS flag in the ctype parameter. When used in conjunction with an erow specified in millirows, the usual interpretation (i.e., causing an "aesthetic adjustment" to the size or position of certain control types) is changed to simply disable the automatic subtracting of the leading from the bottom coordinate.

The 1.0(103) update of the GUILIN sample program (see EXLIB) illustrates this difference by drawing a pair of columns made up of lines 1000 millirows high (in the lower right corner of the screen). The first column has gaps between the lines due to the leading; the second column uses MBF_ALTPOS to eliminate them. Note that we could also have eliminated them by just adding more to the erow coordinate; this is less convenient though since we would have had to query the current leading value (see MX_WINSETTINGS) and then converted from pixels to millirows (see AUI_WINDOW). (Overlapping would not matter for lines but it might for some other controls.)

Notes

• Millirow 1000 is the top of the usable area of a dialog. It might have been more logical for millirow 0 to have been the top, but this offset does provide some advantages. One is that it seems more consistent with the fact that the first row in standard coordinates is 1, not 0. This makes it somewhat easier to mentally convert from row x to the equivalent millirow (1000x), and dovetails nicely with the fact that static text is currently aligned at the top of the control area. Consequently, if you want to shift a text label up by 1/4 row, just multiply the srow by 1000 and subtract 250. Another advantage is that it eliminates the ambiguity that would otherwise arise if trying to position a control within 200 millirows of the top of a dialog. (If you needed to use a millirow value of between 1 and 200 to do that, it would have been otherwise interpreted as a standard row.)

• In the main window (i.e. not a dialog), there will be left, top, right and bottom margins which are made up of the pixels left over after determining the largest integer grid size that will accommodate the rows and columns into which the main window is divided (via Tab(-5,rows) or Tab(-6,cols)). Thus, millirow 1000, just like row 1, will not necessarily be the very top of the window. You can specify a millirow value of between 200 and 1000 to shift the control up into that margin space, although it may get clipped if your adjustment is more than the margin.


Millicolumns

Beginning with A-Shell 5.1.1139 (Feb 2009), most controls now support "millicolumns". When the starting column or ending column coordinate of a control (created by AUI_CONTROL, AG_CONTROL, INFLD, etc.) is greater than 200, it is assumed to be in units of "millicolumns" (1000 per standard column) rather than standard columns. This allows the horizontal position and size of a control to be more finely adjusted than was previously possible.

To convert a starting column coordinate to millicolumns, simply multiply by 1000. (Then add or subtract as needed to make your fine adjustments.)

To convert an ending column coordinate to millicolumns, first add 1, then multiply the total by 1000.

For example, the millicolumn equivalent of scol=5, ecol=9 is scol=5000, ecol=10000. (A coordinate whose starting and ending column is the same will be effectively one column wide when using standard column coordinates, but only one millicolumn wide when using millicolumn coordinates, hence the need for adding 1000 to the ending coordinate during the conversion.)

In the case of INFLD, which uses a maximum width (XMAX) rather than ending column coordinate, you can still specify XMAX in millicolumns, but the threshold is 1000 rather than 200. (That is, any XMAX value less than 1000 will be considered as a number of standard columns.)


fgc, bgc

Updated June 2011; see History

(Num) These parameters allow you to override the default control foreground (text) and background colors, in some cases. Some controls do not allow override colors, and most controls do not when XP Themes are active. Specify these values as –1 to use the "current" colors (if applicable to the control type), or –2 to use the default Windows colors. (The "current" colors are those that would apply to ordinary PRINT statements, i.e those set by TAB(-2,x) and TAB(-3,x) or SET TERM FCOLOR and SET TERM BCOLOR.)

To override the foreground and background colors in a non-Theme environment (such as W2000 or when Themes have been disabled), specify palette color numbers in the range of 0-15 (same as would be used with the TAB(-2,x) and TAB(-3,x) commands).

To override the foreground and background colors even when Themes are active (assuming this is even possible for the control type and Theme), do one of the following:

• Add +64 to the palette index value. For example, if 3 is the palette index for magenta, to request magenta even when it contradicts the default for the Theme, specify 3+64.

• Instead of a palette index value, specify an RGB value. RGB values are made up of 3 bytes, with the low byte representing the Red, the second byte the Green, and the third byte, the Blue values. This is most easily accomplished using hex notation, i.e. &h00bbggrr where rr, gg, and bb are the red, green and blue values, each ranging from 00 to FF. Note that this may appear to reverse the order of the rr, gg, and bb, values, but is necessary for direct compatibility with the Windows RGB format, which uses the least significant byte for the red. Also note that since an overall RGB value of between -2 and 15 might be confused with a palette index, to avoid confusion, make sure that either the blue value > 0, or the green value is > 0, or the red value > 128. You can also experiment with the RGB values and corresponding colors via the Settings..Colors dialog (click on one of the color buttons, then the "Define Custom Colors" button; as you move the pointer and slider bar, you'll see the Red, Green and Blue values appear in the boxes.

History

2011 June, A-Shell 5.1.1220.1: New pseudo RGB symbol RGB_TRANSPARENT (&h02020202) may be specified with static and checkbox/radiobutton controls to create a transparent background, providing an alternate method for making those controls blend into non-standard window background colors.


fontattr

(Num) May be used to override the default font attributes for the control. Again, as with colors, this is probably used most effectively only with static text controls. Choose one or more (sum) from the following tables. Note that these are only requests to the font mapper; if it cannot supply an exact match for the given fontface, fontscale, and fontattr values, if will supply the "closest" match. Note: this table also occurs in XTREE Param…coldef…advanced…font; change here and copy there!!!

Symbol | Value | Description
FS_UPRIGHT | &h00 | Normal upright
FS_ITALIC | &h01 | Italic
FS_UNDERLINE | &h02 | Underline
FS_STRIKEOUT | &h04 | Strikeout

Symbol | Value | Description
FA_DONTCARE | 0 | Do not care
FA_THIN | 1600 | Thin
FA_EXTRALIGHT | 3200 | Extra Light
FA_LIGHT | 4800 | Light
FA_NORMAL | 6400 | Normal
FA_MEDIUM | 8000 | Medium
FA_SEMIBOLD | 9600 | Semibold, demibold
FA_BOLD | 11200 | Bold
FA_EXTRABOLD | 12800 | Extrabold, ultrabold
FA_HEAVY | 14400 | Heavy

Note the difference between the FA_xxx symbols used here, and the similar FW_xxx symbols used by the //SETFONT GDI printing directive; the FA_xxx symbols are shifted up 4 bits (16 times) from the FW_xxx symbols.

Symbol | Value | Description
FA_GRIDWIDTH | &h8000 | This flag may be added to FONTATTR to tell the font matcher to try to match the average character width to the grid cell width. This probably only makes sense when specifying a fixed pitch font, in which case it should make the selected font match pretty closely in width to the standard non-GUI text.
FA_SYMBOL | &h20000 | Use symbol character set (instead of the ansi character set). This normally would only make sense with a fontface like "Wingdings" or "Symbol." Symbol fonts are mainly used in the context of AUI as a trick for creating buttons with graphic, without having to find or create an icon or bitmap. See the sample program SYMBOL in the EXLIB for an example.


fontscale

(Num) If specified, causes the font for the control to be scaled by the specified percentage (100=100%). This factor is applied in addition to the global font scale factor found in the Misc. Settings menu, so should only be used to adjust the font size of a particular control relative to the others.

Note that what is being scaled in this case is the point size of the font, and that may not correspond linearly to what you might expect. For example, if you want to create a static text control with double-high characters, and have specified coordinates with erow = srow + 1, you may find that a fontscale factor of 200 is bigger than you want. (Or it might fit the height but be too wide.) Some experimentation is in order here, and it is also highly recommended to be conservative (i.e. go for something smaller than the maximum size that will fit), because different resolution screens and other display parameters outside of your application’s control may affect the sizing. (It is better for a message to be slightly smaller than you wanted, than for it to be so big that it does not fit, or wraps inappropriately.)


fontface

(String) If specified, it is added to the request to the font mapper to help determine the font to be used. If left blank, the default is the font that is specified as the "GUI (Control)" font in the A-Shell Settings menu. If that is also blank (as it usually is), then the default becomes the standard Windows dialogs (aka "MS Dialog"). If a font face is specified but there is no such font defined to the system, the Windows font mapper will use its own reasoning to decide what font to use. To avoid the uncertainties that might entail, it is best to stick with fonts that are nearly universal, such as "Arial", "Times New Roman", etc. Note that a particular font face is generally either fixed pitch (e.g. "Courier New", "Lucida Console") or proportional ("MS Dialog", "Arial", etc.) Note that to request a special symbol font, such as Wingdings or Symbol, you should also set the FA_SYMBOL bit in the fontattr parameter.


tooltip

Updated December 2013

(String) If specified, and if the control is clickable, then the specified string will appear automatically just above or below the control when the mouse hovers over it for about one second. This is useful for additional explanation about what will happen when the control is clicked.

If you want to associate a tooltip with a static text control, it must have the MBF_KBD style flag and a click string defined in the ctype parameter. Otherwise the control is not really "clickable", or more precisely, the click action is ignored and so is the tooltip feature. If you want to have a tooltip even though there is no click action, the workaround is to use "VK_NULL" from the Virtual Key Symbolic Names table.

Update: Context and Hover Menus

With A-Shell 6.1.1335 of January 2013, the syntax of tooltip has been expanded for static image controls to allow for context and "hover" menus.

Tooltip only (original syntax):

tooltip

Menu only:

\menudef

Tooltip and menu:

>tooltip\menudef

This scheme, with > and \ leadins, follows the general syntax relating to tooltips and context menus supported by INFLD's hlpidx parameter.

The menudef syntax is:

\{@<attrib>\} <text>,<cmd>; ... <text>,<cmd>;

It must start with a leading backslash, followed by an optional list of attributes (which must begin with "@" and end with "\"), followed by one or more <text>,<cmd> pairs, each terminated with a semicolon. This also matches the syntax used for INFLD menu definitions, and XTREE PopupMenu definitions, except that the attribute list is new, and there are no special $cmds yet defined.

The only attribute currently supported is:

@Hover{=##}

Where the optional =## may be used to specify the millisecond hover time before the menu appears. 0 indicates that the menu should appear immediately with no hover delay; omit the =## clause for the system default hover delay (typically 400ms). If the Hover attribute is not specified, then the context menu acts like a typical one, i.e. doesn't appear unless you right click on the control.

Each <text> field contains the text to display in the menu, with an optional image specification, enclosed in vertical bars, i.e.:

|imagespec{=##}|display text

This is identical to the format supported by the AUI_MENU mnutxt parameter.

The optional =## clause at the end of the image spec specifies the size of the displayed image in pixels. The width and height of the image will be the same, so only one size value is needed.

The imagespec may be a native or AMOS-style filespec, or a DLL library reference, e.g.: "images:sunshine.ico", "exit::ashico1", "c:\img\new.png". Under ATE, if the image is not found in the specified location or default path, it will also be looked for in the ATECACHE and ATEPERMCACHE directories.

Submenus

The context menus just described may also contain sub-menus, i.e. multi-level menus. To define a sub-menu, set the <cmd> string for the parent item to "[SUB]". Indicate the end of the submenu by defining a dummy item whose <text> is "[ENDSUB]" and whose command is empty. See examples below.

Examples

Standard right-click context menu with two options and a separator between them:

TIP$ = "\Option 1,VK_xF101;-------,;Option 2,VK_xF102;"

Same menu, but with instant display as soon as mouse enters control:

TIP$ = "\@Hover=0\Option 1,VK_xF101;-------,;Option 2,VK_xF102;"

Same menu, appearing after the standard hover time:

TIP$ = "\@Hover\Option 1,VK_xF101;-------,;Option 2,VK_xF102;"

Same menu, appearing after 100 ms, and with an icon (in its default size) from the ashico1 library next to the first option and the separator removed:

TIP$ = "\@Hover=100\|gear::ashico1|Option 1,VK_xF101;Option 2,VK_xF102;"

Same as above, but with a different icon image spec, including an explicit size of 24 pixels:

TIP$ = "\@Hover=100\|gear.ico=24|Option 1,VK_xF101;Option 2,VK_xF102;"

Standard context menu and tooltip together:

TIP$ = ">Right click for options\Option 1,VK_xF101;Option 2,VK_xF102;"

Note that combining a tooltip and a menu only makes sense for the standard right-click menus. Those with the Hover option (that appear automatically) will end up clobbering the tooltip display.

Two-level context menu: The following tooltip string will define a two-level menu with the following structure:

Item 1

Item 2 > Sub-Item 1a

Sub-Item 1b

Item 3

Item 4 > Sub-Item 2a

Sub-Item 2b

TIP$ = ">tooltip string\" &

+ "Item 1,VK_xF101;Item 2,[SUB];" &

+ "Sub-Item 1a,VK_xF201;Sub-Item 1b,VK_xF202;[ENDSUB],;" &

+ "Item 3,VK_xF103;Item 4,[SUB];" &

+ "Sub-Item 2a,VK_xF301;Sub-Item 2b,VK_xF302;[ENDSUB],;"

Note that any or all of the above menu items can contain icons, just as in previous examples.

History

2014 March, A-Shell 6.1.1377: Tooltips will now automatically wrap at 600 pixels, and you now have the option of manually breaking the lines by inserting chr(13) characters. The display time for a tooltip, normally about five seconds, is also now extended by four seconds for every 100 characters past the first 100. You may extend the display time to the maximum value of 32 seconds by inserting a "+" at the start of the tooltip string. Note that the maximum tooltip length remains 400 characters.Added support for sub-menus within context menus.

2013 October A-Shell 6.1.1363: Added support for sub-menus within context menus, and also for adding an accelerator key definition within the tooltip for controls with no ctext. See Accelerator.

2013 February, A-Shell 6.1.1337: The tooltip/context menu feature supports the ability to create disabled menu items by prefixing the item's definition with "!", e.g.

TIP$ = "!Disabled item,VK_xF101;"

TIP$ += "Enabled item,VK_xF102;"

TIP$ += "!|image.ico|Disabled item with image,VK_xF103;"

There is no way to individually enable/disable such menu items without redefining the entire menu, which may call into question what the point is. I.e. why not just recreate the menu without the disabled items? A possible rationale would be in order to preserve the layout of the menus so as to make it easier for users to memorize the menu layouts.


parentid

(integer) If specified when creating a new control, the new control becomes a child of the specified control. This has two primary ramifications: 1) the coordinates of the child control are taken to be relative to the client area of the parent, and 2) such child controls will be automatically deleted when the parent is deleted or cleared. (If a dialog box is currently displayed, then the parentid of any new controls is automatically set to the current dialog box.)

Parentid, like ctlid, may also be expressed as an alphanumeric string. See ctlid for further notes, and also see Control names.

History

2006 July, A-Shell 4.9.961: Dialogs created with AUI_CONTROL may now specify a parent ID of -1 to signify that the dialog is a child of the main window. The default (0) makes the new dialog a child of the current dialog, if any.


winclass

(String) May be used, along with winstyle and winstylex as an alternate way of specifying a control type. Note that this technique is only practical for controls that do not require special processing by A-Shell. (For example, it can be used safely to create a new style of button or static text control, since these do not require any special handling other than to process their click command. But it cannot be used to create a complex control like a spreadsheet, up-down, or property sheet, since in order to be used effectively, these would require integration with other A-Shell operations.) See Lines, Rectangles and Frames and Animated Graphics.


winstyle

(integer) May be used in conjunction with winclass or ctype to specify window-style flags. This is equivalent to the "dwStyle" parameter in the WIN32 API CreateWindowsEx() function (consult the Microsoft documentation for details). As with winclass, these flags are only practical if they affect the appearance or other characteristic of the control without changing the way it interacts with the application.

Symbol | Value | Description
WS_VISIBLE | &h10000000 | The window is initially visible.
WS_CHILD | &h40000000 | The window is a child window. A window with this style cannot have a menu bar. This style cannot be used with WS_POPUP. .
WS_OVERLAPPED | &h00000000 | The window is an overlapped window. An overlapped window has a title bar and a border.
WS_POPUP | &h80000000 | The windows is a pop-up window. This style cannot be used with the WS_CHILD style.
WS_CLIPSIBLINGS | &h04000000 | Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of a child window, to draw within the client area of a neighboring child window.
WS_CLIPCHILDREN | &h02000000 | Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window.
WS_MAXIMIZE | &h01000000 | The window is initially maximized.
WS_CAPTION | &h00C00000 | Adds a title bar. Includes the WS_BORDER style.
WS_BORDER | &h00800000 | Adds a thin-line border.
WS_DLGFRAME | &h00400000 | The window has a border of a style typically used with dialog boxes. A window with this style cannot have a title bar.
WS_SYSMENU | &h00080000 | The window has a window menu on its title bar. The WS_CAPTION style must also be specified.
WS_MINIMIZEBOX | &h00020000 |
WS_MAXIMIZEBOX | &h00010000 | The window has a maximize button. The WS_SYSMENU style must also be specified.
WS_VSCROLL | &h00200000 | Used to support vertical scrolling in dialogs. The scroll bar is initially disabled, but is automatically enabled and configured as fields are added to the dialog that extend beyond the bottom of the visible dialog. Users can scroll the dialogs using the scroll bar. AUI_EVENTWAIT will also auto-scroll the dialog as needed to bring the newly focused control into view. See Dialog Scrolling.


winstylex

Updated February 2015

(integer) Another set of flags of the same type as winstyle. These correspond to the "dwStyleEx" parameter in the WIN32 API CreateWindowsEx() function.

For what it’s worth, the addition of this second set of flags is what distinguishes CreateWindowEx() from the earlier CreateWindow(); even Microsoft is guilty of not seeing far enough into the future to prevent having to add more parameters to functions over time. We have the advantage, though, of being able to use variable length argument lists, so at least we do not have to create a whole new "Ex" version of a function just to add another parameter.

Symbol | Value | Description
WS_EX_DLGMODALFRAME | &h00000001 | The window has a double border; the window can, optionally, be created with a title bar by specifying the WS_CAPTION style in the dwStyle parameter.
WS_EX_NOPARENTNOTIFY | &h00000004 | The child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
WS_EX_TOPMOST | &h00000008 | The window should be placed above all non-topmost windows and should stay above them, even when the window is deactivated. To add or remove this style, use the SetWindowPos function.
WS_EX_ACCEPTFILES | &h00000010 | The window accepts drag-drop files.
WS_EX_TRANSPARENT | &h00000020 | The window should not be painted until siblings beneath the window (that were created by the same thread) have been painted. The window appears transparent because the bits of underlying sibling windows have already been painted.
WS_EX_TOOLWINDOW | &h00000080 | The window is intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB. If a tool window has a system menu, its icon is not displayed on the title bar. However, you can display the system menu by right-clicking or by typing ALT+SPACE.
WS_EX_WINDOWEDGE | &h00000100 | The window has a border with a raised edge.
WS_EX_CLIENTEDGE | &h00000200 | The window has a border with a sunken edge.
WS_EX_CONTEXTHELP | &h00000400 | Adds a "?" button to the right end of the capture bar of a dialog; clicking the button sends exitcode -70. Note that in order to use this feature, you must specify MBF_SYSMENU but not either of the min/max buttons.

History

2015 February, A-Shell 1403: Improve operation of WS_EX_CONTEXTHELP.


ctype2

Updated March 2013; see History

This is an extension of the ctype parameter, and specifies any valid combination of options from the following table. The symbols come from ashell.def.

Symbol

Value

Description

MBF2_STICKY

&h0001

Causes child control to "stick" to the edge of the parent container, if otherwise close to or overlapping the edge. Starting with A-Shell 6.0.1261, it also applies to MBF2_DLGNOCAP dialogs. Prior to 6.1.1355, to activate, the scol coordinate must be 1. After 1355, this is still true for the left edge but stickiness can now apply to the right edge independent of the left. To stick the right edge to the parent's right edge, the ecol coordinate must be larger than the maximum coordinate of the parent.

MBF2_DLGICON

&h0010

May be used with MBF_DIALOG to cause the dialog to display the application icon on its title bar. This is equivalent to MBF_DLGNOPARENT except without the other aspects of MBF_DLGNOPARENT (i.e. retains the parent child relationship).

MBF2_PIXCOORDS

&h0020

Allows the coordinates of a control to be specified in pixels rather than in row/col units.

MBF2_PIXSIZE

&h0080

Causes erow and ecol to be interpreted as the desired control height and width (respectively) in pixels. May be combined with MBF2_PIXCOORDS, in which case srow and scol are interpreted as coordinates while erow and ecol are interpreted as height and width. As of A-Shell build 5.1.1176, may also be used with dialogs. Previously was only supported for child controls. If used with MBF_DIALOG and MBF_ALTPOS, the dialog borders and caption dimensions will be added to erow and ecol so that the resulting dialog's client area will be of the requested size; otherwise the erow and ecol will determine the outer dimensions of the dialog.

MBF2_NOTHEME

&h0100

Disables theme (visual style) for the control. In the case of MBF_GROUPBOX, this also causes the control to be manually drawn by A-Shell rather than by Windows, allowing the FGC and BGC values to be taken into account. (Otherwise, the themed version of a groupbox ignores the FGC value, and only applies the BGC value to the background of the text.) Note that for the new implementation, you must use an RGB value for FGC and/or BGC if you want custom colors. (For black, you should use &h00010101 rather than &h00000000 to avoid any confusion with palette color numbers, which range from 0-15.)

MBF2_CUSTDRAW

&h0200

Causes A-Shell to draw the control, rather than let Windows draw it. Generally this is a bad idea (a lot of work, guaranteed never to match the way Windows does it). But, sometimes it is useful, in order to implement a visual variation that Windows does not support. Currently there are only two control types this applies to: MBF_GROUPBOX (described under 1133.3) and MBF_STATIC. In the case of MBF_STATIC, the MBF2_CUSTDRAW flag allows us to create variations of the standard rectangular static control (rounded corner rectangles, ellipses, circles, and controls with a border matching the text color.) To get any of these effects, combine MBF2_CUSTDRAW with MBF2_ROUNDRECT or MBF2_ELLIPSE.

MBF2_ROUNDRECT

&h0400

Causes the corners of the static control be slightly rounded. This is only noticeable if the BGC parameter is set to an RGB value, or if the WS_BORDER flag is used.

MBF2_DLGNOCAP

&h0800

Creates a dialog with no caption. Such a dialog is effectively anchored to its parent, as if it were a child control, except that it can host its own child controls. These dialogs are positioned using the same logic as for child controls.

MBF2_ELLIPSE

&h0800

Causes the control to have an elliptical rather than rectangular shape. As with MBF2_ROUNDRECT, the effect is invisible unless you define a non-standard BGC value or use the WS_BORDER flag.

If the display width and height of an ellipse are equal, you have a circle. Unfortunately, at present, there is no good way to calculate how many columns are needed to match a particular number of rows or millirows, so circles may end up as ellipses. (Actually, you could use the MBF2_PIXCOORD flag to specify the dimensions in pixels, and that would work, but leads to a different problem which is how to calculate the desired number of pixels. (We may need to add another flag to force the width of the ellipse to match the height so that you end up with a perfect circle, regardless of the window aspect ratio or resolution.)

MBF2_RESIZE

&h01000

May be used with an MBF_ALTPOS dialog to allow it to be resized with the mouse. The range of resizing is from 50% of the original dialog size to maximized.

MBF2_STATICWIN

&h04000

Creates a static child control window that looks something like a dialog box but can be used as a variation of a group box.

MBF2_TABX

h08000

Combine with MBF_TAB (ctype) for the TabX Control variation of the Tab control. Set SBR=AUTO_TABX to automatically convert all Tab controls to TabX controls.

MBF2_NOMOVE

&h040000

Prevents a dialog from being moved. This does not interfere with the ability to minimize, maximize or resize the dialog, which are controlled by other options (MBF_MODELESS, MBF_MAXBUTTON, and MBF2_RESIZE, respectively).

MBF2_MINBUTTON

&h080000

Used with MBF_SYSMENU to add a minimize button to a modal dialog. A minimize button is not normally allowed in this case, because if the dialog is minimized, it may make the parent window appear to be unresponsive. But if you are sure that won't be a problem (perhaps you've made the dialog's parent invisible already), you can force the minimize button option with this flag (in the cflag2 parameter).

MBF2_FNTPTSIZE

&h0100000

Interpret font scale factors as points (x 10) rather than as a percentage.

MBF2_DLGMWFNTGRID

&h0100000

May be used with captionless dialogs based on the main window grid (i.e. without MBF_ALTPOS) to force the text controls within the dialog to use the same font scaling logic as the main window uses. This is mainly of use when the Misc Settings font scaling option is non-zero—i.e. when the main window controls use a font scaled to the main window grid. In particular, if you are using the MX_AUTOPARENT and AUTOTPRINT features to run a non-GUI-aware program in a dialog, this allows you to scale the dialog and the fonts within it to the main window size. Note: due to context, this function does not conflict with the one above having the same value.

MBF2_DLGSTATE

&h0200000

Can be specified with MBF_DIALOG to cause the previous last state (normal or maximized) and position of the dialog to override the state and position specified in the AUI_CONTROL statement. The saved state is keyed to the combination of the current program name and the dialog control name, so you must use an alphanumeric control name. MBF2_DLGSTATE overrides the MBST_xxxx options relating to dialog positioning—e.g. MBST_CENTER, etc. The miame.ini option OPTIONS=AUTODLGSTATE allows you to make the MBF2_DLGSTATE option be the default for all dialogs. Dialogs with the MBF2_DLGSTATE option are moved back to the default position if the previously saved position is no longer visible due to a monitor configuration change. The dialog is considered visible if enough of its caption bar is visible to reasonably be able to spot it and drag it. This allows you to deliberately set the dialog's initial position so that only a fraction of its title bar is visible. Note that MBF2_DLGSTATE overrides the MBST_xxxx options relating to dialog positioning (e.g. MBST_CENTER, etc.). Previously, MBST_CENTER would effectively override a custom saved position.

MBF2_GDIPLUS

&h00400000

Set for images using the GDI Plus library. Set automatically for some image types and mainly of internal interest; may be set manually to force images with <32 bpp to use the GDI. See Disabled and Hot Images.

MBF2_GLOBAL

&h0800000

May be specified for a clickable control to make it active even when not part of the current modal dialog. It has the additional effect of changing the default parent from the current modal dialog to the main window, if applicable. This is the only way you can create a control outside of the current modal dialog.

MBF2_NOAUTOPARENT

&h01000000

Overrides the normal logic for defaulting the parent of a new control that doesn't specify an explicit parent. Normally, if the new control does not specify a parent and a modal dialog exists, the new control is assigned that dialog as its parent. With this flag set, the main window (ctl #0) would instead become the default parent.

History

2014 Feburary, A-Shell 6.1.1376: Added MBF2_DLGMWFNTGRID

2013 July, A-Shell 6.1.1356: Added MBF2_NOAUTOPARENT

2012 May, A-Shell 6.0.1250: Added MBF2_DLGSTATE

2012 May, A-Shell 6.0.1249: Added MBF2_FNTPTSIZE


Static Text Control

UpdatedDecember 2013; see History

Static text controls are the simplest kind of controls, consisting just of a text string formatted within a rectangular area, with an optional click notification. You may adjust the font and color, but in most cases, will just want to use the default font and color to get the most uniform, Windows-like look.

In the main window, static text controls correspond to PRINT statements and use the same coordinate system. In dialogs, ordinary PRINT statements are not permitted, and multiple coordinate systems are available (see Dialog Positioning) but otherwise the following discussion applies to static text controls in all contexts unless otherwise noted.

The simple PRINT statement:

PRINT TAB(10,5);"Customer Name:";

would correspond to this static text object:

xcall AUI, AUI_CONTROL, CTLOP_INFO, ID, "Customer Name:", MBST_ENABLE, MBF_STATIC + MBF_LFJUST, "", "", STATUS, 10, 5, 10, 19

This probably seems like overkill, but before addressing that, we should first clarify some subtle distinctions between the standard text and static text control implementations.

• Because the text and GUI layers in the main window use the same coordinate system, in both cases, the message starts in the same location (row 10, column 5). Also, since we set the ending column of the GUI version to 19, both will occupy the same amount of space. (This fact is important in converting from the fixed pitch to proportional font layouts. But, although the static text control occupies the same amount of space as the text counterpart, some of that space may appear blank (depending on the size of the font and how much difference there is between the fixed and proportional font metrics for this particular string. Typically, lower case characters will take up much less space in a proportional font than in a fixed pitch font, but the reverse may be true with all upper case. So if your text prompts are all upper case, you may need to allow more room (or convert them to lower case, or add the font parameters to the AUI CONTROL call to adjust the font to fit.)

• Because the proportional version of the character string will not appear to take up the same amount of space as the fixed pitch text version, attempts to position adjacent messages based on columnar calculations will not work very well in the proportional environment. See the section on Text Message Tokenization for further comments on this.

• In the above example, we did not define a command to be associated with clicking on this static text object, but we easily could, in which case the static text object acts like a button. To define a click event, add the MBF_KBD (or MBF_CMDLIN or MBF_SHLEXC flag) to the ctype parameter and put the string to be sent (or executed) in the cmd parameter. You may also want to add a tooltip so the user knows what to expect when clicking.

• Although (in the main window) the static text object exists in a layer above the standard text layer (and thus would obscure anything below it), as a convenience, it may be deleted by the same kinds of Print Tab operations that would delete the text version.

• If your screen prompts are parameterized (loaded from a file and output using a centralized routine), then converting from the PRINT version to the AUI CONTROL version will be simple. But if you have thousands of literal PRINT statements throughout your programs, you might want to consider one of the following shortcuts:

• PRINT statements may be replaced one-to-one with TPRINT statements, which, when compiled with the /X:2 switch, are equivalent to the AUI CONTROL shown above. That is, every segment or argument to a TPRINT statement will be converted to a separate static text control starting in the position it would have in the fixed pitch environment, and occupying the same frame space (although likely with some trailing space at the right edge of the frame.) When compiled without /X:2, TPRINT statements revert to PRINT.

• PRINT statements may also be replaced with DPRINT or EPRINT statements, which are similar to TPRINT except use the MBF_SUNKEN and MBF_EDIT styles, respectively, both of which work well to separate data fields from labels.

• SET AUTOTPRINT may be used prior to running a program to automatically treat all PRINT statements like TPRINT. This method provides the fastest way to see how well your screen layouts behave with proportional fonts.

• PRINT TAB(-10,AG_CONTROL); TEXT$; chr(127) is equivalent to TPRINT TEXT$. The advantage of the AG_CONTROL approach is that it eliminates any compiler dependency (i.e. you could compile under AMOS, or use the same RUN under both AMOS and A-Shell). You would probably need to modify your AMOS terminal driver to filter out the trailing chr(127), or perhaps ideally, to send the necessary escape sequence so that an ATE client could understand the command just as A-Shell/Windows would have.

• Tab(x,y);expr$ statements may be replaced with Tab(x,y,z);expr$ where the z parameter can be used to invoke a previously defined set of attributes to associate with the string expression (converting it into a GUI control object). See MX_DEFTABXYZ for details.

Addition Static Text Control Notes

Justification: When using AUI_CONTROL, the default justification is centered, but all of the shortcuts listed above automatically set left justification. The AG_CONTROL option supports a second two-character argument of which the first character sets the style ("T" for TPRINT or "D" for DPRINT), and the second character sets the justification ("L", "C", or "R").

Auto-expand: When using AUI_CONTROL to create a static text control, you can add the MBF_AUTOGROW flag to ctype to allow the control to grow as needed (both to handle the case of unexpectedly wide characters or a dynamic/unpredictable amount of text.)

Wrap: Static text controls automatically wrap, although this is typically only applicable when using the AUI_CONTROL syntax, since it allows you to adjust the height to make room for multiple rows of text.

Font: If not specified explicitly, via the fontface, fontattr or fontscale parameters of AUI_CONTROL, the font face is set according to the global Settings > Font > Control menu option. The size (for main window static text controls) is determined by the Settings > Misc Settings Proprtional font scaling option. (If 0, it uses the standard Windows desktop font, otherwise it applies the specified scale to the grid cell size.) For static text controls within dialogs, the Settings > Dialog Sizing > Font Scaling factor is applied to the standard Windows dialog font size.

History

2013 December, A-Shell 6.1.1371: Static text controls without images can now have context menus attached, with or without the hover/auto-show feature. Use the same syntax as documented in the tooltip parameter for image controls.


Lines, Rectangles and Frames

These controls share the same STATIC class with static text controls, and are even simpler than their cousins, except that creating them requires the use of the winclass, winstyle, and winstylex parameters, which are otherwise not commonly needed.

The EXLIB sample program GUILIN illustrates most of the combinations of these control types (see the sample screen shot below), all of which are created with variations of the following code:

MAP1 DWSTYLE,B,4

MAP1 NOSTATUS$,S,1,"" ! dummy to eliminate need for returned status

. . .

CREATE'STATIC:

xcall AUI, AUI_CONTROL, CTLOP_ADD, 0, "", 0, 0, "", "", NOSTATUS$, SROW, SCOL, EROW, ECOL, -2, -2, 0, 0, "", "", 0, "STATIC", DWSTYLE, 0

In this case, since we have no doubt about the operation succeeding, and do not care about the returned ctlids, we set the ctlid parameter to a literal 0 and use NOSTATUS$ for the cstatus parameter.

The different styles of lines and boxes are accomplished by setting DWSTYLE to one of the following values (defined in ashell.def):

Symbol | Value | Description
SS_BLACKRECT | 4 | Black rectangle.
SS_GRAYRECT | 5 | Gray rectangle.
SS_WHITERECT | 6 | White rectangle.
SS_BLACKFRAME | 7 | Black frame.
SS_GRAYFRAME | 8 | Gray frame.
SS_WHITEFRAME | 9 | White frame.
SS_SUNKEN | &h1000 | Sunken.
SS_ETCHEDFRAME | 12 | Etched frame.

See the Virtual Key Symbolic Names table for conversion data.

The second set (with the "sunken" look) is accomplished by adding SS’SUNKEN to one of the above:

this is a linked image

Note that MBF_ALTPOS can be used with horizontal line controls to shift their position from the middle of the cell to the bottom of the cell. Millirows can also be used for finer adjustments; see the GUILIN sample for details.


Button Control

After static text controls, buttons are the next simplest. Essentially they can be viewed as nearly equivalent to a static text control except that it gets drawn with a box around it, and you are more obligated to define a command string to go with it. (The command string is option with static text controls, since users do not necessarily demand that all text be clickable.)

Buttons do have a couple of additional features over static text controls. One is that they have a more obviously different appearance when enabled vs. disabled, and when they have the focus, where as static text pretty much appears the same all the time. This example illustrates the different appearance of enabled, disabled, and focused buttons (in the standard XP Visual Theme.)

A second special feature of buttons is that they may display a bitmap (BMP) or icon (ICO) file in place of text. The following example shows a button displaying an icon. Note that when a button displays a BMP or ICO, the image is automatically expanded to fill the button. To help users understand what the button pictures represent, use the tooltip parameter to define a tooltip (as shown in this example).

The code to create the icon button in the above screen shot looks like this:

xcall AUI,AUI_CONTROL, CTLOP_INFO,CID,"ctlpan.ico", 0, MBF_BUTTON + MBF_KBD + MBF_ICON, "%VK_xF2%", "", STATUS, 3, 72, 4, 75, -1, -1, 0, 0, "", "Click for additional options"

Bitmap and icon images for buttons may also be loaded from DLL resources. See the topic Button Icon Control for more details.

Buttons are often grouped together using groupbox controls (which see next).

A chr(13) character embedded in the text of a button (MBF_BUTTON) will automatically enable multi-line mode (eliminating the need to remember to set MBF_WRAP at the same time).

Subtopics

Command Link Button

Add Icon or Bitmap to Button

Auto-Countdown Buttons


Command Link Button

Added September 2010

Command link buttons are a new button type, introduced in Vista, which are typically rather large and contain three sub-components:

• Main Text: a short text string comparable to the normal button text.

• Secondary Text: a longer text string with additional explanation of what the button does. This string appears in a smaller font beneath the Main Text.

• An icon: either the default green arrow pointing to the right, or a custom icon you specify. The icon appears at the left side of the button.

For example:

See the Microsoft documentation for examples and usage guidelines.

Command Link buttons are distinguished from regular buttons in AUI_CONTROL purely by the syntax of the ctext parameter, which must be as follows:

ctext = maintext$ + "|" + secondarytext$ + "~" {+ iconspec$}

The iconspec$ can be a .bmp file, a .ico file (with the standard search path, which includes the %MIAME%\icons directory), or an iconname::dllname spec. It may also be omitted (to use the default icon), but the tilde must then be the last character in the ctext string. Do not specify the MBF_ICON or MBF_BITMAP flags. The icon or bitmap will be displayed at the larger of 16x16, 32x32 or 48x48, depending on how tall the button is.

If the Command Link button style is not supported by the version of Windows (i.e. prior to Vista), then the iconspec will be ignored, and the "|" will be converted to a chr(13) and the MBF_WRAP flag turned on, so as to display the secondarytext$ below the maintext$. (So the button will still appear at least functional, if not beautiful.)

See the sample program CMDLINK.BP in [908,51] of the EXLIB for an example.

History

2010 September, 5.1.1192: added to A-Shell


Add Icon or Bitmap to Button

Added September 2010

In Windows Vista and above, you can add an icon or bitmap to any button. The concept is similar to the Command Link button, except without the secondary text (and thus may be suitable for more "normal" sized buttons.) As with Command Link buttons, they are requested purely by means of the syntax of the ctext parameter contents, which must be:

ctext = text$ + "~" + iconspec$

The syntax options for iconspec$ are the same as for Command Link buttons.

If the version of Windows does not support the feature, the iconspec$ will just be ignored.

Note that as with the Command Link buttons, the image displays on the left of the text. But here the image is allocated the entire left half of the button, while the text gets the right half. And the right side of the image will be adjacent to the left edge of the text. If you prefer some spacing between them, add space(s) to both ends of the text$ string. (The leading space provides the separate with from the image, but the trailing space will help maintain centering of the text within the button if the image option is not supported.)

See the sample program IMGTXTBTN.BP in [908,51] of the EXLIB for an example.

History

2010 September, 5.1.1192: added to A-Shell


Auto-Countdown Buttons

Added January 2017

To enable this feature, append "<##>" to the text of a button (ctype MBF_BUTTON), where ## is the desired length of the countdown in seconds. The button display will be updated each second with the remaining length of the countdown until it reaches zero. At that time, the "<##>" suffix will be removed entirely, and one of the following two events will occur:

• If the button was initially disabled (MBST_DISABLE), then it will become enabled. This might make sense in a situation where you want to prevent the user from prematurely or accidentally triggering an action with serious consequences.

• If the button was initially enabled, then the click event will be triggered.

History

2017 January, A-Shell 6.3.1542: added to A-Shell


Groupbox Control

A groupbox is a hollow rectangle with rounded corners used to group a collection of related control. In the following sample, the three buttons are grouped within a groupbox titled "Test Group."

The controls belonging to the groupbox must specify the groupbox ctlid as their parent when they are created, and their coordinates are relative to the upper left corner of the groupbox.

Groupboxes are useful in several ways:

• They provide visual organization.

• The fact that the child controls use relative coordinates allows you to adjust the position of the entire group by changing the position of the groupbox.

• The AUI_EVENTWAIT class allows the user to move among the buttons within a group, providing a simple way to wait for one of a group of option buttons.

• Grouping controls together using a groupbox allows them all to be deleted in a single step by deleting the groupbox.

• Groupboxes are needed to define more than one set of radio buttons.

Groupboxes do not have to be visible to offer all of the above features (except for the first one). Also, the child controls do not have to be confined geometrically within the groupbox. The groupbox above would work just as well if the box were invisible, and even if it was reduced to a one by one block in the upper left corner. Also, child controls may be placed on top of the border (whether visible or not). These facts come in handy when you want to have a group of buttons for control purposes, but you do not want to waste any screen space for it. For example, you can make the groupbox invisible and one row high, then put a row of buttons on that same row. Or, another common arrangement is to put a row of buttons at the bottom of a window, with just a line above it:

In the example above, an invisible group was probably created, occupying the bottom two rows of the screen. On top of the invisible group, a single line was drawn (see Lines, Rectangles and Frames), along with the buttons below it. BTNMNU.SBX can be used to create groups of buttons like this.)

A groupbox one row high still contains 4 sides, so if you want a single line like in the above example, you have to use the rectangle technique.

Subtopics

Groupbox + MBF_ALTPOS


Groupbox + MBF_ALTPOS

In the standard groupbox layout, the top border is positioned at the very top of row 1, and the bottom border is about in the middle of the bottom row. This is not always ideal, particularly when you want to put controls on every row within the groupbox. The illustration below shows what can happen. In each of the three groupboxes, the first control within is on row 2 (relative to the groupbox), and the last control is on the bottom line of the groupbox. For example, the last groupbox (Predefinir) is four rows high, with controls on rows two, three, and four. The "profile" text control and edit box on row four share the row with the bottom border of the box. The problem is that we have plenty of room between the top border and the controls in row two, but almost no room between the bottom border and the controls on the bottom row. In fact, the parts of the border are being obscured by the controls "Pré-visualizar", "Paisagem", and "Profile." Also, the buttons on the bottom are not centered vertically very well in the space between the bottom of the dialog and the bottom of the groupbox. (Note that the difference between this and the previous example above which shows a set of four buttons below a horizontal line, is that the horizontal line is positioned vertically near the top of the row, whereas the whereas the bottom border of the groupbox is closer to the bottom.

Adding the MBF_ALTPOS option to both the groupboxes and the buttons at the bottom shifts the spacing and sizing of the groupboxes and buttons, resulting the in the example below. The top border of the groupboxes has been moved down by about 1/3 of a row, and the bottom border has been down slightly less than that, resulting in more even vertical spacing between the borders and the controls within. Also, for the buttons, MBF_ALTPOS causes them to take up the entire row height, including the inter-row (aka "leading") area, and to be shifted down to take advantage of some of the margin which is added to the bottom of dialogs.


Checkbox Control

Checkboxes are the Windows GUI equivalent of yes/no questions.

Typically several checkboxes are presented as a group, either within a groupbox, or in a dialog as in this example below:

When the group of checkboxes has no other input fields which require real-time support by the application, the easiest way to implement them may be to just display them, then use the EVENTWAIT class to wait for a button action (Apply or Cancel in the above dialog), then query the buttons to see which ones are checked. In the Windows environment, you do not even need to query them, since one of the parameters passed to AUI CONTROL to create the checkbox is the actual variable which gets updated automatically as the box is checked/unchecked. But in the ATE environment, direct linkage between the checkbox on the screen and the control variable is not possible, so the technique of querying the checkboxes is more universal. See the following topic for sample code showing how to create a query a group of checkboxes like is shown above.

The other way to manage checkboxes is INFLD, which makes them act like yes/no fields from the point of view of the application. To turn an existing INFLD yes/no field into a checkbox, just add the TYPE code ||c. In this case, you will need to process exitcodes like for any other field in order to allow the user to move up and down or among the fields.

Note that although INFLD does a reasonable job of hiding the idiosyncrasies of checkboxes from the application (making them act like yes/no fields), it is hard to overlook the fact that unlike other field types, with a checkbox, the label or prompt is actually part of the control, so you need to specify it to INFLD if you want it to create the checkbox with the text. To do so, put the label text in the SETDEF parameter, and you must set the field width to accommodate the text plus the checkbox. However, as a convenience to programs that are used to displaying the field prompts in one operation, and editing the fields in another, when INFLD is given a standard one-character-wide yes/no setup with the ||c option added, it will scan the existing controls to see if this matches the left or right edge of an existing checkbox, and if so, uses the existing one rather than creating a new one. This allows you to create the checkboxes as part of your screen layout operation, but then edit them as if they were simply yes/no fields.

Subtopics

Checkbox Alignment, Justification


Checkbox Alignment, Justification

There are two parts to a checkbox control (the text label and the checkbox itself), and six ways to arrange them, as shown here (from the TSTCBZ sample program in EXLIB).

AUI_CONTROL Calls

The checkboxes in the upper group were created with these AUI_CONTROL calls:

xcall AUI, AUI_CONTROL, OPCODE, ID(1), "Left Text; Left Justify", MBST_ENABLE, MBF_CHKBOX + MBF_LFTEXT + MBF_LFJUST, CMD$, CB1, STATUS, 2, 2, 2, 24, 67, -2, 0, 0, "", "", GRPID1

xcall AUI, AUI_CONTROL, OPCODE, ID(2), "Left Text; Right Justify", MBST_ENABLE, MBF_CHKBOX + MBF_LFTEXT + MBF_RTJUST, CMD$, CB2, STATUS, 3, 2, 3, 24, 67, -2, 0, 0, "", "", GRPID1

xcall AUI, AUI_CONTROL, OPCODE, ID(3), "Right Text; Left Justify", MBST_ENABLE, MBF_CHKBOX + MBF_LFJUST, CMD$, CB3, STATUS, 5, 2, 5, 24, 67, -2, 0, 0, "", "", GRPID1

xcall AUI, AUI_CONTROL, OPCODE, ID(4), "Right Text; Right Justify", MBST_ENABLE, MBF_CHKBOX + MBF_RTJUST, CMD$, CB4, STATUS, 6, 2, 6, 24, 67, -2, 0, 0, "", "", GRPID1

xcall AUI, AUI_CONTROL, OPCODE, ID(5), "Left Text; Center Justify", MBST_ENABLE, MBF_CHKBOX + MBF_LFTEXT, CMD$, CB5, STATUS, 8, 2, 8, 24, 67, -2, 0, 0, "", "", GRPID1

xcall AUI, AUI_CONTROL, OPCODE, ID(6), "Right Text; Center Justify", MBST_ENABLE, MBF_CHKBOX, CMD$, CB6, STATUS, 9, 2, 9, 24, 67, -2, 0, 0, "", "", GRPID1

INFLD Calls

The checkboxes in the lower group were created with INFLD, which only supports four of the six possible alignments:

xcall INFLD, 2, 2, 23, 0, "||c", CB$(1), INXCTL, GRPID2+1, 2, EXITCODE, 0, 0, -1, -1, -1, "Left Text; Left Justify"

xcall INFLD, 3, 2, 23, 0, "||c|J", CB$(2), INXCTL, GRPID2+1, 2, EXITCODE, 0, 0, -1, -1, -1, "Left Text; Right Justify"

xcall INFLD, 5, 2, 23, 0, "||cR", CB$(1), INXCTL, GRPID2+1, 2, EXITCODE, 0, 0, -1, -1, -1, "Right Text; Left Justify"

xcall INFLD, 6, 2, 23, 0, "||cR|J", CB$(2), INXCTL, GRPID2+1, 2, EXITCODE, 0, 0, -1, -1, -1, "Right Text; Right Justify"

TYPE code legend: ||c is for checkbox; R reverses the normal alignment (putting the checkbox on the left and the text on the right), and |J right justifies the text. (|J is the same as setting SBR=INFLDCBRJ but has the advantage of being easy to change from one field to the next.)

INFLD uses the SETDEF parameter for specifying the text associated with checkboxes.


Radio button Control

Radio buttons are similar to checkboxes, except that within a group, only one can be set at a time, as shown in the example below:

This is a typical way of presenting a choice among several mutually exclusive options, and can be implemented using either of the techniques described above for checkboxes. (If using INFLD, use ||r rather than ||c to create a radio button field.) However, despite the obvious parallel to checkboxes, radio buttons do not correspond neatly to any legacy data entry INFLD construct, because it breaks the normal one data field to one input field correspondence.

For example, consider a payroll application that needs to know the marital status, with the choices being single, married filing together and married filing separately. Since this information is going to be stored as a single data item (probably coded as a number), it would be easiest to just prompt for the code number (1-3) while displaying a menu. To present this as a series of radio buttons, we need more screen real estate and logic to check each of the fields to see which one was selected. So, while they may look neat, they may not be that practical to implement, especially when migrating from, or trying to preserve compatibility with a text implementation of the same application. A much more natural, and legacy-friendly way to present such a choice is via a combo box.


Animated Graphics Control

Animated icons or graphics are typically used to entertain the user during an operation that takes more than a couple of seconds. They are usually stored in AVI files, which internally are made up of multiple frames of a similar image, which when "played", give the impression of a moving image. The example below shows two such frames of an AVI file that presents the appearance of the letter moving from one computer to the other:

Another common example is the "flying files" that appear when transferring a lot of files to the recycle bin. You can acquire such AVI files from various sources on the Internet, or build them yourself with AVI toolkits which are also available on the Internet. Once you have the desired AVI file in hand, you can display it using a standard AUI_CONTROL call with the following particulars:

• Set the ctype parameter to 0

• Set the winclass parameter to "SysAnimate32"

• Set the winstyle parameter to a combination of zero or more of the following flags:

Symbol | Value | Meaning
ACS_CENTER | &h0001 | Center the graphic in the specified rectangle; instead of putting it in the upper left corner. (Animated graphics do not scale.)
ACS_TRANSPARENT | &h0002 | Use a transparent background. (This is almost always desirable.)
ACS_AUTOPLAY | &h0004 | Start the graphic "playing" automatically

CTYPE = 0 ! use winclass instead of type

xcall AUI,AUI_CONTROL, CTLOP_ADD,ID,AVIFILE$, MBST_ENABLE, CTYPE, "","",STATUS,SROW,SCOL,EROW,ECOL,-2,-2,0,0,"","",0, "SysAnimate32",ACS_TRANSPARENT+ACS_AUTOPLAY,0

You can stop and start it using the CTLOP_CHG opcode with the special cstate flags MBST_PLAY and MBST_STOP, for example:

xcall AUI,AUI_CONTROL, CTLOP_CHG,ID,"", MBST_STOP

or

xcall AUI,AUI_CONTROL, CTLOP_CHG,ID,"", MBST_PLAY


Icon Control

Icon controls may be created as a variation of either the STATIC or BUTTON control types. In general you would use the STATIC type for icons that are just decorative, and the BUTTON type for icons meant to be clicked on. The following two subsections deal with the specifics of each type:

Subtopics

Static Icon Control

Button Icon Control

Icons: Static vs. Button


Static Icon Control

The STATIC version of the icon control gives you a non-scaled icon with no border, which is appropriate for displaying as a sort of logo in a dialog. This example shows a dialog with several icons, just for illustration purposes:

Static icons are created by setting ctype to MBF_STATIC + MBF_ICON, and ctext to the resource name of the icon. There are four possible sources of icon resources, each with its own syntax:

• System icon resources. These are embedded in Windows, and are referenced with a name starting with "#". As of build 919, the only ones available are shown in the example above and listed in the following table (the names are not case sensitive):

ICONAMES | Description
#HAND | Same as the MBICON'stop icon in MSGBOX. In XP, this appears as an X in a red circle.
#QUESTION | Same as the MBICON'question icon in MSGBOX.
#EXCLAMATION | Same as the MBICON'exclamation in MSGBOX. In XP, this is a yellow triangle with an exclamation mark in it.
#INFO | Same as the MBICON'info icon in MSGBOX. In XP, this is an "i" in a white caption bubble.
#WINPTR | A generic printer icon.

For example:

xcall AUI, AUI_CONTROL, CTLOP_INFO, ctlid, "#question", MBST_ENABLE, MBF_STATIC + MBF_ICON, "", "", cstatus, srow, scol, erow, ecol2

• A-Shell internal icon resources. These are icons embedded in the ashw32.exe executable, and consist of icons used internally by A-Shell, plus any third-party application icons that have been sent to us for embedded in ashw32. The syntax for these is just a string name, without the "#", such as "ACORNICON", or #dddd where dddd is the decimal icon numbe (1000+). (If we embedded an icon specially for you, we will tell you the name and/or number.)

• Icons loaded from external DLLs. In this case the syntax for ctext is "resourcename::modulename" where resourcename is a string name, such as "stop", and modulename is the name of the DLL (or other loadable module). For DLL’s, you do not need to specify the DLL extension, but the DLL file must be located in the same directory as the copy of ashw32.exe that is being launched, or else in the WINDOWS or SYSTEM32 directory. (As of A-Shell 5.1.1185 of June 2010, under ATE, such modules can also be located in the ATEPERMCACHE directory.) For example, an icon source named "document_check" in the ashico1.dll library would be referenced as "document_check::ashico1".

• ICO files. In this case the syntax for ctext is simply the filespec of the .ICO file (either in AMOS or native Windows format).

Static icons are generally not scaled to the size of the control (see next paragraph for exception). Instead, they are fixed by Windows, according to characteristics of the desktop environment. In almost all cases, this means they are 32 x 32 pixels. The two consequences of this are that the erow and ecol parameters do not matter (by convention they should probably be set to match the srow and scol parameters), and that you need to allow for adequate space for the icons in cases where the number of pixels in the window is smaller than what you designed with. For example, if the window size is about 800 x 500, a 32 x 32 icon will occupy about 1.5 rows in height and 3.2 columns in width. But the same icon in a window of 1200 x 1000 will occupy less than one row in height and about two columns in width.

The exception to the above rule is that you can force the icon to display at a particular size by setting erow and ecol to the desired height and width in pixels, and specifying the MBF2_PIXSIZE flag in the ctype2 parameter. Note that for best results, you should use standard sizes, such as 64x64, 128x128, or 256x256, since icons are typically optimized for these sizes.

Static icons in dialogs interpret a starting row of 0 as a special flag to position it with about ½ row of top margin below the title bar of the dialog. This is just about right for the typical case. (Row one puts the icon right up against the title bar, and row two would waste too much space.) The sample dialog showing the five built-in icons above illustrates this. The first four icons are positioned with srow = 0, while the last one uses srow = 1.

Subtopics

Icon Library


Icon Library

Subroutines > AUI > AUI_CONTROL > Control Types > Icon Control > Static Icon Control

Icon Library

MicroSabio provides an icon library in the file ashico1.dll, which contains the icons shown and listed below. These have been purchased by MicroSabio so they can be used, royalty-free, by A-Shell developers. While these icons are free to use, most icons are copyrighted and/or licensed and should not be used without the explicit permission of their owner. Icon collections, such as MicroSabio's, are available for purchase from many icon vendors and developers.

The library may be displayed with the sample program ICODLG, which makes use of the subroutine BTNMENU.SBX. Both files may be found in the SOSLIB. A text listing of the available icons is given after the images.

As attested to by the following historical notes, the icons have changed over the years in order to stay aesthetically compatible with the latest versions of Windows.

History

2011 March, A-Shell 5.1.1208: The standard icon set, housed in ashico1.dll, has been replaced with a new version containing "Vista-style" versions of the same icons. The new icons, which were previously available in ashico1v.dll, are quite similar to the old ones, but have a slightly enhanced style, presumably more aesthetically compatible with Vista and Windows 7. The old icon set has been renamed to ashico1x.dll, and will remain available for manual download on our website. The two dlls are otherwise identical, so they can be substituted for each other by just renaming the dll.

2008 October, A-Shell 5.1.1127: A first attempt at updating the ashico1.dll icon library to Vista has been made in the form of a new ashico1v.dll module. The new module has the same set of icon names, but most of them have been upgraded to "Vista style". The degree of backwards compatibility to XP and before has not yet been adequately tested. A new version of the icon display program, ICODLG[907,27] has been created under the name ICODLGV for testing.

this is a linked image

this is a linked image

this is a linked image

icolib4 this is a linked image

Here is a listing of the icons' names, grouped by category where appropriate.

miscellaneous

about, add, add2, copy, cut, delete, delete2, door, door2, edit, error, exchange, exit, export1t, first_aid, fit_to_size, font, forbidden, garbage, help, help2, history, import1, information, music, paste, printer3, preferences, question and answer, redo, refresh, replace, replace2, signpost, star_blue, stop, transform, transform2, undo, unknown, view, warning

arrow

down_blue, left_blue, right_blue, down_green, left_green, right_green, up_blue, up_green,

bookmark

add, delete, down, new, up

check

check, check2, checks

disk_blue

disk_blue, error, ok, warn

document

add , certified, chart, check, cup, edit, error, exchange, find, heart, info, lock, ok, out, preferences, text, view, documents

find

find, again, next, previous, text

folder

folder, folder_add

gear

gear, error, ok, pause, refresh, stop, time, gears

lightbulb

off, on,

media

beginning, end, fast_foward, pause, play, play_green, rewind, step_back, step_forward, stop, stop_red

navigate

beginning, up, up2, left, left2, end, down, down2, right, right2

notebook

notebook, notebook_preferences

photo

portrait, scenery

text

text, bold, find, italics, normal, speaker, tree, underline

window

colors, environment, gear, preferences

zoom

in, out


Button Icon Control

Button icon controls are typically used for icons intended to be clicked on to perform some action, as in this sample (TSTICB, which uses the subroutine ICOBAR. SBX):

this is a linked image

Button icons use the ctype combination MBF_BUTTON + MBF_ICON. (In most cases, you would also add the MBF_KBD type to specify a string to be sent when the button is clicked.)

Button icons can be loaded individually from .ICO files, or via resource names from a DLL. (As of build 919, they do not support the Windows internal icon resources such as "#question.") To load an icon into a button from an ICO file, just specify the ICO filespec in the ctext parameter, either using AMOS or native syntax, for example:

xcall AUI, AUI_CONTROL, CTLOP_INFO, id, ".\control panel.ico", MBST_ENABLE, MBF_BUTTON + MBF_ICON, cmd$, "", status, srow, scol, erow, ecol, -2, -2, 0, 0, "", "", grpid1

To use an icon resource from a DLL, use the same syntax as for static icons, i.e.:

xcall AUI, AUI_CONTROL, CTLOP_INFO, id, "navigate_down::ashico1.dll", MBST_ENABLE, MBF_BUTTON + MBF_ICON, cmd$, "", status, srow, scol, erow, ecol, -2, -2, 0, 0, "", "", grpid1

Unlike static icons, button icons are scaled to fit the button. However, this can sometimes result in a distorted look if the button is not square. (In the example above, the buttons are slightly taller than they are wide, which results in a slightly "squeezed" look.) To prevent that kind of distortion, you can add the flag MBF_NODISTORT, which forces it to retain the original square aspect ratio. The example below illustrates some icons from the ashico1.dll displayed as buttons with the MBF_NODISTORT flag (all except the last icon, which illustrates what it would look like without the MBF_NODISTORT.

this is a linked image

See Also

The sample dialogs under Groupbox + MBF_ALTPOS for a good example of how using an icon on a button can be much easier to understand than text in a foreign language (which may be how your application appears to even native users.)


Icons: Static vs. Button

The distinctions between icons implemented as static controls (MBF_STATIC + MBF_ICON) and those implemented as buttons (MBF_BUTTON + MBF_ICON) are summarized here:

• Icons on buttons are scaled to the size of the button, whereas icons in static controls display in their "natural" size (which in most cases is 32x32 pixels, although on an extremely low res or high res screen, or if you tinker with the Windows system parameters, it may be as small as 16x16 or as big as 64x64). Although the icon size (for static controls) is not affected by the erow and ecol parameters, we recommend setting them equal to srow and scol.

• Only buttons can load icons from individual files, whereas only static controls can load them from the internal system resources (e.g. "#INFO"). Either type of icon can load the image from a DLL.

• Static controls, including icons, may have click actions defined, but they cannot get the focus while waiting in the EVENTWAIT routine.


Bitmap Control

Updated and Reviewed June 2010

Bitmap controls are very similar to icon controls, and come in the same two flavors – static (MBF_STATIC + MBF_BITMAP) and button (MBF_BUTTON + MBF_BITMAP). The main differences between bitmaps and icons are:

• Icons (whether stored in an ICO file or in a resource) typically contain variations of themselves with different color depths and grid sizes, from which Windows will usually select the most appropriate one. Bitmaps, on the other hand, are stored with only one size, and are typically converted internally to a format appropriate for the display device.

• Icons are square, whereas bitmaps can be in any rectangular shape.

• The MBF_NODISTORT flag only applies (as of build 919) to icons.

For both bitmap and icon controls, the ctext parameter must be set to either the filespec of the image file, or a DLL resource identifier (in the format resname::dllname).

Examples

++include ashinc:ashell.def

! button with JPG bitmap loaded from file

xcall AUI, AUI_CONTROL, CTLOP_ADD, "btnCoffee", "IMAGES:COFFEE.JPG", MBST_ENABLE, MBF_BUTTON+MBF_BITMAP+MBF_KBD, "VK_xF101", NUL_FUNC$, CSTATUS, SROW, SCOL, EROW, ECOL

! static with bitmap loaded from resource called "logo1" within images.dll

xcall AUI, AUI_CONTROL, CTLOP_ADD, "stcLogo1", "logo1::images", MBST_ENABLE, MBF_BUTTON+MBF_STATIC, NUL_CMD$, NUL_FUNC$, CSTATUS, SROW, SCOL, EROW, ECOL

History

2010 June, 5.1.1183: Add ability to reference bitmap DLL resources

2007, A-Shell 5.0: Icon DLL resources supported


Edit Control (INFLD)

An edit control is a rectangle in which text may be edited. Most commonly they are used to input just a single field, limited to one line of text and a certain number of characters. Although it is possible to use the AUI CONTROL class to create an edit box (using the winclass parameter), as a practical matter, edit boxes are handled by INFLD, which takes care of the details of creating and managing the edit control and providing a single interface to the application which works in both text and GUI modes; see INFLD's type table of GUI-related Codes. For convenience, the GUI-related TYPE codes are excerpted here. For information about other INFLD control types, see Groupbox + MBF_ALTPOS, Checkbox Alignment, Justification, Date Picker Control (INFLD), Time Picker Control (INFLD), Combo Box Control (INFLD) and Up/Down Control (INFLD).

INFLD supports several TYPE codes which activate various graphic user interface features within the A-Shell/Windows (or ATE) version of INFLD.

When in GUI mode, INFLD typically assumes the form of a Windows edit control when editing, and a static text control (with sunken edges) when not currently being edited. For date and time fields, a date or time "picker" (e.g. calendar /clock) control may be used, and for fields with certain kinds of SETDEF lists, a combo box may be used. See the INFLD GUI-related Codes for more details.

Comments

The height of an INFLD control is normally a single row, except for the Multi-line Edit Control (INFLD), but the precise calculation of that row height depends on some factors which bear explaining. Mostly these involve options set in the Miscellaneous Settings and Dialog Sizing dialogs, or alternatively via the MX_WINSETTINGS function. If the Force edit box height to match combo|topic=Force Edit Boxes to Match Combo Height option is set, then A-Shell will determine the height of a standard combo box (see next paragraph) and use that for the edit box. Otherwise, the raw row height is based on the grid for the main window or dialog; see Dialog Grid Units. Then if the Allow Edit Boxes to Use Leading Space|topic=Allow Edit Boxes to Use Leading Space option is not checked, the External Font Leading will be subtracted from the height.

Unlike the edit box whose height is independent of the font, the height of combo box is determined by the height of the font associated with it. To avoid this difference resulting in differing heights for your standard edit and combo box controls, you can use the Force edit box height to match combo Height option to force the height of edit boxes to match the height of combo boxes. The combo box reference height is determined initially based on the default font for the window. However, as of 6.1.1380.0, the reference height is updated whenever an actual combo box is created. This provides the possibility of a workaround for a problem in which the font or scale characteristics of the actual combo boxes in use do not match the default font and scale. To completely take advantage of the feature, if you are using a different font or scale for your combo boxes than for your edit boxes, you should create one of the combo boxes (or a dummy, if necessary) before creating the edit boxes. This will ensure that the combo and edit box heights match.


Up/Down Control (INFLD)

The Up/Down or "Spin" (or "Spinner") control is like a regular numeric edit control, except that it in addition to the normal keyboard method of data entry, there is also a pair of up/down arrows on the right edge which allow the user to increment/decrement the value by a predetermined amount.

To create an Up/Down control, use the field TYPE ||U along with a numeric TYPE such as #. By default the increment is 1, and the range extends from 0 to 100, with the down arrow increasing the value of the field. You can change the range by specifying a string in the SETDEF parameter, formatted as follows:

/n1/n2//

or

/n1/n2/n3//

where n1 and n2 are the low and high limits of the range, and n3, if specified, is the increment (the amount of change you get with each arrow/click). Normally, the down arrow increases the value of the field, but if you want to reverse this, reverse the n1 and n2 values in SETDEF so that the high value is first.

If the preloaded value you specify in ENTRY does not fit in the range, it will be changed to the nearest range limit.

Increment values must be positive integers, but the either or both of the range limits may be negative.

Note that the increment value only affect that amount of change when you click on the arrow; it does not prevent numbers that are within the range but not multiples of the increment from being entered. For example, if SETDEF = "/-20/50/10//", the range is from -20 to 50, and the increment is 10. But the user may keyboard in a value such as 13. In that case clicking on the up/down arrows will increment/decrement the field by 10 (i.e. to 3 or 23 in this case).

Up/Down controls revert to the form of a regular edit control when not active.

Note that the Up/Down control is internally separate from the edit control. This is probably of no concern to anyone except that it will show up in a control dump, independent of the associated edit control.

History

2006 September, A-Shell 4.9.967: Up-Down controls now preserve their Up-Down buttons even when the field is not active. (Previously they reverted to ordinary edit controls when not active.) Note that if you click on one of the Up-Down buttons while the field is not active, it will trigger the click string for the field, but not increment or decrement the field value. (This is deliberate to avoid the possibility that your application may decide not to respond to the click string by enabling the field, thus giving the user the false impression that the field value had actually been updated.) Although this will be a slight annoyance, it is no worse that before (where you had to click the field to activate and display the Up-Down buttons before the field could be changed), and has a somewhat better visual aesthetic.


Multi-line Edit Control (INFLD)

A multi-line edit control is a special case of the standard edit control. See types |M and ||M and ||H in the table above for notes on implementing one. A sample is shown below. Note that although this is a convenient way of editing and displaying a free format block of text, it is suitable for a maximum of about 1600 and has various other limitations. For a more powerful text editing control, see XTEXT.

The SCRSTS.SBX subroutine uses a multi-line edit control in display-only mode to implement a scrolling status window. It is available, along with sample programs, from EXLIB.

Note that when INFLD is in multi-line mode (|M or ||M) and up/down exits are enabled (3 and 5), and is not using Windows keyboard conventions (i.e. not specifying |K), then the Up/Down Arrows will cause INFLD to exit if used when the cursor is already on the first or last line of the control. Note that the last line is defined as the line containing text.


Combo Box Control (INFLD)

A combo box is another compound control type, made up of an edit control and a drop-down list box. As with other variations of edit controls, they are managed by INFLD rather than by the AUI CONTROL class. The example below shows two combo boxes, one in the display state and the other being edited and with the drop-down list extended.

Thanks go to Jorge Tavares for the example above, which besides illustrating combo boxes, also illustrates the use of a button as the label or prompt associated with the combo box. In this case, clicking on the button pops up a dialog, allowing the qualified user to edit the list of items available to be chosen in the drop down list.

There are a number of variations of combo boxes. In the default state, you can freely type in the edit box. (Whether or not INFLD allows you to exit the field after entering a value not in the list depends on whether you add the TYPE ||s, or include a wildcard "*" in your SETDEF list.) As with other INFLD fields, TYPE O may be added to make the field optional, i.e. to allow a blank entry. If you want to limit the operator to just selecting values from the list (either by displaying it and clicking on an option, or by typing one or more characters and using the auto-selection logic), then add TYPE code ||S.

The width of the drop-down list will be increased beyond the XMAX value, if necessary to accommodate the longest choice (as specified in the SETDEF parameter). This allows you to have longer, more descriptive choices in the drop-down list than the field allows for. A good example of this would be a 2-character state abbreviation field, which you can now link to a list of choices such as ",CA California, MN Minnesota,," etc. In this case the user will be able to see the full descriptions, but the data returned to the program will be limited by XMAX (i.e. to just the 2 character state abbreviation).

There is no set maximum to the number of characters (or number of choices) that can be displayed in the drop-down list, but once it gets beyond a few thousand bytes or a few hundred entries, you will probably want to consider another method, such as XTREE, or perhaps a Self Service Combo Box.

Also see the comments below Edit Control (INFLD) for details on how the height of a combo box is determined.

Subtopics

Text Mode Compatibility

Coded Lists

Self Service Combo Box


Text Mode Compatibility

INFLD supports most of the combo box-related TYPE codes even in text mode, only in that case, instead of a combo box like shown above, you get a normal looking field, with a display of the list of options along the bottom line of the screen. (The display can be turned off with TYPE s.) This is a good example of a GUI enhancement that you get with INFLD without any programming changes, simply by activating GUI mode (with |G).


Coded Lists

Often, if a list has only a limited number of items, and especially if the description of those items might be lengthy, it makes more data processing sense to store the selected item as a coded number, rather than as text. For example, the program shown above (Combo Box Control (INFLD)) actually stores the choices for the Zona field as a B,1 value, maintaining a table which translates the numeric codes into the descriptions which are seen above. Rather than having to do this work separately, you can let INFLD manage the table by adding TYPE ||L, and specifying SETDEF as a list of pairs, i.e.

SETDEF=",01,Norte,02,Centro,03,Sul,04,Pink Zone,05,Hot Zone,06,Ozone,,"

In this case, INFLD displays just the descriptions, but returns to the program the numeric codes (in other words, letting the user and the programmer have it their own way.)

A sub-variation of the above causes INFLD to return both parts of the pair, i.e. "04,Pink Zone" if TYPE ||l (lower case L) is used instead of ||L.

Since INFLD typically trims the XMAX value to be no greater than the physical size of the ENTRY parameter, you may need to map the variable used for the ENTRY parameter large enough to display the descriptions in the coded list (rather than just large enough to hold the coded values).


Self Service Combo Box

Another variation of a combo box is where you want to present the user with the appearance of there being a combo box to select from, but you do not want to specify the choices in advance. One reason might be that the choices are actually all the records in a file, and rather than fetch them in advance, you want to allow the user to enter a couple of characters to limit the number of choices, then presenting them in an XTREE control (which is equipped to handle thousands of entries, unlike the combo box). To get this effect, specify SETDEF="..." (3 dots). INFLD will then return EXITCODE 29 to the application when the user clicks on the DownArrow button or hits a key that would normally display the list (including the DownArrow key)


Date Picker Control (INFLD)

A date picker is a special kind of edit control designed only for the input of dates. It is created automatically by INFLD when called on to edit a date field (TYPE D) in GUI mode (|G). (It is not activated in the "lesser GUI mode", which you get with TYPE |g.) In the first example below, the field is being edited, but unlike with a normal field, the control selects one sub-field (month, day, or year) to edit at a time. You can either type digits, or use the Up/Down Arrows (or +/- keys on the numeric pad) to increment/decrement the value. Use the RightArrow to move to the next sub-field.

If the date is optional (XMIN=0), a checkbox will appear. If unchecked, the date is grayed out and unavailable. To change it, first check the checkbox:

To display the calendar, click on the DownArrow button, or hit Alt+DownArrow:

The format used by the date picker for editing and display is based on the localization settings of the client PC. But the format returned to the application is based on the INFLD TYPE codes and XMAX value. With XMAX=6, only 2 digits of the year are turned. With XMAX=8, the entire CCYY is returned. TYPE D uses American format (MM/DD/{CC}YY), TYPE U forces European (DD/MM/{CC}YY) format, and TYPE u selects the format from the language definition file (e.g. ENGLSH.LDF[1,6]). TYPE > forces the date to be returned in CCYYMMDD format (most convenient for sorting, independent of country format).

See Month Calendar Controlfor information on using the calendar control independently of an INFLD date field.

Comment

If you would like to implement your own date picker (i.e. your own calendar display associated with the INFLD date field), use the "lesser GUI mode" (|g) and set the SETDEF parameter to "...", which will give you an INFLD date control which returns to you with EXITCODE=29 if the user clicks on the DownArrow button. You can then pop up whatever kind of display you like to help the user select a date.

Or, to use the edit part of the date picker control, but replace the drop-down calendar part, use |G with ||v (and set setdef = "..." as above).


Time Picker Control (INFLD)

A time picker is similar to a Date Picker Control except for time rather than dates. (Use INFLD TYPE t or ||t.) As with the date picker, the editor selects one sub-field at a time for editing (hour, minute, second) and you can edit it either by typing or by clicking on the Up/Down Arrows.

time1.

The format used by the control for editing and display is based on the localization settings for the workstation, but the format in which the field is returned is determined by the TYPE code and XMAX values. With TYPE t, the time is returned in military (24 hour) format. With TYPE ||t, the time is returned in 12 hour format with AM/PM appended. In both cases, setting XMAX to 5 will eliminate the seconds from the returned time string. (Otherwise 8 is the normal XMAX value.)

Notes

The time picker control bases its format on MAXCHARS rather than XMAX, allowing you to use XMAX to set the physical display width of the field. In this case you may want to use TYPE ||] to defeat the automatic widening of the field to accommodate the extra formatting features of the time picker. (This behavior matches the date picker and other field types as well.)

If TYPE O (optional) or XMIN=0, the time field will have a check box allowing you to select whether the field is to be valid or not.


Month Calendar Control

Updated April 2011

The month calendar control is essentially the same as the calendar that appears in a date picker when you press the dropdown button, but is not associated with an input field, thus making it suitable to just place in a window/dialog as a convenience to the user in applications that involve dates (like scheduling). In comparison to the generic date/time dialog (the one you get by double-clicking on the system time display), this one has the advantage of being visually more compact, as well as providing some degree of application control. For example, you can:

• generate a key click string/exitcode when the user changes the date

• query or set the selected date (independent of the system date)

• you can set limits on the range of dates that can be selected or displayed

• highlight individual dates

To create a calendar control, use the following syntax:

xcall AUI, AUI_CONTROL, CTLOP_ADD, id, ctext$, MBST_ENABLE, ctype, cmd$, func$, cstatus, srow, scol, erow, ecol, fgc, bgc, fontattr, fontscale, fontface$, tooltip$, parentid, "ASHMONTHCAL", winstyle, winstylex

See Operations for tips, examples, and more information. Also see the sample program MONCAL.BP in the EXLIB for a simple working example.

Parameters

Option | Description
ctext$ | generally ignored when creating a calendar, unless you specify a WINSTYLE that creates a title bar. CTEXT$ is however used with the CTLOP_CHG opcode to set the date or day states.
ctype | may be set to 0, unless you want to enable a click string, in which case specify the MBF_KBD flag.
cmd$ | may specify a standard key click string (if MBF_KBD specified). If so, then clicking on a date will send the click string. Unless the MCS_DAYSTATES option is specified in WINSTYLE, advancing to another month does not trigger the click string.
func$ | ignored
cstatus | standard return codes (0=ok)
position | See topic of this name.
<ignored> | fgc, bgc, fontattr, fontscale, fontface$
tooltip$, parentid | work as usual.
winclass | must be specified as "ASHMONTHCAL". This replaces the fact that we didn't specify a control type in ctype.
winstyle | may be used to specify additional style options relating to the window wrapper for the control, as well as options specific to the calendar. See winstyle table for options, values and descriptions.
winstylex | may optionally have additional extended window styles: use WS_EX_TOPMOST (&00000008) to force on top (of its siblings)

History

2011 April, A-Shell 5.1.1212: The month calendar control now supports multiple calendars in a single control—i.e. multiple months showing at a time. Because it is difficult to know how big the control coordinates must be in order to display a specific number of calendars, you may now replace the lower right coordinate (erow,ecol) with the number of rows and columns, respectively, of calendars to display, provided that the MBF2_PIXSIZE flag is specified in the ctype2 parameter. For example, srow=1, scol=50, erow=1, ecol=2 will create a control with two calendars side by size, starting at position 1,50. (If the two calendars would extend off the edge of the parent window, the starting coordinates will be adjusted so that the entire calendar fits in the window.)

Note that the day states feature (MCS_DAYSTATES) is not compatible with multiple calendars.

The MONCAL test program in [908,42] of the SOSLIB has been enhanced to illustrate the new technique.

Subtopics

position

winstyle

Operations


position

Because the control size is fixed by the system (based on system display parameters), it doesn't make much sense to specify an arbitrary rectangle—although you can, with unpredictable results. Typically, you want the control to be stuck in one of the four corners of the window or dialog, or at least up against an edge. To accomplish this, A-Shell will apply certain logical rules to the coordinates given. The first rule is that if you ask for a size that is less than the minimum width and height needed to display one month, it will be automatically expanded as needed. To take full advantage of this, just set the erow, ecol parameters to match the srow, scol. For example, to put it in the upper left, set the coordinates to 1,1,1,1. The second rule is that if the starting position specified is beyond the width or height of the window, it will be moved to fit. So to position the control in the bottom corner, specify numbers that you know are larger than the size of the window, like 100,100,100,100. (Note that if you specify a row greater than 200, millirows are assumed, which means you would need to specify a much larger value.) With these rules, you can position the control in each of the four corners as follows:

Position | Values
Top left | 1,1,1,1
Top right | 1,100,1,100
Bottom left | 100,1,100,1
Bottom right | 100,100,100,100

Even with this simplification, you still need to deal with the fact that the actual size may be smaller or larger than you are expecting in terms of the row/column coordinates used for other controls. (This problem is minimized if you use MBF_ALTPOS since at least then the units are based on the font size and resolution, giving the calendar a predictable size of about 6 rows and 17-20 columns, depending on the display options.) But if your dialog grid is based on the main window, then the size of the main window will determine how many rows and columns are actually occupied by the calendar.)

If you specify a rectangle that fits in the window and is large enough to show more than one month, the control will display as many months as it can. (This is not recommended though, as no consideration has yet been given to the special issues that may arise. In particular, the day states option only works for single-month-at-a-time calendars.)


winstyle

This parameter may be used to specify additional style options relating to the window wrapper for the control, as well as options specific to the calendar:

Option | Value | Description
MCS_DAYSTATE | &h0000001 | Enable day state highlighting; see next topic.
MCS_WEEKNUMBERS | &h0000004 | Show week numbers in calendar.
MCS_NOTODAYCIRCLE | &h0000008 | Don't circle today's date.
MCS_NOTODAY | &h0000010 | Don't show today's date at bottom of calendar.
WS_BORDER | &h0800000 | Put a thin border around it.
WS_DLGFRAME | &h0400000 | Put a dialog-style border around it.
WS_CAPTION | &h0C00000 | Add a title bar; allows dragging.
WS_SYSMENU | &h0080000 | Add an X button to close calendar.
WS_VSSCROLL | &h0200000 | Adds a vertical scroll bar to the dialog; see Dialog Scrolling.

WS_THICKFRAME (&h040000) may be added to the WINSTYLE parameter when creating static controls to give them a raised panel effect. This is the visual reverse of WS_EX_CLIENTEDGE. It isn't clear whether any other control types can benefit from this option, but it probably won't hurt to try.


Operations

Retrieve Date

To retrieve the selected date (either in response to receiving the click string or exitcode, or whenever you like), use CTLOP_QRYCB (5) opcode to query the control. This opcode was previously only used for querying a checkbox, but takes on a slightly different meaning here:

xcall AUI, AUI_CONTROL, CTLOP_QRYCB, id, ctext$, cstate, ctype, cmd$, "", cstatus

Set id to the id number of the control (as returned from the CTLOP_ADD) operation. The currently selected date will be returned in cstatus as a number with the following format: CCYYMMDD. (You can convert it to a string and parse it out into subfields as you like.) The ctext$, cstate, ctype, and cmd$ parameters are ignored.

Set Date

To set the date in the calendar, use the CTLOP_CHG opcode and put the date (in CCYYMMDD format) into the ctext$ parameter, as if you were changing the text of a control. Set the cstate parameter to MBST_TEXTONLY:

xcall AUI, AUI_CONTROL, CTLOP_CHG, id, ctext$, MBST_TEXTONLY

Set Limits

To limit the calendar to a range of dates, Use the CTLOP_CHG operation as for setting the date, except format the ctext$ parameter as a 17 byte string of two dates in CCYYMMDD format with a dash in between, for example:

CTEXT$ = "20050120-20070630" ! range of 15-Jan-05 thru 30-Jun-07

xcall AUI, AUI_CONTROL, CTLOP_CHG, ID, CTEXT$, MBST_TEXTONLY

Set Day States

As an added feature, you can force selected dates to be shown in bold. To do so, specify the MCS_DAYSTATES flag (in the winstyle parameter) when creating the control. You must then send a string of 0's and 1's to the control to update the day states for the current month when the control is first displayed and whenever the month changes (which will require you to respond to the click code). Set the ctext$ parameter to a string 31 digits long, representing the days 1-31 of the current month. (Set any extra days to 0). 0 indicates the normal state, and 1 the bold state. Then use the same CTLOP_CHG format as shown above for setting the date. The control will determine which attribute you are setting by the fact that the ctext$ string is exactly 31 bytes long. For example::

CTEXT$ = "1000000000000010000000000000000" ! bold 1st & 15th

xcall AUI, AUI_CONTROL, CTLOP_CHG, ID, CTEXT$, MBST_TEXTONLY

Note that this mechanism currently is only supported for one month at a time (so see the discussion above about specifying the coordinates to make sure that the control is not big enough to show multiple months).

Visibility Issues

The calendar control, when positioned on top of another control in the same window, allows the control underneath to "bleed" through (both visually and when processing mouse clicks). (This is just a Windows quirk of that control.) The normal way to avoid such problems with it is to not position on top of another control (seems reasonable), or, if you insist, then first enclose it in a separate dialog. However, if neither of those options is desirable, yet another possibility is to remove the child flag from the control, so that it acts like a top-level popup or overlapped window. To do so, add the WS_VISIBLE flag, and optionally, the WS_POPUP flags in the dwStyle parameter. (e.g. DWSTYLE = WS_CAPTION + WS_SYSMENU + WS_VISIBLE). This essentially turns the calendar control into its own dialog, which has its own downsides (affecting the positioning and also making it difficult to use in conjunction with another control to receive the date clicked on), but for cases where you just want to have a floating calendar handy, this may be an easier technique than manually creating your own modeless dialog to house the calendar control.

The reason why adding WS_VISIBLE removes the child flag (WS_CHILD) is that if neither WS_VISIBLE nor WS_CHILD are specified, both are turned on by default. Turning on the visible flag explicitly removes the default.


Modal Dialog Box Control

Updated December 2013; see History

A "modal" dialog (MBF_DIALOG) is a popup window that holds on to the keyboard focus, making it impossible to type in any other window owned by the current application, until the modal dialog is closed. You can, however, drag the dialog around, access the main A-Shell menu bar, and even pop up nested modal dialogs. They are quite handy when you want to interrupt the context of the current operation to display or input a collection of related fields.

When creating a dialog box, you should save its ctlid parameter so that it can be used later with opcode CTLOP_DEL to delete the dialog box. Deleting the dialog box will automatically delete the controls within it.

Once a modal dialog is opened with A-Shell, any subsequently created child controls (buttons, static text, edit prompts, etc.) will be, by default, owned by the dialog box, and their coordinates will be taken as relative to the dialog box. (In other words, the parentid parameter will automatically be set to the dialog box ctlid.) However, it is probably still a good idea for you to manually set the parentid , as it probably will make your programs easier to follow, and will be indispensable if you want to implement a text version of a dialog using MSBOXX. Ordinary text output (e.g. PRINT statements, unless SET AUTOTPRINT is enabled) will ignore the dialog box and appear in the main A-Shell window. (In other words, you can only place Windows control-objects within these dialog boxes.)

Typically, a dialog box should have one or more buttons which notify the program (via a keyboard sequence) to close the dialog (for example, "OK", and "CANCEL"). You may also include an "X" in the upper right corner of the dialog by adding the MBF_SYSMENU flag to ctype, which the user can click on to close the dialog.

Note that clicking on the "X" to close a dialog does not directly close it. Instead, it sends a click string to the keyboard buffer, which should generate an exitcode in the dialog's event handler or input routine, allowing the application to close the dialog (with opcode CTLOP_DEL). By default, the click string is a single escape character, i.e. chr(27), which generally translates to exitcode 1. But as of 6.1.1355.0 you can override it by putting the desired click string (e.g. VK_xF999 for exitcode 999) into the cmd parameter and not setting the MBF_KBD flag in the ctype parameter. If you set the MBF_KBD flag, then clicking anywhere on the dialog will send the click string, as if it were a button or other clickable control.

To simplify programming, if the dialog also has a CANCEL button, you might as well program it to send the same click string so that pressing on the CANCEL button or "X" has the same effect. Also note that you are not obligated to close the dialog just because the user clicked on either of these buttons; if there is a problem needing resolution by the user, you can ignore the clicks or pop up a message box to tell the user what they must do before closing the dialog.

To display a dialog by itself, without the main window behind it, using one of the following techniques:

• You can launch a new session of A-Shell with either of the command line switches -z or -zi (both of which make the main window invisible) and use a startup command that launches a program which shows a dialog. Note however, that the dialog should be created with MBF_ALTPOS flag or else it will likely be sized inappropriately.

• You can hide the main window on demand using XCALL AUI, AUI_WINDOW , SW_HIDE and then proceed to create a dialog normally.

History

2013 December, A-Shell 6.1.1368: WS_VSCROLL flag in the winstyle parameter allows creation of vertically scrollable dialogs.

2013 July, A-Shell 6.1.1356: Clicks on controls belonging to windows not within the current modal dialog are normally ignored, unless they come from a modeless dialog. The idea is that modeless dialogs operate outside of the normal dialog hierarchy. This rule has now been modified slightly to ignore clicks from a modeless dialog which is a parent of the current modal dialog. In other words, if a modeless dialog launches a modal child dialog, the user will have to terminate that modal child dialog prior to interacting again with the original modeless dialog.

2013 March, A-Shell 6.1.1340: New ctype2 flag MBF2_GLOBAL allows a control to be clickable even if not part of the current modal dialog.

Subtopics

Dialog Options

Dialog Positioning

Dialog Scrolling


Dialog Options

Updated December 2013

The following ctype and ctype2 flags relate specifically to dialogs:

Symbol | Description
MBF_ALTPOS | Changes the grid units used to size the dialog and position the controls within it, from the main window grid, i.e. the original text R rows by C columns system used by TAB(R,C), to units that are based on the Windows desktop font and resolution. See Dialog Positioning.
MBF_DLGNOCREEP | Applies to nested dialogs which don't use MBF_ALTPOS, eliminating the cascading (aka "creeping") effect by making the dialog interpret its position relative to the main window rather than to the parent dialog.
MBF_DLGNOPARENT | Forces dialog box to be a child of the desktop (sibling of the main A-Shell window) rather than a child of the main A-Shell window. See Dialog Positioning.
MBF_MAXBUTTON | Enables the maximize dialogs button (requires MBF_SYSMENU)
MBF_MODELESS | Creates a Modeless Dialog.
MBF_SYSMENU | Adds the "X" button to the dialog.
MBF2_DLGICON | Display the dialog icon in the dialog title bar.
MBF2_DLGNOCAP | Creates a dialog with no caption. Such a dialog is effectively anchored to its parent, as if it were a child control, except that it can host its own child controls.
MBF2_DLGSTATE | Causes A-Shell to remember and re-use the last size/position/state of the dialog, ignoring the specified coordinates/state.
MBF2_MINBUTTON | Used with MBF_SYSMENU to add a minimize button to a modal dialog.
MBF2_NOMOVE | Prevents a dialog from being moved.
MBF2_PIXCOORDS | Allows you to specify all the coordinates of the dialog in pixels. See Dialog Positioning.
MBF2_PIXSIZE | Allows you to specify the size of the dialog in pixels. See Dialog Positioning.
MBF2_RESIZE | May be used with MBF_ALTPOS to allow the dialog to be resized with the mouse.

Use the following winstyle options to further define the dialogs:

WS_BORDER | &h00080000 | Adds a thin border. Is normally only applicable with MBF2_DLGNOCAP.
WS_VSCROLL | &h00200000 | Used to support vertical scrolling in dialogs. The scroll bar is initially disabled, but is automatically enabled and configured as fields are added to the dialog that extend beyond the bottom of the visible dialog. Users can scroll the dialogs using the scroll bar. AUI_EVENTWAIT will also auto-scroll the dialog as needed to bring the newly focused control into view. See Dialog Scrolling.

History

2013 December: Added two winstyle symbols in separate table.

2012 November: This topic added.


Dialog Positioning

Added November 2012

The size of a dialog is based on interpreting the specified scol, srow, ecol and erow coordinates according to one of following grid systems:

• Main window grid: If the dialog is a child of the main A-Shell window and neither the MBF_ALTPOS nor MBF2_PIXSIZE options are specified (and the Settings > Dialog Sizing > Dialog Grid Units option is not set to "Main window grid size"), then the dialog coordinates will be interpreted using the grid of the main window. For example, if the main window is divided into 24 rows and 80 columns, and the dialog coordinates are 12, 40, 26, 90, then the dialog will be positioned with the upper left corner roughly in the position of the main windows' row 12, column 40, and will extend approximately two rows and ten columns beyond the bottom and right edge of the main window. (The positions are somewhat approximate due to some internal margins in both the dialog and main window, the thickness of the dialog border, etc.) Note that these main window grid units are calculated dynamically based on the size of the main window at the time the dialog is created, which raises the risk of the resulting dialog being too big or too small.

• Altpos grid: If the MBF_ALTPOS flag is specified (or the Settings > Dialog Sizing > Dialog Grid option is set to "Windows desktop font size"), then the "altpos" (alternate positioning) grid is used. The units of this grid are based on the resolution and size of the Windows desktop font, about 120% of that font's character height and average character width. This grid system makes it easy to lay out controls in standard rows and columns that adjust automatically to the desktop resolution, which is the way most Windows dialogs work.

• Pixels: If you specify the MBF2_PIXSIZE or MBF2_PIXCOORDS flags, then you can specify the height and width (or all the coordinates, if MBF2_PIXCOORDS) in pixels.

Although the Altpos grid system is the most convenient of the three, in all cases you can use the AUI_WINDOW function to query the details of the grid system and monitor configuration in order to size and position the dialog relative to the available space.

You can also center the dialog, using the cstate flags MBST_HCENTER and MBST_VCENTER (in which case you might was well set the left and top coordinates of the 1,1 and the right and bottom to the desired width and height).

See the EXLIB sample programs DLGCTR, DLGCTR2 and DLGCTR3 in [908,28] for various examples of these techniques.

History

2012 November: This topic added.


Dialog Scrolling

Added December 2013

Dialogs can be made vertically scrollable by specifying the WS_VSCROLL in the winstyle parameter when the dialog is created. For example:

...

Code for example above.

! create dialog with vertical scroll bar

winstyle = WS_VSCROLL

xcall AUI, AUI_CONTROL, CTLOP_ADD, "dlg1", "Scrolling Dialog", &

MBST_ENABLE, MBF_DIALOG, NUL_CMD$, NUL_FUNC$, NUL_CSTATUS, &

4000, 10000, 10000, 40000, NUL_FGC, NUL_BGC, &

NUL_FONTATTR, NUL_FONTSCALE, NUL_FONTFACE$, NUL_TOOLTIP$, &

NUL_PARENTID, NUL_WINCLASS$, winstyle, NUL_WINSTYLEX, NUL_CTYPE2

! create a bunch of fields that extend arbitrarily below bottom of dialog

row = 500

for fno = 1 to num'fields

row += 1000

xcall SBXINP, "<2>"+label$(fno), INFOP_DISPLAY, row, 8, xmax(fno), &

field$(fno), "|GA||C]g123T", setdef$, 50, fno+100, tooltip$, "dlg1", &

exitcode, -1, 0, 0, -1

next fno

The scroll bar will be automatically configured / calibrated as fields are added to the dialog, and the EVENTWAIT routine will automatically scroll the currently focused field into view.

Note that this works for all types of dialogs, including MBF_DLGNOCAP dialogs, which can be positioned within parent windows or panels (such as Tab panels), allowing you to effectively creating scrollable regions within a larger window.

Code for example above.

To produce this dialog, we modify the code from the first example as follows:

! main dialog (not scrollable)

xcall AUI, AUI_CONTROL, CTLOP_ADD, "dlg0", "Dialog with scrollable region", &

MBST_ENABLE, MBF_DIALOG, NUL_CMD$, NUL_FUNC$, NUL_CSTATUS, &

4000, 10000, 12000, 40000, NUL_FGC, &hffeeee

! ok and cancel buttons at top, in non-scolling region

xcall AUI, AUI_CONTROL, CTLOP_ADD, "btnOK", "OK", &

MBST_ENABLE, MBF_BUTTON+MBF_KBD, "VK_xF5", NUL_FUNC$, NUL_CSTATUS, &

1500, 13000, 3000, 20000

xcall AUI, AUI_CONTROL, CTLOP_ADD, "btnCancel", "Cancel", &

MBST_ENABLE, MBF_BUTTON+MBF_KBD, "VK_ESC", NUL_FUNC$, NUL_CSTATUS, &

1500, 22000, 3000, 29000

! scrollable borderless dialog within main dialog

xcall AUI, AUI_CONTROL, CTLOP_ADD, "dlg1", NUL_CTEXT$, &

MBST_ENABLE, MBF_DIALOG, NUL_CMD$, NUL_FUNC$, NUL_CSTATUS, &

3000, 0, 8500, 31000, NUL_FGC, &hffdddd, &

NUL_FONTATTR, NUL_FONTSCALE, NUL_FONTFACE$, NUL_TOOLTIP$, &

NUL_PARENTID, NUL_WINCLASS$, WS_VSCROLL+WS_BORDER, NUL_WINSTYLEX, &

MBF2_DLGNOCAP+MBF2_STICKY

! create a bunch of fields that extend arbitrarily below bottom of window

! <same as before, fields owned by dlg1 which is now a captionless dialog within dlg0


Modeless Dialog

Updated August 2015; see History

A "modeless" dialog is like a Modal Dialog Box Control except that it does not command the focus and does suspend the operation of the main program or other dialogs). To create, use MBF_DIALOG+MBF_MODELESS. The ending row and column of a modeless dialog may be beyond the limits of the screen or window. These dialogs are mainly useful for displaying information that is not critical to the main window, allowing the user to push it out of the way if desired.

Unlike a modal dialog, a modeless dialog can be minimized, in which case it sits just above the Task Bar rather than within it.

See the sample program DLGMODLES in the EXLIB for an example of creating and managing a modeless dialog.

History

2015 May, A-Shell 6.1.1408: AUI refinement: when a modeless dialog is created in an initial minimized or maximized state (see cstate), the min/max buttons MBF2_MINBUTTON and MBF_MAXBUTTON are now automatically added. This is a follow-up revision to 1402.7 which removed the buttons when the corresponding flags were not specified, but it doesn't make sense to create a minimized or maximized dialog without buttons to normalize it.


Progress Bar Control

Updated August 2012; see History

A progress bar (MBF_PROGRESS) is similar to a hollow static rectangle which you can progressively fill during the course of an operation to give a visual indication of the percentage of the job completed.

The control is similar to a static text control, except that you must specify the MBF_PROGRESS flag instead of MBF_STATIC, and currently the colors are ignored.

You must retain the ctlid returned when creating the control so that it can subsequently be updated. For example:

MAP1 CTEXT,S,5,"0" ! % completed

xcall AUI, AUI_CONTROL, CTLOP_INFO, prgbid, ctext, MBST_ENABLE, MBF_PROGRESS, "", "", status, srow, scol, erow, ecol

Initially the progress bar will be empty. To update it, you can use opcode 2 (change), specifying the ctlid (PRGBID in the above example) returned from the create operation, placing a string representation of the percent completed in the ctext parameter, and specifying the MBST_CHANGE flag in the cstate parameter, e.g.:

CTEXT = str(PERCENT) ! percentage complete (round to integer)

xcall AUI, AUI_CONTROL, CTLOP_CHG, prgbid, str(pct), MBST_CHANGE

The above call would move the progress bar over to the position representing whatever percentage is in the variable PERCENT. Note that we omitted unnecessary parameters, which not only saves typing but in the case of ATE would eliminate the need for it to return the status parameter to us, cutting down on network traffic. (In any case you probably do not want to update the progress bar more often than necessary to convey the sense of action. For example, in a report of 100,000 records, it probably would not make that much sense to update the progress bar for every single record.)

Often a progress bar is displayed inside of a dialog box which contains a message indicating the nature of the activity, an possibly a CANCEL button. As a convenience, we provide a higher-level subroutine, PROGRS.SBX, which combines these elements (text message, progress bar, optional cancel button, within a dialog box).

History

2012 August, A-Shell 1255: the progress bar control (MBF_PROGRESS) can now be given the "marquee" style by setting the winstyle parameter to PBS_MARQUEE (&h0008). This version of the progress bar is used to indicate activity without indicating a percentage complete. As with the normal progress bar, you use the ctext parameter (either in the CTLOP_ADD or CTLOP_CHG operation) to adjust the animation, except that instead of being interpreted as the percent complete, it is interpreted as the refresh rate of the animation, in milliseconds. Setting ctext to "" or "0" turns off the animation, leaving an empty progress bar.


Tab Control

A Tab control looks something like a series of file folders, where you can see the "tabs" for all of them (unless they scroll out of view) but can see the contents of only one at a time. Another way to conceptualize a Tab control is as a combination of a Groupbox and a row of buttons ("tabs") along the top. Clicking on one of the buttons or tabs sends a keyboard command notification allowing the program to replace the contents of the current groupbox with new contents, depending on which tab was clicked.

The coordinates specified are for the outer rectangle, which includes the space occupied by the tabs. The "client area" of the tab control (the usable area bounded by the tabs at the top and the left, right and bottom edges) acts like a groupbox. Controls placed in this area must specify the ID of the tab control in the parentid parameter, and their coordinates are treated as offsets from the upper left corner of this client area. If the number and style of tabs is such that there are multiple rows of tabs, the client area is further reduced by the space taken up the extra row(s) of tabs, so you should allow extra space if this is a possibility.

As with a groupbox, deleting the tab control deletes all of the controls within it. Perhaps more importantly, using opcode CTLOP_CLR to clear the tab deletes all the controls on the current tab page, a necessary step in switching to a new tab page.

Variations of the basic tab control can be specified by adding one or more of the following to the winstyle parameter:

Symbol | Value | Description
TCS_FLATBUTTONS | &h0008 |
TCS_FORCELABELLEFT | &h0020 | Tab labels are left justified within each tab. This only makes sense with the TCS_FIXEDWIDTH style. Otherwise they are centered.
TCS_BUTTONS | &h0100 | Tabs appear as buttons and no border is drawn around the display area.
TCS_MULTILINE | &h0200 | If the tabs do not fit on one row, multiple rows are used. Otherwise, a scroll button is placed at the edge of the one row of tabs to allow it to be scrolled horizontally.
TCS_FIXEDWIDTH | &h0400 | All tabs are made the same width; otherwise the width of each tab is based on the text in that tab.

Hex-Decimal Values

The tabs are defined by specifying ctext in the following format:

CTEXT=Label1~Cmd1~~Label2~Cmd2~~...LabelN~CmdN

In the above specification, Label1 through LabelN represent the text strings displayed in each tab, and Cmd1 through CmdN represent the keyboard command strings each tab sends. As an example:

CTEXT="&Receivables~" + chr(7) + chr(250) + "101." + "~~&Payables~" + chr(7) + chr(250) + "102." + "~~General &Ledger~" + chr(7) + chr(250) + "103."

This would define a set of 3 tabs, "Receivables", "Payables" and "General Ledger" (with corresponding Accelerator keys R, P, and L). Clicking on the "Receivables" tab (or keying alt+R) would generate exitcode –101 (pseudo function key F101), etc. A program using this arrangement would have to check for these exitcodes (or raw key sequences if your input routine did not provide automatic exitcode conversions), and on receipt, display the appropriate options within the display area of the tab control, according to which tab clicked.

See Also

• TabX Control for an extended version of the Tab control.

Subtopics

XTREE/XTEXT Tab Performance

Tab Control Example


XTREE/XTEXT Tab Performance

Added November 2010

This section discusses a performance refinement for Tab controls containing XTREE and XTEXT controls. It is primarily an ATE refinement, but could also apply to local Windows environments where you have large XTREE or XTEXT controls within TABs.

The idea is to avoid deleting and recreating the XTREE or XTEXT control when switching from one Tab pane to another, by just hiding the XTREE/XTEXT control and later reactivating it rather than recreating it.

Normally, the procedure for switching between TABs is to use CTLOP_CLR with the TAB's control ID to clear all of the controls on the pane before switching to the new pane and recreating all the controls for that pane. Destroying and recreating controls is usually just as fast as hiding/restoring them. But in the case of very large and complex controls, like XTREE and XTEXT, and especially in the ATE environment (where a lot of data must be sent from the server to the client to create and load the control), it would be more efficient to just make those controls disappear when switching to another pane, and then make them reappear when switching back to the pane containing them.

To accomplish that, you may now specify the code "!XT" (meant to suggest no XTREE or XTEXT) in the Txt parameter of the CTLOP_CLR call, e.g.:

xcall AUI, AUI_CONTROL, CTLOP_CLR, TABID, "!XT"

This causes any XTREE or XTEXT controls on the current Tab pane to be merely hidden instead of deleted.

Later, when you switch back to the pane containing the XTREE or XTEXT control(s), you just need to use CTLOP_CHG with the MBST_ENABLE and MBST_SHOW cstate flags to redisplay the control, rather than recreating it.

As a practical matter, to do this robustly, you will need the ctlid of the XTREE and/or XTEXT controls, which you would have from the XTR'CTLID and/or txc'ctlid parameters of the respecting routines. (This assumes you are saving the xtrctl and/or txtctl parameter blocks for each XTREE/XTEXT control separately.) If the ctlid parameter is non-zero, that implies that you must have previously created the control, and thus you may be able to just redisplay it with CTLOP_CHG. The returned cstatus value from the CTLOP_CHG operation will be >=0 if it succeeds, else it failed and you'll need to recreate the control. For example:

if XTR'CTLID > 0 then

xcall AUI, AUI_CONTROL, CTLOP_CHG, XTR'CTLID, NUL_CTEXT$, MBST_ENABLE+MBST_SHOW, NUL_CMD$, NUL_FUNC$, CSTATUS

else

CSTATUS = -1

endif

if CSTATUS < 0 then ! we failed to redisplay the XTREE so recreate it

...

endif

Note: this is a client-side enhancement. (If an app tries to use the feature in an older client that doesn't support it, the CSTATUS parameter will indicate an error and you'll be able to recreate the control as before.)

History

2010 November, 5.1.1196: Added to A-Shell


Tab Control Example

See the sample program TABDLG.BP for a good example of the tab control. Here’s a screen shot of it, showing a Tab control inside of a modal dialog box:

this is a linked image

The colored strip across the top of the dialog is a bitmap file, displayed on the dialog using the AUI "IMAGE" class.


TabX Control

Revised December 2014; see History

The TabX control was introduced in A-Shell 6.1.1321 as an alternate version of the standard Tab control, with several extended features, including:

• Many different styles of tab labels | • Ability to set the label font style/size
• Extensive color options (background, text, flyby, active, inactive, etc) for each tab | • Ability to put the labels on the left, right, or bottom, as well as the top
• Options relating to the scroll buttons position and style | • Transparency of the area around the labels (cleaner look)
• Add and delete tab labels | • Enable/Disable tab labels
• Tooltips for each tab label | • Optional close ("x") button
• Options relating to arrangement of the labels | • Option to have just labels (no panel)

In its basic/default configuration, it supports the same configuration syntax as the standard Tab, except that you must also specify the MBF2_TABX flag in the ctype2 parameter (or the SBR=AUTO_TABX|topic=SBR global flag); in this mode it looks and behaves similarly to the standard Tab. To take advantage of some of the extended features, set your ctype parameter according to the following syntax shown below.

Creating a new TabX control (opcode CTLOP_ADD):

ctext$ = {@globalattribs~~} {labeldef~~labeldef~~...labeldef~~}

Modifying a TabX control (opcode CTLOP_CHG):

ctext$ = {@globalattribs~~}{+|-|={labelid}:}{labeldef~~}...{+|-|={labelid}:}{labeldef~~}

where:

globalattribs define attributes for the tab control as a whole

labeldefs define each individual tab/label

labelid identifies a tab/label to modify, or the position in which to insert a new one. It may be either the tab label number, starting from 1, or the label text or command field defined in the labeldef. It must begin with "+", "-", or "=", and end with ":"

Value | Description
+labelid: | insert a new label at the specified position, or at the end (if no labelid)
+: | (no labelid specified) append a new label at the end
-labelid: | delete the specified label
=labelid: | modify specified label, e.g. enable/disable it

History

2014 December, A-Shell 6.1.1399: TabX refinement/workaround: If the user somehow manages to click on a tab label in such a way that the event code trigger is bypassed and consequently the application doesn't know to switch panels, resulting in a mismatch between the actual panel displayed and the highlighted label, you can now rectify the situation by just re-clicking on the correct label. This is a rare situation, generally only possible if clicking rapidly on the labels while other control updating operations are occurring within the TABX control. When it did occur, it previously caused more headache because clicking on the correct label typically caused confusion in the application, which thought that the specified panel was already the active one, thus rejecting the click.

2012 November, A-Shell 6.1.1321: TabX control added to A-Shell

Subtopics

globalattribs

labeldefs

TabX Style Examples

TabX Operations / Examples


globalattribs

Changed July 2013

Global attributes are signaled by a leading "@", followed by one or more clauses of the form attrib=value~, and ending with an extra ~ (two in a row). If the first character of ctext is not "@" then it is assumed there are no global attributes and parsing proceeds with the labeldefs.

Attribute | Value | Description
style | Number | sets the overall style; see descriptions in the following table (not this one)
scrollstyle | Number | sets style of scroll buttons, from following table:
 |  | "none" | No scroll buttons
 |  | 0 | Windows 3.1 style
 |  | 1 | Windows 95 style
 |  | 2 | Standard style
 |  | 3 | Windows 95 alternate style
 |  | 4 | Theme buttons
 |  | 5 | Theme/scroll
 |  | 6 | Hover
 |  | 7 | Theme/scroll alternate
bold | 0/1 | if 1, current label text is to be displayed in bold
xbtnVisible | 0/1 | if 1, an "x" button will be visible, theoretically to close the current tab. When clicked, it sends exitcode -69.
xbtnEnabled | 0/1 | Controls whether the "x" button is enabled or disabled
xbtnTip | text | tooltip for the "x" button
xbtnAlign | near|far|center | controls how close the "x" button is to the last tab label
themes | 0/1 | use visual themes or not. (using them may disable a number of other features relating to color)
sbtn | Number (default = 1) | scroll button options (sum of):+1=scrollable (and visible), +2=conditional visibility (only if needed), +4=buttons displayed at start/left instead of at right/end
sbtnAlign | near|far|center | same idea as xbtnAlign but for the scroll buttons
forcedSize | Number | forced height (if horizontal) or width (if vertical)
ClientArea | 0/1 | determines if the tab control has a client area (attached panel) (see TABSTRIP.BP[908,22] for example with ClientArea=0)
rows | Number | Number of rows of labels; may require sbtn=0; see Note1 below.
rowTabs | Number | Number of tabs per row (if fixed tabs); may require sbtn=0; see Note1 below.
fixedTabs | 0/1 | fixed width tabs
multiLine | 0/1 | if 1, tab labels may have multiple lines using chr(13) for line break.
panelBorder | 0/1 | controls if panel/client area has a border
font fontAttr | facename {,fontattr} Number | Font=facename{,fontattr} and fontAttr=# provide alternate ways of specifying the same exact set of font attributes. Use which ever form you prefer with values from the following table.
 |  | Symbol |  | Value | Description
 |  | FS_UPRIGHT |  | &h00 | Normal upright
 |  | FS_ITALIC |  | &h01 | Italic
 |  | FS_UNDERLINE |  | &h02 | Underline
 |  | FS_STRIKEOUT |  | &h04 | Strikeout
fontFace | facename | alternate method of specifying the label text font.
fontScale or scale | <percent> | optional font scale to use for the label text

Note1: Unlike the traditional Tab Control style option TCS_MULTILINE, which results in a variable number of rows of tab labels (as required to display them all), the TabX control requires, if you want multiple rows of labels instead of a single scrolling row, that you explicitly specify the number of label rows (rows=#). This is actually a sensible limitation, since each additional row of labels subtracts from the client/display area available to the panels. Without knowing how much space is available in the client/display area, it would be difficult to lay out your child controls. In situations where the number of tab labels is unknown at design time, it is probably best to stick with scrolling labels; see sbtn.

Style

The style parameters sets the overall style, using values as shown in the following table. See the TabX Operations / Examples section. Also note the following symbol naming conventions:

• _ L = Tab labels on left side (instead of default which is top)

• _R = Tab labels on right side

• _LR = Tab labels on left and right (requires even number of tab rows)

• _TB = Tab labels on top and bottom (requires even number of tab rows)

• _V = Labels rotated (vertical, not compatible with multiLine attribute)

The source of these values and symbols is the included file ashinc:tabx.def.

Symbol | Value | Description | Symbol | Value | Description
TBXSTY_STD | 0 | Standard style, labels on top | TBXSTY_SQ_L_V | 38 |
TBXSTY_STD_L | 1 |  | TBXSTY_SQ_R | 39 |
TBXSTY_STD_L_V | 2 |  | TBXSTY_SQ_R_V | 40 |
TBXSTY_STD_R | 3 |  | TBXSTY_SQ_B | 41 |
TBXSTY_STD_R_V | 4 |  | TBXSTY_SQ_TB | 42 |
TBXSTY_STD_B | 5 |  | TBXSTY_SQ_LR_V | 43 |
TBXSTY_STD_II | 6 | Standard style II, labels on top | TBXSTY_SQ2 | 44 | Square style with edge
TBXSTY_STD_II_L | 7 |  | TBXSTY_SQ2_L | 45 |
TBXSTY_STD_II_L_V | 8 |  | TBXSTY_SQ2_L_V | 46 |
TBXSTY_STD_II_R | 9 |  | TBXSTY_SQ2_R | 47 |
TBXSTY_STD_II_R_V | 10 |  | TBXSTY_SQ2_R_V | 48 |
TBXSTY_STD_II_B | 11 |  | TBXSTY_SQ2_B | 49 |
TBXSTY_WIZARD | 12 | (Invisible) | TBXSTY_SQ2_TB | 50 |
TBXSTY_SIMP | 13 | Simple, top labels | TBXSTY_SQ2_LR_V | 51 |
TBXSTY_SIMP_B | 14 | Simple, bottom labels | TBXSTY_LSQ | 52 | Another square style
TBXSTY_MOD_I | 21 | Modern style I, labels on | TBXSTY_LSQ_L | 53 |
TBXSTY_MOD_I_L_V | 22 |  | TBXSTY_LSQ_L_V | 54 |
TBXSTY_MOD_I_R_V | 23 |  | TBXSTY_LSQ_R | 55 |
TBXSTY_MOD_I_B | 24 |  | TBXSTY_LSQ_R_V | 56 |
TBXSTY_MOD_I_L | 25 |  | TBXSTY_LSQ_B | 57 |
TBXSTY_MOD_I_R | 26 |  | TBXSTY_LSQ_TB | 58 |
TBXSTY_SIMP_II | 27 | Simple II, top | TBXSTY_LSQ_LR_V | 59 |
TBXSTY_SIMP_II_B | 28 |  | TBXSTY_MOD_II | 60 | Modern style II
TBXSTY_SIMP_III_B | 29 | Simple III, bottom | TBXSTY_MOD_II_L_V | 61 |
TBXSTY_STD_TB | 30 | Standard style, top/bottom labels | TBXSTY_MOD_II_R_V | 62 |
TBXSTY_STD_LR | 31 |  | TBXSTY_MOD_II_B | 63 |
TBXSTY_STD_LR_V | 32 |  | TBXSTY_MOD_II_TB | 64 |
TBXSTY_MOD_TB | 33 | Modern style I, top/bottom labels | TBXSTY_MOD_II_LR_V | 65 |
TBXSTY_MOD_LR | 34 |  | TBXSTY_BTNS | 66 | Buttons style
TBXSTY_MOD_LR_V | 35 |  | TBXSTY_BTNS_L | 67 |
TBXSTY_SQ | 36 | Square style | TBXSTY_BTNS_L_V | 68 |
TBXSTY_SQ_L | 37 |  | TBXSTY_BTNS_R | 69 |


labeldefs

As with the global attributes, each set of label definitions is made up of one or more attrib=value clauses, separated by a tilde. Two consecutive tildes are used to separate the clauses for one label from those of another label. The cmd and label clauses are mandatory; the rest are optional:

Option | Description
cmd=<cmdstring> | (mandatory) click string to send when label clicked, e.g. VK_xF101
label=<text> | (mandatory) text to display in label
enabled=0/1 | disable/enable the tab
RGBbg=r,g,b | background color for the unselected tab labels.
RGBbgSel=r,g,b | background color for the currently selected tab label
RGBbgClient=r,g,b | background color for the client panel. Also sets RGBbgSel to match, if not already set.
RGBbgClientStart=r,g,b~RGBbgClientEnd=r,g,b | alternative to RGBbgClient; creates a gradient background
RGBfg=r,g,b | foreground color for the unselected tab label text.
RGBfgFlyby=r,g,b | foreground color for the tab label text when the mouse is over it.
RGBfgSel=r,g,b | foreground color for the text in the currently selected tab label
tip=<text> | tooltip text for the label


TabX Style Examples

Many of the style variations are limited to particular sets of attributes, or are variations of each other (e.g. tab labels on bottom instead of on top, or on right instead of left). Here are some examples of variations with labels on the top and on the left. (The TSTTABX program in [908,22] allows you to cycle though the variations.)


TabX Operations / Examples

See the sample program TSTTABX for a working example of many of the operations discussed in the following sections.

Creating a TabX Control

map1 tabdefs$,s,0

map1 tabid$,s,24,"tbx1"

! start with TABX global options

tabdefs$ = "@style=0~" ! std modern style

tabdefs$ += "XbtnVisible=1~" ! "x" (close) button visible

tabdefs$ += "XbtnEnabled=1~" ! close button is enabled

tabdefs$ += "XbnTip=Close current tab~" ! tool tip for close btn

tabdefs$ += "themes=0~" ! themes disabled

tabdefs$ += "~" ! end of global options

! add tabs (each with individual options)

tabdefs$ += "Label=&One~"

tabdefs$ += "Cmd=VK_xF101~"

tabdefs$ += "id=One~"

tabdefs$ += "RGBbgClient=200,180,160~" ! active panel/lbl (light beige)

tabdefs$ += "RGBbg=140,130,120~" ! inactive lbl (darker gray/beige)

tabdefs$ += "tip=this is the tab one tip~"

tabdefs$ += "~" ! end of tab 1 options

tabdefs$ += "Label=&Two~"

tabdefs$ += "Cmd=VK_xF102~"

tabdefs$ += "id=Two~"

tabdefs$ += "tip=this is the tab two tip~"

tabdefs$ += "RGBbgClient=150,200,250~"

tabdefs$ += "RGBbg=140,130,120~" ! inactive lbl (darker gray/beige)

tabdefs$ += "~" ! end of tab 2

xcall AUI, AUI_CONTROL, CTLOP_ADD, TABID$, tabdefs$, MBST_ENABLE, MBF_TAB, NUL_CMD$, NUL_FUNC$, NUL_CSTATUS, tsrow,tscol,terow,tecol, NUL_FGC,NUL_BGC,NUL_FONTATTR,NUL_FONTSCALE, NUL_FONTFACE$, NUL_TOOLTIP$, parentid$, NUL_WINCLASS$, NUL_WINSTYLE,NUL_WINSTYLEX, MBF2_TABX

Selecting a Panel

When first creating a Tab (or TabX) control, the first tab label will automatically be selected. To select a different label/panel, use the CTLOP_PANE opcode, specifying either the pane/label number in the cstate parameter (and leaving ctext empty), or the pane/label text or click string (as defined by the label or cmd attributes) in the ctext parameter and setting cstate to 0. For example:

tabno = 3 ! select panel #3 (Tab or TabX control)

xcall AUI, AUI_CONTROL, CTLOP_PANE, ctlid$, "", tabno

! (the following methods only work with the TabX control)

labelid$ = "&One" ! select panel with label text "&One"

xcall AUI, AUI_CONTROL, CTLOP_PANE, ctlid$, labelid$, 0

labelid$ = "VK_xF402" ! select panel with click str "VK_xF402"

xcall AUI, AUI_CONTROL, CTLOP_PANE, ctlid$, labelid$, 0

Switching Panels

Typically, the user will signal the desire to switch to another panel by clicking on the label, which will transmit the label's click string, which will typically generate an exitcode in the application. To respond (or to switch panels purely according to the whim of the application), you might first want to start by validating or storing the contents of the current panel (if applicable), then proceed by clearing the panel with the CTLOP_CLR opcode, followed by selecting the new panel with the CTLOP_PANE opcode (as described above). In the example below, we use the exitcode returned by clicking on the label to identify the label (assuming that the exitcode was generated by the standard click string syntax of VK_xF###):

switch exitcode

…

case -102 ! user clicked label #2

<validate current panel contents>

if <ok to switch to new panel> then

xcall AUI, AUI_CONTROL, CTLOP_CLR, ctlid$ ! clear current panel contents

labelid$ = "VK_xF"+str(exitcode)

xcall AUI, AUI_CONTROL, CTLOP_PANE, ctlid$, labelid$, 0

<display contents of panel>

else

<display a message saying why switch is not allowed>

! now we must re-select the current panel

labelid$ = <id of previous panel>

xcall AUI, AUI_CONTROL, CTLOP_PANE, ctlid$, labelid$, 0 ! select new panel

endif

endif

If you don't want to allow the user to switch panels, then you must explicitly use CTLOP_PANE to re-establish the label/panel you were previously on, else the control will display the clicked-on label as if it were the current label. An alternate approach would be to disable the other panels until you wanted to allow the user to switch to them.

Disabling/Enabling a Panel/Label

To disable or enable panels, use the CTLOP_CHG opcode and cstate MBST_CHANGEX, identifying the labels to be enabled/disabled using "=labelid:" clauses in the ctext parameter (either by # or by the alphanumeric id), e.g.

ctext$ = "=1:~Enabled=0~~" ! disable the first panel

ctext$ += "=Th&ree:Enabled=1~~" ! and enable the panel "Th&ree"

xcall AUI, AUI_CONTROL, CTLOP_CHG, ctlid$, ctext$, MBST_CHANGEX

Adding a Panel/Label

To add a new panel to the end, specify the panel's label definition, preceded by "+:", e.g.

ctext$ = "+:label=New~cmd=VK_xF405~~" ! add new panel "New"

xcall AUI, AUI_CONTROL, CTLOP_CHG, ctlid$, ctext$, MBST_CHANGEX

Inserting a panel in another position is the same except that you must specify the panel's labelid (number or label text or click string). Here we insert the new label in position 2:

ctext$ = "+2:label=New~cmd=VK_xF405~~" ! insert new panel "New" at position 2

xcall AUI, AUI_CONTROL, CTLOP_CHG, ctlid$, ctext$, MBST_CHANGEX

Here we insert it prior to the panel whose cmd click string is "VK_xF402":

ctext$ = "+VK_xF402:label=New~cmd=VK_xF405~~"

xcall AUI, AUI_CONTROL, CTLOP_CHG, ctlid$, ctext$, MBST_CHANGEX

Note that inserting or deleting a label in the middle causes the pre-existing labels to be renumbered.

Deleting a Panel

To delete a panel, specify the panel's label identifier preceded by a "-" and followed by the ":". Note that as with the other operations, the label identifier can be a number (the panel's ordinal position), or the panel's text label string, or its command string. Also note that although we are deleting a panel, we are not deleting the entire control, so we are using the CTLOP_CHG opcode (rather than CTLOP_DEL). For example:

ctext$ = "-2:~~" ! delete panel #2

xcall AUI, AUI_CONTROL, CTLOP_CHG, ctlid$, ctext$, MBST_CHANGEX

ctext$ = "-Th&ree:~~" ! delete panel whose label is "Th&ree"

xcall AUI, AUI_CONTROL, CTLOP_CHG, ctlid$, ctext$, MBST_CHANGEX

ctext$ = "-VK_xF101:~~" ! delete panel whose command string is "VK_xF101"

xcall AUI, AUI_CONTROL, CTLOP_CHG, ctlid$, ctext$, MBST_CHANGEX

Finally, note that deleting a panel effectively renumbers all of the panels to its right, which is why the panel label text or command text might be generally more useful than the ordinal position for identifying the panel.


Image Control

Updated June 2010

A-Shell supports the following five internal methods for displaying images:

• AUI_IMAGE (e.g. xcall AUI, AUI_IMAGE, or xcall IMAGE) . This method doesn't actually create a "control"; it just displays the image at the specified row/col coordinates, and may be used in both traditional text screens as well as fully GUI windows and dialogs. The main disadvantage of this method is that the images don't act like controls, so they don't integrate as well into GUI screens.

• Icon Controls, which come in both static and button flavors too, and are essentially just a particular variation of an image type. The term "icon" has both a technical meaning (referring to the ICO file format, which contains multiple versions of the image in different sizes and bit depths) and a more common meaning (referring to a small image of a somewhat standardized size which either acts as a kind of logo to identify a program or represents some kind of action that will occur when you click on it). It is important to note that other types of image formats (besides ICO, e.g. BMP) can serve as icons in the latter sense. In fact, so called "icon libraries" often contain both ICO and other file formats.

• Images can be displayed inside of XTREE cells.

• Static controls (MBF_STATIC + MBF_BITMAP), where the ctext parameter specifies the image file, which may be in JPG, BMP, PCX, TIF or PNG format.

• Button controls (MBF_BUTTON + MBF_BITMAP), where the ctext parameter specifies the image file, same formats as above. Button controls displaying an image are very similar to static controls displaying an image - both support the same range of image types and both can have click events associated with them. The differences are mainly in the way the border of the control looks, and in the way scaling and alignment work.

Static and Button controls can also specify bitmap resources contained inside DLLs using the syntax:

resname::dllname

The first three of the above five categories are already covered elsewhere in this document; so we will focus here on the last two, which we will refer to as the Static Image Control and the Button Image Control.

History

2010 June, 5.1.1183: Static and Button controls can now also specify bitmap resources contained inside DLLs.

Subtopics

Static Image Control

Button Image Control

Hover/Context Menus


Static Image Control

Static image controls are created with xcall AUI_CONTROL, with ctype set to MBF_STATIC + MBF_BITMAP (plus optional flags such as MBF_NODISTORT, MBF_CENTER, MBF_KBD, etc.) For example:

xcall AUI, AUI_CONTROL, CTLOP_ADD, NUL_CTLID, imgfile$, MBST_ENABLE, ctype, NUL_CMD$, NUL_FUNC$, NUL_CSTATUS, srow, scol, erow, ecol, NUL_FGC, NUL_BGC, NUL_FONTATTR, NUL_FONTSCALE, NUL_FONTFACE$, NUL_TOOLTIP$, parentid$, NUL_WINCLASS$, winstyle

Here are a few examples, using the above code with different values for ctype, winstyle, and the coordinates. In each case, we draw a groupbox just outside the image control so that you can easily see the true size of the control (which doesn't always match the size of the image).

Stretched to fit, no border

ctype = MBF_STATIC + MBF_BITMAP

winstyle = 0

No distortion, thick frame border

ctype = MBF_STATIC + MBF_BITMAP + MBF_NODISTORT

winstyle = WS_THICKFRAME ! &h0004000 (border)

The WS_THICKFRAME flag puts a border around the static control, making it look more like a button. (You can make it act like a button, in the sense of giving it a click event, by adding the MBF_KBD flag and specifying a click string in the cmd parameter.)

When the MBF_NODISTORT flag is used, the image is scaled only as much as it can be without changing the aspect ratio. So if the original static control shape is relatively taller or wider than the image shape, you end up with extra vertical or horizontal space within the control. The question then becomes how to position the image within the space provided, the default being as shown above, in the upper left. You can use the MBF_HCENTER, MBF_VCENTER or MBF_CENTER flags to force horizontal and/or vertical alignment, as in the example below:

ctype = MBF_STATIC + MBF_BITMAP + MBF_NODISTORT + MBF_CENTER ! H+V centering

winstyle = WS_THICKFRAME ! &h0004000 (border)

By default, after computing the maximum image size and position of the scaled image, the static control is then shrunk to fit. This probably makes no difference unless the border option is used, but to see the effect of not shrinking the control to fit the image, add the SS_CENTERIMAGE flag, as shown below:

ctype = MBF_STATIC + MBF_BITMAP + MBF_NODISTORT + MBF_CENTER

winstyle = WS_THICKFRAME + SS_CENTERIMAGE ! &h0004000 + &h00000200

See the EXLIB program, STIMGT.BP[908,32], which illustrates many of these static image alignment options.


Button Image Control

Button image controls are nearly identical to static image controls. To create them, use the same code as you would for static image controls, but replace MBF_STATIC with MBF_BUTTON, and the eliminate WS_THICKFRAME flag and any SS_xxxx flags from the winstyle parameter. (Buttons always have borders, which makes them look very similar to the static controls with the WS_THICKFRAME option.)

Another subtle difference is that buttons are not by default shrunk to fit the non-distorted scaled image, unless one of the MBF_CENTER, MBF_HCENTER, or MBF_VCENTER flags is used. Plus, the default alignment is centered. For example:

ctype = MBF_BUTTON + MBF_BITMAP + MBF_NODISTORT

In the above example, the images are centered in the button. The image is not stretched to fit the button because of the MBF_NODISTORT flag, and the button is not subsequently shrunk to fit the image because none of the alignment flags were used. If we add MBF_CENTER to the above, we get the following:

ctype = MBF_BUTTON + MBF_BITMAP + MBF_NODISTORT + MBF_CENTER

Note that in the above case, the effect is virtually identical to the corresponding static control.

See the EXLIB routine TSTICB[907,23] for an example of using intermixing icons and other image types on buttons.


Hover/Context Menus

Added November 2013

Hover/context menus, associated with image controls and any static text controls, may contain submenus. To indicate the start of a submenu, set the command string for the parent item to "[SUB]". To indicate the end of a submenu, define a dummy menu item whose text is "[ENDSUB]" and whose command field will be ignored.

For example, to define a two level hover/context menu similar to the following:

Item 1

Item 2 > Sub-Item 1a

Sub-Item 1b

Item 3

Item 4 > Sub-Item 2a

Sub-Item 2b

The definition string in the tooltip parameter should be coded something like:

TOOLTIP$ = ">tooltip string\" &

+ "Item 1,VK_xF101;Item 2,[SUB];" &

+ "Sub-Item 1a,VK_xF201;Sub-Item 1b,VK_xF202;[ENDSUB],;" &

+ "Item 3,VK_xF103;Item 4,[SUB];" &

+ "Sub-Item 2a,VK_xF301;Sub-Item 2b,VK_xF302;[ENDSUB],;"

Sub menus may be nested up to nine levels deep, and a single hover/context menu may contain up to 99 total sub menus.

History

2013 November, A-Shell 6.1.1368: Added ability to contain submenus, and added this section to doc.


Toolbar Control

Updated November 2013; see History

The toolbar control (ctype MBF_TOOLBAR) is a standard Windows control which acts as a container for buttons. It is attached to one of the four edges of the parent window. Although created with the standard AUI_CONTROL function, toolbars differ from other controls in the following ways:

• The coordinates specified when creating a toolbar are ignored; position is determined by the CCS_xxx option set in the winstyle parameter, which selects the edge of the parent window to which the toolbar will be attached. The thickness of the bar is determined by the size of the images, labels, and style.

• Toolbars do not scale with changes in size to the parent window. Instead, they only stretch to match the length of the window edge to which they are attached.

• Toolbars do not take up space within the main window grid. Instead, the grid itself adjusts to make room for the toolbar.

• Toolbars are not removed by the tab(-1,0) command, unless they were created with the MBF_UNPROTECTED flag. They must be removed explicitly by AUI_CONTROL with the CTLOP_DEL opcode.

• There is a maximum of four toolbars per parent window, one for each edge.

• Currently, toolbars may only be created in the main window. This restriction may be lifted later.

You can also create toolbar-like controls or panels using standard buttons or icons, either positioned manually in a row along one edge of the screen, or contained within a floating dialog (i.e. a floating tool panel).

Several example programs and PNG images are included in [908,58] of the EXLIB.

Examples

See A-Shell Screen Elements for an extreme example with all four toolbars in use. Other examples:

16x16 buttons in top
toolbar with tooltips:

24x24 buttons in bottom toolbar with labels beneath (TBSTYLE_FLAT):

24x24 buttons with labels to side (TBSTYLE_LIST), with one disabled button:

Syntax and Parameters

Like the TabX Control, the Toolbar is largely configured via the AUI_CONTROL ctext parameter using the following syntax:

ctext = {@toolbarattribs~~}{opcur}{btndef~~btndef~~...btndef~~}

opcur

identifies the operation and button when modifying an existing toolbar. If present it must start with a "+" or "=" and end with a ":", according to the following:

opcur | Description
+: | Append subsequent btndefs to the end of the toolbar
-labelid: | Modify the button whose id or cmd attribute matches the specified labelid.

toolbarattribs

defines attributes of the toolbar as a whole, most importantly the image size info. Starts with a @ and ends with ~~, between which you may have any number of <attrib>=<value> pairs separated a single tilde, i.e.:

@<attrib>=<value>~<attrib>=<value>~...<attrib>=<value>~~

Attrib | Value | Description
ImgSiz | <width>,<height>,<bpp> | width, height (in pixels), bits per pixel. All images for the toolbar will be scaled to the specified size (although the quality will be best if the original images are already of the specified size). For bpp < 32, you must specify the MBF2_GDIPLUS ctype2 flag when creating the control in order to support some of the more advanced options, like the automatic transparency and ImgDis/ImgHot features.
ImgDir | <default directory> or standard icon set id | (optional) Default location for images, which avoids need to specify the full directory for each individual image. May be in native format (e.g. ImgDir=c:\images\toolbars) with or without %env% variables, or AMOS format. Note that A-Shell and ATE will also look in the their own default locations if not found here. To use one of the standard icon sets built in to Windows, specify the id # here in place of a directory; see Using Windows Native Icons below.
ImgCount | # of images to expect | (optional) estimate of the number of images in the toolbar. Simply improves the efficiency of memory allocation operations.
ImgDis | <rop>{,<suffix>} | (optional) Rendering OPtion and suffix for disabled version of images. Rop 0 is the standard Windows scheme; 1 uses an A-Shell alternate algorithm for generating the disabled/gray version of the image. If the suffix is specified, A-Shell looks for an alternate image file to use for the disabled image. For example, if the img file is clickme.png and <suffix> is _d, then it will look for clickme_d.png. See following topic Disabled and Hot Images.
ImgHot | <rop>{,<suffix>} | (optional) Rendering OPtion and suffix for hot version of images. Same concept as for ImgDis except for the "hot" version of the image (displayed when the mouse is hovering over it). See following topic Disabled and Hot Images.

btndefs

define each individual button. Each btndef clause is made up of a series of <attrib>=<value> pairs, each delimited by a single tilde with the entire clause terminated by a double tilde, i.e.:

<attrib>=<value>~<attrib>=<value>~...<attrib>=<value>~~

Attrib | Value | Description
img | Image specification or standard icon id | The image to load for the button. If no directory specified, the default directory (see ImgDir in the toolbarattribs) is used. Note that only discrete PNG files are properly supported. If using standard built-in icons, specify the icon id number instead of the image file specification; see Using Windows Native Icons below.
cmd | command string | May be any of the following: keyboard client string (e.g. VK_xF201, VK_ESCAPE, etc.) MENUID:<menu identifier> (see Edit Menu Control) CMDLIN:<windows command line> (see HOSTEX) SHLEXC:<url or file object> (see MX_SHELLEX)
lbl | Label text | (optional) If specified, text will display either under the button (for toolbar winstyle TBLSTYLE_FLAT) or to the side of the button (winstyle TBSTYLE_LIST). Note that in the typical toolbar aesthetic style, label text for the buttons is omitted, relying instead of tooltips to clarify the function of each button. You cannot have both labels and tooltips, so either specify the lbl attribute or the tip attribute, but not both.
tip | Tooltip text | (optional) If specified (and lbl not specified), establishes the tooltip to display when the mouse hovers over the button.
id | Button ID | (optional) unique identifier for the button. Mainly used as a way to identify the button later for the purpose of enabling/disabling or otherwise altering it. You may also use the cmd string or the ordinal button position, but this approach probably makes for more readable and robust code.
enabled | 0,1 | (optional) state. Defaults to 1 (enabled)
type | SEP | (optional) type of button. Currently the only available type is SEP (separator). Separators require no other attributes, and normal buttons do not require the type attribute.
opaque | 0,1 | (optional) If set to 1, the image background will be displayed as opaque; otherwise it will be transparent. For images with bpp < 32, requires the MBF2_GDIPLUS flag when creating the toolbar. Note that 32 bit PNG images are assumed to be pre-configured with the alpha channel controlling transparency; for other image types, the first pixel determines the background color, which is converted to match the toolbar background.

winstyle and winstylex

Aside from the toolbarattribs in the ctext parameter, other global attributes of the toolbar control are set via bits in the winstyle and winstylex parameters, including:

Winstyle Symbol | Value | Description
TBSTYLE_WRAPABLE | &h00000200 | Wrap-able text labels (applies only with horizontal toolbars)
TBSTYLE_FLAT | &h00000400 | Standard toolbar style; any button labels appear beneath the buttons
TBSTYLE_LIST | &h00001000 | Alternate style; labels appear to right of buttons
CCS_TOP | &h00000001 | horizontal toolbar along top of window (default)
CCS_BOTTOM | &h00000003 | horizontal toolbar along bottom of parent window
CCS_LEFT | &h00000081 | vertical toolbar along left edge of parent window
CCS_RIGHT | &h00000083 | vertical toolbar along right edge of parent window
WS_BORDER | &h00800000 | gives toolbar a thin black border

Winstylex Symbol | Value | Description
WS_EX_CLIENTEDGE | &h00000200 | gives toolbar a beveled edge

Note that attempting to add a toolbar in a position already occupied by a toolbar automatically deletes the prior toolbar.

Sample Program

This sample program creates a top toolbar with various types of 16x16x32 buttons It illustrates using CTLOP_CHG mode to disable buttons, and CTLOP_DEL to remove the toolbar.

++include ashinc:ashell.def

map1 ctext$,s,0

map1 winstyle,b,4

map1 a,b,1

! global attributes

ctext$ = "@" ! beginning of global options

ctext$ += "ImgDir=C:\vm\miame\images~"

ctext$ += "ImgSiz=16,16,32~"

ctext$ += "ImgCount=5~"

ctext$ += "ImgDis=1~" ! alternate rendering of disabled images

ctext$ += "~" ! end of global options

! buttons that simulate menu items

ctext$ += "id=copy~img=copy_16.png~tip=Copy to clipboard~" &

+ "cmd=MENUID:"+IDM_COPY+"~~"

ctext$ += "id=paste~img=paste_16.png~tip=Paste from clipboard~" &

+ "cmd=MENUID:"+IDM_PASTE+"~~"

ctext$ += "type=SEP~~"

! buttons that simulate keyboard keys

ctext$ += "id=up~img=nav_up_16.png~tip=Up one field~" &

+ "cmd=VK_UP~~"

ctext$ += "id=down~img=nav_down_16.png~tip=Next field~" &

+ "cmd=VK_DOWN~~"

ctext$ += "type=SEP~~"

! buttons that generate pseudo-function exitcodes

ctext$ += "id=bskip~img=nav_left2_16.png~tip=Back 10 recs~" &

+ "cmd=VK_xF501~~"

ctext$ += "id=fskip~img=nav_right2_16.png~tip=Forward 10 recs~" &

+ "cmd=VK_xF502~~"

ctext$ += "type=SEP~~"

! button to launch a windows app

ctext$ += "id=calc~img=calc_16.png~tip=Calculator~" &

+ "cmd=CMDLIN:calc.exe $~~" ! note $ so as not to wait for it

! button to launch a URL

ctext$ += "id=home~img=house_16.png~tip=MicroSabio Home Page~" &

+ "cmd=SHLEXC:http://www.microsabio.com~~"

winstyle = TBSTYLE_FLAT or CCS_TOP

xcall AUI, AUI_CONTROL, CTLOP_ADD, "tb1", ctext$, &

MBST_ENABLE, MBF_TOOLBAR, NUL_CMD$, NUL_FUNC$, NUL_CSTATUS, &

0, 0, 0, 0, NUL_FGC, NUL_BGC, &

NUL_FONTATTR, NUL_FONTSCALE, NUL_FONTFACE$, NUL_TOOLTIP$, &

NUL_PARENTID, NUL_WINCLASS$, winstyle, NUL_WINSTYLEX, &

NUL_CTYPE2

input "Enter to disable '^' and '<<' buttons...",a

ctext$ = "=up:enabled=0~~=bskip:enabled=0~~"

xcall AUI, AUI_CONTROL, CTLOP_CHG, "tb1", ctext$, MBST_CHANGEX

input "Enter to delete the toolbar ",a

xcall AUI, AUI_CONTROL, CTLOP_DEL, "tb1"

Using Windows Native Icons

It is also possible to create toolbars using one of the sets of button images which are built in to Windows. Each toolbar can contain images from one of these built-in sets, or can contain discrete images loaded from PNG files, but not a mixture. To use one of the built-in image sets, include the file ashinc:toolbarstd.def, set the ImgDir= attribute to the identifier for one of the sets (e.g. IDB_STD_SMALL_COLOR), and each img= attribute to the identifier for one of the buttons within that set (e.g. STD_FILEOPEN). For example:

! toolbarattributes:

ctext$ = "@"

ctext$ += "Imgdir="+IDB_STD_SMALL_COLOR+"~" ! std small color images

ctext$ += "ImgSiz=16,16,24~~" ! 16x16, 24 color

! buttons

ctext$ += "id=fnew~img="+STD_FILENEW+"~tip=New file~cmd=VK_xF601~~"

ctext$ += "id=fopen~img="+STD_FILEOPEN+"~tip=Open files~cmd="VK_xF602~~"

History

2013 November, A-Shell 6.1.1368: MBF_TOOLBAR enhancement: it is now possible to split the top and bottom toolbars into two separate toolbars so as to left justify one set of buttons and right-justify the other. Within any single toolbar, all of the buttons get justified as a group. To accomplish this, set the ecol parameter to the desired ending column (main window column grid units) for the left toolbar, and ecol to the starting column for the right toolbar. All the other coordinates should remain zero, as they do for the normal toolbar configuration. Note that to avoid a seam in the middle where the two toolbars meet, you may want to set the TBSTYLE_FLAT option in the dwstyle parameter.

2013 August, A-Shell 6.1.1359: ImgDis and ImgHot toolbarattributes added. Bottom toolbar position moved to above bottom status and session lines.

2013 July, A-Shell 6.1.1358: Background transparency is now automatic for all image formats; previously it only worked with PNG ARGB images. To force the background to remain opaque, you can add the new btndef (button definition) clause: opaque=1. For example: tbdef$ += "img=clickme.bmp~opaque=1~lbl=Click me~" ...

2013 July, A-Shell 6.1.1355: MBF_TOOLBAR added to A-Shell

Subtopics

Disabled and Hot Images


Disabled and Hot Images

Added October 2013

Note: These are the release notes that accompanied the introduction of new button attributes to improve rendering of disabled and hot images:

ImgDis=<rop>{,<suffix>}

ImgHot=<rop>{,<suffix>}

The rop parameter (short for Rendering OPtion) determines the algorithm used when automatically rendering the button images in the disabled (gray) or hot (highlighted) states. Set rop to 0, or omit the clause entirely, for the default effect applied by Windows, or set it to 1 for an alternate effect applied by A-Shell.

The optional suffix clause may be used to specify separate images for the disabled and/or hot version of each button. A-Shell will look for image files matching the base image, with the specified suffix. For example:

Img=clickme.png~ImgDis=0,_d

In the above case, the file clickme.png will supply the normal image. A-Shell will look for clickme_d.png for an alternate image to use when the button is in the disabled state. If the clickme_d.png file is not present, the disabled version will use the same base image as the enabled version, with the standard Windows disabled/gray effect.

Note: rop option 1 requires GDIPlus, which is activated automatically for 32 bpp images; see toolbarattribute ImgSiz=w,h,bpp. Otherwise you must explicitly specify the MBF2_GDIPLUS option in the AUI_CONTROL ctype2 parameter when creating the toolbar.


ATE Optimization

In the ATE environment, any operation that requires a return status or other response from the client workstation introduces a small delay. The delay is not significant when doing just a few operations, but it can add up when large numbers of operations are performed in sequence. The simplest way to minimize the problem is to not ask for a returned status (see cstatus) or ctlid when creating controls (assuming that you do not need to use the ctlid later.) But when you do need a return status or control ID, then an alternative way to speed up the communication with the client is to create a batch. See Batch Operations.


Control names

Controls may be given names, which can then be used instead of the ID numbers to reference them. To assign a name to a control when creating it, specify a string parameter with the desired name in place of the CTLID parameter, i.e.:

CTLNAME$ = "Cus-cbTaxExampt"

PARENTNAME$ = "dlgCustomer"

xcall AUI, AUI_CONTROL, CTLOP_ADD, CTLNAME$, CTEXT$, CSTATE, CTYPE, CMD$, FUNC$, CSTATUS, SROW, SCOL, EROW, ECOL, FGC, BGC, FONTATTR, FONTSCALE, FONTFACE, TOOLTIP, PARENTNAME$, WINCLASS, WINSTYLE, WINSTYLEX, CTYPE2, CAUXDATA

In the example above, the string variable CTLNAME$ is being used in place of the normal numeric CTLID parameter (which normally returns the ID of the newly created control). Since we are assigning the name "Cus-cbTaxExempt" to the control, we probably don't need to get back the numeric control ID, but in case you do want to save it, it will be in the CSTATUS parameter. (Previously CSTATUS was set to 0 for success; now, if a string name is used in place of the CTLID parameter, CSTATUS will return the ID #.)

Similarly, the PARENTID parameter may be replaced with a string name in order to reference the parent by its name rather than number.

Control names should be unique across all controls used within a single program. You may want to adopt a naming standard which includes a prefix for the dialog and perhaps another prefix to identify the control type, as in our example above, where "Cus-cbTaxExempt" is meant to indicate that it is part of the Cus dialog, and it is a checkbox (cb). Names may be up to 23 characters long, plus a trailing null.

You can retrieve the control ID # associated with a control name, or vice versa, using the CTLOP_INFO opcode. To get the ID # associated with the name, just use CTLOP_INFO with the name in place of the CTLID parameter; the ID # will be returned in CSTATUS (just as when the control was created). For example:

xcall AUI, AUI_CONTROL, CTLOP_INFO, CTLNAME$, CTEXT$, CSTATE, CTYPE, CMD$, FUNC$, CSTATUS

if CSTATUS > 0 then CTLID = CSTATUS

To get the name associated with a control ID #, specify a string variable in place of the CTLID parameter, that contains the string representation of the control ID #, e.g.:

CTLNAME$ = str(CTLID) ! e.g. "7"

xcall AUI, AUI_CONTROL, CTLOP_INFO, CTLNAME$, CTEXT$, CSTATE, CTYPE, CMD$, FUNC$, CSTATUS

In this case, the CTLNAME$ parameter will be updated on return, with the name of the control.

A new "Name" column has been inserted into the Control Dump, providing a convenient way for you to verify how your control names and numbers are matching up.

Note that although you may specify a name for the PARENTID parameter, the name is converted to the equivalent number at the time the control is added. So the PARENTID name doesn't show in the control dump. But the CTLOP_INFO command will return the PARENT control name if you specify a string variable in place of the PARENTID parameter.

Also note that for controls and functions that do not currently support a convenient means of specifying a symbolic name for the control ID or parent ID when creating the control (e.g. XTREE, XTEXT, EVENTWAIT), you have to convert the control names to ID numbers (using CTLOP_INFO if necessary).

The symbolic names are currently supported in all forms of AUI_CONTROL, AG_CONTROL, MX_AUTOPARENT and AUTO_PARENT.


Scaling Logic

Scaling logic applies to dialogs immediately, and the ALTPOS grid basis has changed slightly. Unfortunately this will likely have a minor effect on the width of existing dialogs using ALTPOS, but the new formula is slightly more natural, and virtually eliminates the need for the strange 160 default width scale in the Dialog Sizing dialog. Consequently, existing dialog sizing scale factors will be reset to 100 for existing .ash files. (Once you re-save any settings, your saved settings will be preserved.)

For dialogs using the ALTPOS grid, the grid basis continues to be the size of a character in the default GUI font. The actual grid row height is equal to the height of a combo box plus the external leading, and the grid column width is about half way between the "average" and maximum character width for the default GUI font. Unlike before, the default GUI font is scaled according to the scale factor in the Misc. Settings dialog. Since scaling that font also affects the height of combo boxes and the average character width, the entire grid scales along with the font scale factor.

For example, with the font scale factor set to 0 or 100, the dialog grid will be based on the default size of the default GUI font. (This is the font you see in menu bars and in most standard Windows dialogs.) If you change that to, say, 90, then the dialog and everything in it should get about 10% smaller. (Scaling isn't entirely linear or orthogonal, but that's approximately the idea.)

Related to this, the Dialog Sizing dialog offers a new option of whether to include the dialog caption in the dialog height when forcing dialogs to use the grid based on Font Size (i.e. ALTPOS units). Normally, dialogs using the font-size or ALTPOS grid are sized so that they have the expected number of rows not counting the caption bar. For example, if SROW = 1 and EROW = 10, then there will be room for 10 logical rows inside the dialog. This is quite convenient and logical, but conflicts with the way non-ALTPOS (main-window based) dialogs are sized, since they include the caption in the height. So in our example of SROW=1 and EROW=10, the outer height of the dialog would be equivalent to 10 rows in the main window, but since that includes the caption, you'll probably end up with something closer to 9 rows.

This causes a problem when trying to convert dialogs to the ALTPOS grid, because you almost always end up with the equivalent of one extra row in the dialog. The new option in the Dialog Sizing dialog to include the caption in the dialog height should help you counteract that. Note however, that it only has an effect on dialogs that weren't explicitly coded to use MBF_ALTPOS. (The theory is that if you coded the dialog to use the ALTPOS grid, then you were counting on the number of rows. But if you coded it to use the main window grid, and then we force it to use the ALTPOS grid via the option on the Dialog Sizing dialog, then you probably don't want the extra row.

Another side effect of the new scaling logic is that you can indirectly resize an active dialog by resizing the main window behind it.


Height of Controls

This change adjusts the logic used in determining the height of controls. This partially resolves an issue that became apparent in build 973 in which buttons at the bottom of ALTPOS dialogs suddenly got closer to the bottom than before, but, for worse or hopefully better, goes beyond that.

The new rule is that when the EROW coordinate of a control is expressed using regular rows (not millirows), then the control height will not include the external leading (see Misc. Settings dialog), unless it is a variation of edit control and the Misc. Settings option to allow edit controls to extend into the leading area is set. On the other hand, if the EROW coordinate was expressed in millirows, then the control height will include the external leading.

Previously, the second part of the rule was also contingent on the ALTPOS option. (Then, in 973, it was inadvertently changed so that as long as ALTPOS was in effect, millirows were not needed to get full-height controls.)

This sounds confusing, but hopefully the new rule is more logical and simpler than the old one. The idea behind it is as follows:

• When using regular row units, it is common to put controls in adjacent rows. In order for these to not appear too crowded (especially for buttons and other controls that have their own borders), it seemed logical to preserve the external leading area between the rows as empty space.

• But, when using millirows, the idea is that row N occupies millirows N*1000 to (N+1)*1000-1. (E.g., row 5 spans millirow 5000 to 5999.) Thus, if you actually asked for a control to occupy millirows 5000 to 5999, you would expect it to be right up to the edge of another control that started in millirow 6000. It would seem too confusing if the system automatically converted your request for a control spanning millirows 5000-5999 into one spanning millirows 5000-5850 in order to preserve the leading area.

This line of reasoning seems sensible whether or not ALTPOS is in effect. So, if you are updating from a previous version, it is possible that depending on whether you were using millirows and/or ALTPOS, that some of your buttons and edit boxes may get taller or shorter by the amount of the leading, but in the majority of those cases, the effect will probably be too small to matter much, or will be an improvement.

A sample program, TSTBTX in [9??,*] has been added to the EXLIB to illustrate the different button heights for different button styles.


Control Alignment

The following sample program (ALIGN.BP[908,24] in the EXLIB) illustrates the use of the various alignment options for text within static and button controls.

this is a linked image

The tooltip for each control shows details about the ctype and winstyle flags, and of course the source code reveals all, but here are the relevant flags from ctype:

Flag | Description
MBF_LFJUST | Left justify text
MBF_RTJUST | Right justify text
MBF_HCENTER | Horizontally center text
MBF_VCENTER | Vertically center text
MBF_CENTER | Vertically and horizontally center text

BS_TOP (&h00000400), BS_BOTTOM (&H00000800), BS_VCENTER (&h00000C00) can be added to the WINSTYLE parameter for buttons to adjust the vertical alignment of the text within the button. The horizontal alignment can be adjusted by the traditional MBF_RTJUST and MBF_LFJUST flags. Note: default alignment for buttons is centered in both directions.

SS_CENTERIMAGE (&h00000200) can be added to the WINSTYLE parameter for static images (scaled with MBF_NODISTORT and without any other MBF_xxx alignment options) to center them within the static control, without changing the size of the control. See the STIMGT.BP[908,32] sample program.

See Image Control for an example of using these same flags for aligning images within Static Text controls, and see the cstate MBST_?CENTER flags for options relating to centering the control itself (relative to its parent).


AUI_EVENTWAIT

xcall AUI, AUI_EVENTWAIT, parentid, ctlid, exitcode {, opflags {,timer}

The AUI_EVENTWAIT class is really less of an independent "class" than a method relating to the CONTROL class, but is separated out for parameter organization convenience. Its purpose is simply to wait for an event, allowing the user to shift the focus among a range of buttons (plus some other control types) until something is clicked which triggers an event. It could be implemented using an invisible INFLD call in a loop, but this is much simpler to program.

The basic concept is analogous to the dialog manager in Windows or forms manager in VB, which allows the user to move around the form or dialog until some event is triggered that requires the dialog or forms manager to exit (temporarily or permanently) back to the application. In Windows/VB this is done by calling special event handler routines in the application. In A-Shell, this is done by returning from the routine with an exitcode and control ID and leaving it to the application to perform whatever action it deems suitable, after which the application can return to the eventwait (or not).

Aside from simplifying the coding of event-driven programs, AUI_EVENTWAIT can often be useful for converting legacy programs which prompt the user to enter a field number to edit, or to choose among a handful of commands that might otherwise be represented as buttons. In the legacy case, the program would be waiting for only one kind of event (the entry of a field number or menu command.) With AUI_EVENTWAIT, the program logic is nearly the same, except that instead of keying in a command, the user can select a field to edit or operation to perform by either clicking on something that generates an exitcode, or by using the Arrows and Tab and Shift+Tab keys to move the focus around a collection of buttons or other controls and hitting Enter to generate the equivalent of a click.

There are several options relating to managing which control gets the focus to start with, which controls can get the focus, and what kinds of events generate exitcodes.

Although AUI_EVENTWAIT will exit on any click event that generates an INFLD-style exitcode, it only allows the focus to be moved (via Arrows and Tab and Shift+Tab) to a limited subset of controls that can take the MBF_TABSTOP style. Standard pushbuttons automatically get this style, while it can be manually added to checkboxes and radio buttons when they are created. In the case of INFLD controls, there is no way to specify the MBF_TABSTOP style when creating them, but you can pass the EVW_INFLD flag to AUI_EVENTWAIT to temporarily confer that style on all INFLD controls in the scope.

Note that this function was originally designated as MX_EVENTWAIT and MX_BTNIDLE.

Subtopics

AUI_Eventwait Parameters

Eventwait Comments


AUI_Eventwait Parameters

Parameter | Type | I/O | Description
parentid | String or Num | in | Specifies a parent control to which the button controls of interest are children to. Leave zero if not applicable. See below.
ctlid | String or Num | in/out | ID of the control which should start with the focus. If zero, the first control within the group specified by parentid will start with the focus.
exitcode | Num | in/out | (Signed Num) Returns a code indicating the event received.
opflags | B,4 | in | Flags affecting operation.
timer | Num | in | Optional numeric argument which can be set to the number of milliseconds to wait for an event before the eventwait times out with exitcode 11.


parentid

Update February 2011

The parentid parameter determines the scope of the controls to which the focus can be moved using the Tab and Arrow keys, while waiting for an event. Note that unless the flags EVW_DESCEND and/or EVW_SIBLINGS are set, the focus will be limited to direct children of the specified group or dialog. To clarify this, consider the dialog below:

This dialog is made up of at least 3 groups. (The two buttons at the bottom may be direct children of the dialog, or they may be in their own invisible group, which is common but hard to detect visually.) If we set the parentid to the ID of the dialog, and do not set the EVW_DESCEND flag, then the user would not be able to move the focus to the radio buttons and edit boxes within the groups, because those are all grandchildren (rather than direct children) of the dialog. If the two icon buttons at the bottom were direct children of the dialog (not part of their own invisible group) then the focus would be limited to those two buttons. (That is, the Tab and Arrow keys would not permit the focus to be moved into any of the groupboxes.) The user, could, however, use the mouse to click on anything that generates an exitcode.

Similarly, if the parentid was set to the ID of the group "Destinos", then, the user could Arrow or Tab around within that groupbox but not go directly to another groupbox without first existing from the event wait operation (unless the EVW_SIBLINGS flag was set.).

History

2011 February, A-Shell 5.1.1205: You can now pass alphanumeric IDs for the parentid and ctlid parameters. This eliminates one of the most common excuses for needing a numeric control ID. Note, however, that the updated ctlid parameter will be returned as a number (although formatted as a string if you pass a string parameter). This shouldn't make any difference to your application as a string-formatted numeric control ID may be used anywhere an alphanumeric control ID may be used.


ctlid

Update February 2011

The ctlid parameter is often set to zero, which causes EVENTWAIT to initially put the focus on the first control within the specified parentid. On exit, it will be automatically set to the ID of the control that last had the focus (or was just clicked on). Setting the ctlid to a specific control ID will cause the focus to start there.

If the specified ctlid does not exist, EVENTWAIT returns exitcode 99. Also note that if ctlid does exist, but is not in the group you specified by parentid, then the results might be unpredictable.

History

2011 February, A-Shell 5.1.1205: You can now pass alphanumeric IDs for the parentid and ctlid parameters. This eliminates one of the most common excuses for needing a numeric control ID. Note, however, that the updated ctlid parameter will be returned as a number (although formatted as a string if you pass a string parameter). This shouldn't make any difference to your application as a string-formatted numeric control ID may be used anywhere an alphanumeric control ID may be used.


exitcode

Exitcode returns a code indicating the event received. Typically this would be the exitcode associated with a mouse click on an object, or a particular keystroke or timer event. The actual values are generally consistent with INFLD, or XTREE, or both, to facilitate a single exitcode-handling routine that covers all three.

To avoid confusion between control-identifying exitcodes (i.e. those generated via the click string associated with a control) and navigational exitcodes (such as those in the following table), you should avoid assigning control-identifying exitcodes in the range of -100 to 100. See the cmd parameter of AUI_CONTROL, the hlpidx parameter of INFLD, and the XTR'KBDSTR (xtrctl) parameter of XTREE for information on how control-identifying exitcodes are defined.

Note that buttons with exitcode values -1 thru -32 may be used with EVW_EXCDINOUT. This allows buttons that emulate the standard function keys to be used with EVW_EXCDINOUT.

Exit Code | Flag(s) | Description
0 | EVW_NUMERIC | number + enter
0 | EVW_RAW | any keystroke
1 |  | Escape
2 | EVW_HAREXIT | LeftArrow
3 | EVW_NOWRAP | Attempt to navigate up/back from end of group (instead of wrap)
3 | EVW_VAREXIT | UpArrow
4 |  | PrevPage
5 | EVW_NOWRAP | Attempt to navigate down/forward from end of group
5 | EVW_VAREXIT | DownArrow
6 |  | NextPage
7 | EVW_TABEXIT | Tab
10 |  | Ctrl C
11 |  | Time out
12 | EVW_HAREXIT | Right Exit
99 |  | Invalid combination of parameter values (no matching control)
-35 | EVW_TABEXIT | Shift Tab
-36 | EVW_HAREXIT | Shift Left Arrow
-37 | EVW_VAREXIT | Shift UpArrow
-38 | EVW_HAREXIT | Shift Right Arrow
-39 | EVW_VAREXIT | Shift Down Arrow
-45 |  | Home
-46 |  | End
-47 |  | Del
-52 | EVW_CTLARROW, EVW_HAREXIT | Ctrl+Left Arrow
-53 | EVW_CTLARROW, EVW_VAREXIT | Ctrl+UpArrow
-54 | EVW_CTLARROW, EVW_HAREXIT | Ctrl+Right Arrow
-55 | EVW_CTLARROW, EVW_VAREXIT | Ctrl+Down Arrow
-56 | EVW_CTLCLIPBD | Ctrl+C
-57 | EVW_CTLCLIPBD | Ctrl+V
-58 | EVW_CTLCLIPBD | Ctrl+X
-60 | EVW_CTLCLIPBD | Ctrl+Z
-61 | EVW_CTLARROW | Ctrl+-(numpad minus)
-62 | EVW_CTLARROW | Ctrl+Plus (numeric keyboard)
-65 |  | Shift+Tab
-66 |  | Ctrl+PageDown
-67 |  | Ctrl+PageUp
-68 |  | Ctrl+Home
<= -100 | EVW_EXCDINOUT | No event, incoming exitcode passed through
-1 thru -16 |  | F1 thru F16
# |  | Right click on control with VK_xrF# clickstring
-# |  | Left click on control with VK_xF# clickstring


opflags

Updated November 2013

opflags specifies any sensible combination of the symbols below (symbols defined in ashell.def):

Symbol | Value | Description
EVW_NEXT | &h000001 | Set initial focus on control following the one specified by ctlid. Generally not used, particularly if ctlid = 0, since the focus will automatically be placed on the first control within the specified parent group.
EVW_NOWAIT | &h000002 | Set the focus and return (do not wait for an event). This is a bit of an oxymoron, since it directly contradicts the idea of waiting for an event, and thus is only useful in very limited circumstances, where you just want to put the focus on a control while doing some time consuming calculations.
EVW_NOWRAP | &h000004 | Exit from the wait operation with EXITCODE 3 or 5 rather than wrap.
EVW_NOFOCUS | &h000008 | This is another exotic switch, which eliminates the initial step of setting the focus on an appropriate control when starting the eventwait. Probably the only situation where it would be useful is if, due to the context of the program, the application knew that it wanted to start with the focus where it currently was, without knowing where that was..
EVW_NUMERIC | &h000010 | Allow keyboard input.
EVW_DESCEND | &h000020 | Expand scope to include grandchildren, great-grandchildren, etc.
EVW_SIBLINGS | &h000040 | Expand scope to include siblings of parentid.
EVW_INFLD (or) EVW_EDIT | &h000080 | Allow navigation keys to move the focus to editable fields, such as EDIT, COMBO, DATE/TIME and XTREE controls. Otherwise EVENTWAIT ignores controls except for buttons and controls with the MBF_TABSTOP flag explicitly set. (Standard push buttons get this flag automatically.) Note that unlike the case with buttons, when EVENTWAIT puts the focus on an editable field, it actually returns to the application with the same exitcode as if the field had been clicked (allowing the application to take over the editing operation.)
EVW_PREV | &h000100 | This is the inverse of the EVW_NEXT option, and was provided mainly to satisfy some arcane notion of symmetry.
EVW_SQUELCH | &h000200 | Squelch radio button exits on focus change.
EVW_TABEXIT | &h000400 | This option overrides the normal behavior of the Tab and Shift+Tab, so that instead of advancing the focus, they simply exit, with exitcode 7 and -35, respectively.
EVW_ACCEL | &h000800 | Allow "accelerator" keys.
EVW_RAW | &h001000 | Raw keyboard input.
EVW_HAREXIT | &h002000 | Exit on horizontal Arrows. Exitcodes: Left=2, ShiftLeft=-36, Right=12, ShiftRight=-38
EVW_VAREXIT | &h004000 | Exit on vertical Arrows. Exit codes: Up=3, ShiftUp = -37; Down = 5; ShiftDown = -39
EVW_EXCDFOCUS | &h010000 | Incoming exitcode overrides CTLID.
EVW_EXCDINOUT | &h040000 | Like EVW_EXCDFOCUS; see detailed description.
EVW_CTLARROWS | &h080000 | May be added to EVW_VAREXIT or VAR_HAREXIT to cause Ctrl+Arrow to return a unique exitcode (offset by -16 from the Shift+Arrow exitcodes). Without this qualifier, Ctrl+Arrow returns the same exitcode values as the arrow keys by themselves. EVW_CTLARROWS also causes Ctrl+Plus and Ctrl+Minus- (i.e. Ctrl in conjunction with the Plus and Minus keys on the numeric keypad) to return EXITCODEs -62 and -61, respectively.
EVW_CTLCLIPBD | &h100000 | Causes the normal Windows clipboard shortcuts to be returned as exitcodes: ^C=-56, ^V=-57, ^X=-58. Also causes ^Z to return EXITCODE -60.
EVW_NODELAY | &h200000 | Removes the timer filter that normal restricts click events for a single control to one per 1/2 second. This is normally useful for preventing (click bounce), but in some cases (like a scroll button), you may want to allow more rapid click response by specifying this flag.
EVW_ENTER | &h400000 | Causes the ENTER key to return exitcode=33, instead of acting like a click on the currently focused control. This might be useful to implement a default action that was independent of the currently-focused button. Note that you can identify the currently-focused button from the returned ctlid parameter.
EVW_ULFOCUS | h00800000 | Clickable static text controls are highlighted to indicate when they have the focus. The default highlight effect is a dotted line around the perimeter of the control. As an alternative, you can specify this flag (EVW_ULFOCUS), which changes the highlight effect to the combination of bold+underline. Note: PNG and GDIPLUS images are excluded from this treatment on the theory that they are amenable to a more sophisticated highlighting approach.

Hex-Decimal Values

History

2013 November, A-Shell 6.1.1368: Added EVW_ULFOCUS flag


EVW_NOWRAP

This option controls what happens when keyboard navigation commands (Arrows, Tab, Shift+Tab) are used to move the focus around within a group of controls and you hit the "edge". If the flag is not set, then the focus will "wrap" around to the first control in the group. Otherwise, the eventwait operation will exit, setting EXITCODE 3 (up, left) or 5 (down, right) depending on which direction the group was exited. (The ctlid parameter will also be set to identify the last focused control, so the distinction between exitcode 3 and 5 may not be that important.)

As an example, consider the Tab Control Example dialog above, which features a groupbox containing three buttons. In the default case, without EVW_NOWRAP, hitting the Left/Right Arrows, or Tab/Shift+Tab keys, will just move the focus around in a circle between the buttons. The user will have to click on one, or hit Enter to exit from the eventwait. If the user wanted to edit one of the fields in the tab pane, they could click the "Edit" button. As an alternative, you could use the EVW_NOWRAP flag, in which case, merely using the arrow keys would trigger an exit from the eventwait, allowing the program to refocus on one of the edit fields. (See EVW_SIBLINGS and EVW_DESCEND flags for other approaches to allowing the user to navigate around the dialog.)


EVW_NUMERIC

This switch allows you to also accept "events" consisting of a string of numeric digits followed by <ENTER> . This is particularly useful when migrating from text-mode (or power-user) environments where users are accustomed to selecting fields or menu options by keying in the corresponding number and hitting <ENTER>. When you start adding clickable controls to such screens, you may want to replace the "Enter Field #" prompt with an EVENTWAIT operation, allowing the user the choice of either clicking on a control (possibly generating an exitcode or a keyboard string simulating what the user could have typed to make that selection), or just typing the desired option # and hitting Enter.

Note that these numeric keyboard "events" are returned to the calling program with exitcode set to 0, and ctlid set to the numeric value entered. Since the returned ctlid may not have anything to do with a valid control ID, take care not to pass the value back as input to a subsequent EVENTWAIT operation (or else it will probably abort with exitcode 99, meaning invalid control ID.) In other words, after interpreting the returned ctlid, set it back to either 0 or to the ID or a valid control on which you want to place focus for the next EVENTWAIT.

See EVW_RAW for a similar option.


EVW_DESCEND

This flag allows the focus to be moved (via the keyboard Arrows and Tab/Shift+Tab) into child subgroups of the parentid. Otherwise keyboard navigation is limited to the immediate group. For example, in the sample dialog above (see parentid) there are three or four separate groups in the dialog. If you start an eventwait with parentid set to one of them but the EVW_DESCEND flag not set, the user will be able to navigate around the controls in that group, but not leave the group (except by clicking or some other event that triggers an exitcode). This might be useful if you wanted to do some validation logic on the group as a whole before moving to another group. On the other hand, if you wanted to allow the user to navigate around all of the groups without requiring program intervention, then you could set the parentid to the ID of the dialog itself and set the EVW_DESCEND flag.


EVW_SIBLINGS

This flag is similar in concept to the EVW_DESCEND, except that it extends the scope of controls which can be navigated to via keyboard navigation commands to groups and controls that have a sibling relationship to the parentid. The effect is essentially the same as if instead of setting parentid to a particular group, you set it to the parent of that group (or the dialog ID), and set the EVW_DESCEND flag.


EVW_SQUELCH

This oddly named feature, like its namesake in the world of radios, turns down "the noise" when navigating among a collection of radio buttons. With buttons and checkboxes, the focus can be moved from one control to the next without actually changing the selection. But with radio buttons, the act of changing the focus with the Arrows also changes the selection, and thus is essentially the same as clicking on a button. If each button has an exitcode associated with it, then each time you hit the Arrow key to move to the next radio button, the eventwait will exit. This might be appropriate when, depending on which radio button is selected, you might need to enable/disable some other controls in the dialog. For example in the output dialog above (see parentid), if you select the printer option, then you would want to enable the combo box containing the list of printers, and set the focus on it. But if you selected, say, PDF output, then the printer selection combo box can be disabled, along with the Copies option. The immediate exitcode as you move the focus among the radio buttons allows the program to perform these actions.

But if you do not need to perform any immediate action just because the radio button selection was changed by arrowing through the group, then use the EVW_SQUELCH option, and wait for some more important event to terminate the eventwait, after which you can go back and query the buttons.

To advance the focus out of the current radio button group, without changing the currently selected radio button, use Tab (or Shift+Tab).


EVW_ACCEL

Updated June 2013; see History

This flag allows alphanumeric keystrokes to act as "accelerator" keys, automatically selecting and clicking on the matching control, if present. You can define an accelerator key association for a control by inserting a "&" in front of the desired character in the control's text. For example, a button defined using "E&xit" will use "x" as the accelerator key. (The & will not appear, but the subsequent character will be underlined.) In this case, hitting "x" will have the same effect as clicking on the button.

Note that the standard Windows keyboard accelerator formula (alt+key) does not require that EVW_ACCEL be specified.

History

2013 June, A-Shell 6.1.1354: When the EVW_ACCEL flag is set, underlining of the hot keys is now forced on. Previously, and otherwise, it follows the Windows convention, showing them if the last input event was a keyboard event and hiding them if it was a mouse event.


EVW_RAW

Causes nearly all keystrokes to be returned "raw" by setting the ctlid to the ASCII value of the keystroke and exitcode to 0. The only exceptions are the TAB, Shift+Tab, and Arrow keys, which retain their navigation function. This is similar to EVW_NUMERIC, in that the ctlid parameter is used to return a user-input code which has nothing to do with an actual control ID.

Since the returned ctlid may not have anything to do with a valid control ID, take care not to pass the value back as input to a subsequent EVENTWAIT operation (or else it will probably abort with exitcode 99, meaning invalid control ID.)


EVW_EXCDFOCUS

When this option is set, AUI_EVENTWAIT gives preference to the incoming EXITCODE value in deciding which control to initially set the focus on, using the following rules:

• If EXITCODE < 0 and not -35 through -42 (often used for Shift+Tab and Shift+Arrows) then it is interpreted as if the CTLID parameter had been set to the control whose click-string generates the specified EXITCODE. Provided that the control is of a type that is normally allowed to retain the focus by EVENTWAIT. If, for example, you define both a static text label and an INFLD field with the same EXITCODE click string, EVENTWAIT will skip over the label and activate the INFLD field.

• Else if EXITCODE is 2, 3, -35, -36, -37, -40 or -42 (LeftArrow, UpArrow, Shift+LeftArrow, Shift+UpArrow, Shift+Tab and shifted XTREE up/left) then the EVW_PREV flag is automatically set.

• Else if EXITCODE is 5, 7, 12, -38, -39 or -41 (Down+Arrow, Tab, Right+Arrow, Shift+Right, Shift+Down, Shift+Right in XTREE) then the EVW_NEXT flag is automatically set.

• Else it acts as if the EVW_EXCDFOCUS flag had not been set.

An example will make it clear why this is handy. Imagine a dialog containing some buttons and also several INFLD fields, where you are going to use AUI_EVENTWAIT. Previously, to start you might have set CTLID to the ID of a particular button. You can still do that, but since the logic of your application is probably built on the EXITCODE values rather than the control IDs, it will be easier to just set EXITCODE to the value corresponding to the desired control and use EVW_EXCDFOCUS. That's a minor improvement. But consider if you wanted to start on one of the INFLD fields. You would not call AUI_EVENTWAIT at all, rather you'd call INFLD. But this complicates your logic. If you just set EXITCODE to the value corresponding to the desired field (and specify EVW_EDIT) then AUI_EVENTWAIT will immediately return to you with the desired exitcode—which accomplishes nothing but simplifies your code since you do not have to have special logic for handling the initial focus.

The main improvement comes as you return to the AUI_EVENTWAIT after calling INFLD (or XTREE). If the user exits from the INFLD operation by hitting UpArrow (returning EXITCODE 3), previously you would have had to figure out what the control ID was for the control prior to that INFLD control (or at the very least, have logic to set the EVW_NEXT or EVW_PREV flags). Now, with the EVW_EXCDFOCUS flag, you can just go right back to the AUI_EVENTWAIT operation and let it decide what the next control to get the focus should be.

In other words, your dialog loop can probably now be simplified down to something like:

do

xcall AUI,AUI_EVENTWAIT, CTLID, PARENTID, EXITCODE, OPFLAGS

if <exitcode to exit dialog>

exit

else

call <field handler based on exitcode>

loop


EVW_EXCDINOUT

This flag is similar to EVW_EXCDFOCUS but just causes any incoming EXITCODE value of -100 or less to be "passed through" (i.e. returned directly) to the application. This is useful (in conjunction with EVW_EXCDFOCUS) for responding to button clicks that occur while INFLD has the focus. For example, you might have a structure like this:

do

xcall AUI,AUI_EVENTWAIT,CTLID,PARENTID,EXITCODE,OPFLAGS

if <exitcode to exit dialog>

exit

else

call <field handler based on exitcode>

loop

With just EVW_EXCDFOCUS alone, if the user clicks on a button while INFLD has the focus (in the "field handler" above), the subsequent EVENTWAIT would merely put the focus on the button without triggering it. (The first click would trigger an exit from the current INFLD, but it would take a second click on the button to invoke the "field handler" for the button, using the logic above.) With EVW_EXCDINOUT added to the OPFLAGS, the button click would cause the "field handler" to exit, as before, but now the EVENTWAIT would also exit, so that the new "field handler" for the button could be called. This is not an issue when clicking on an INFLD field, because the combination of EVW_INFLD+EVW_EXCDFOCUS would cause any attempt to put the focus on an INFLD field to just exit from the EVENTWAIT so that INFLD could be called.

Note that one situation where you might not want EVW_EXCDINOUT is if you want to explicitly put the focus on a button by specifying its EXITCODE, without forcing the button to get clicked.


Eventwait Comments

When converting from a traditional procedural program to an event-driven one, you will probably encounter situations where used to have an input prompt to wait for the user to select among many choices or confirm/cancel an operation. In the GUI model, such an input prompt may seem silly, since the layout of the screen (buttons, other things to click on) makes it obvious what the user needs to do without being prompted to type something. This EVENTWAIT class is perfect for such situations. Examples include:

• Menus, where in the text version you might have a prompt like "Enter Selection:" but now you have buttons.

• At the bottom of an input form, where in the text version you might have had an "Any Change?" prompt, but now you have buttons such as "OK" and "Cancel", with the implicit understanding that the user can just click on a field to edit it.

• Dialogs, especially those containing checkboxes and radio buttons (which do not require any special procedural coding and can instead just be queried upon exiting the dialog).

Although you do not need to specify a parent group, this concept is generally much clearer if you do group the relevant buttons within a parent. The best way to do this is with a Groupbox Control. Note that the group box need not take up any extra space or even be visible. (You can set its initial state to MBST_HIDE and its size to one row high, and place the buttons right on top of it.)

The BTNMNU.SBX routine encapsulates this logic in a wrapper making it easy to create and use (i.e. wait on) groups of buttons.

The TSTEVW sample program (see in EXLIB) provides detailed examples of using EVENTWAIT, both via BTNMNU.SBX and via AUI.SBR.

EVENTWAIT only allows the focus to be moved amongst controls that have the MBF_TABSTOP property. This property is automatic for regular buttons, and may be applied manually to check boxes and radio buttons. No other control type currently supports the MBF_TABSTOP property, although the EVW_INFLD flag will cause EVENTWAIT to act as if all INFLD controls had the MBF_TABSTOP property.


AUI_ENVIRONMENT

xcall AUI, AUI_ENVIRONMENT, opcode, guiflags

The AUI_ENVIRONMENT class keeps track of properties and capabilities of the interface environment that affect the kind of user interface a program should use. It supports two methods, get (0) and set (1) GUI flags. (As a practical matter you would probably never set any of these properties yourself. They are set automatically by A-Shell when a session is launched.) This routine is equivalent to MX_GUIFLG.

Support has been added for another opcode, 2, which is like 0 (get flags) but doesn't query the ATE client to find out if it has XP theme support or not. This is probably only useful within a repetitively-called SBX where you need to determine whether you can use ATE/GUI methods or must stick with text methods, but for performance reasons you want to avoid excessive communication with the client and it doesn't make any difference to your logic whether themes are active.

Values for guiflags are shown in the following table, and are defined in ashell.def.

Symbol | Value | Description
AGF_LWG | &h0001 | Local Windows w/ GUI (e.g. PCTDVG)
AGF_LWN | &h0002 | Local Windows w/o GUI (e.g. PCTDV)
AGF_ATE | &h0004 | Running on server via ATE connection
AGF_RWN | &h0008 | Remote windows (ATS)
AGF_TNT | &h0010 | Telnet
AGF_ASH | &h0020 | A-Shell
AGF_THEMES | &h0040 | XP Themes are active
AGF_HOLDKBD | &h0080 | Client currently holding kbd
AGF_ATERES | &h0100 | Currently waiting on ATE response
AGF_LOCWIN | &h0003 | Local Windows (AGF_LWN or AGF_LWG)
AGF_ANYWIN | &h000B | Any windows platform (_LWN or _LWG or _RWN)
AGF_GUIEXT | &h0005 | GUI extensions avail (AGF_LWG or AGF_ATE)
AGF_LWNATE | &h0007 | Local Windows or ATE
AGF_ATECLI | &h0200 | Running on ATE client (i.e. inside TELNET.LIT)
AGF_INPROC | &h0400 | TAB(-10,x) command in progress
AGF_DESIGN | &h1000 | Design mode
AGF_NOSTATUS | &h2000 | Disable the return of cstatus information

Hex-Decimal Values

Here are some examples of using this information. All of them would start with retrieving the current guiflags as follows:

xcall AUI, AUI_ENVIRONMENT, 0, GUIFLAGS ! retrieve GUI flags

Before creating a graphical user interface with components from the AUI CONTROL class, you might want to check for either AGF_LWG or AGF_ATE. Since these are combined in AGF_GUIEXT, we can simply check it as follows:

if (GUIFLAGS and AGF_GUIEXT) then ? TAB(-10,x);.....

If you wanted to display a file for the user, either using NOTEPAD (if applicable) or else EZTYP (if not), you might use the following logic:

if (GUIFLAGS and AGF_LOCWIN) then &

xcall HOSTEX,"NOTEPAD "+F$ &

else if (((GUIFLAGS and AGF_ATE)#0) and &

((GUIFLAGS and AGF_TNT)#0)) then &

call XFER'TO'PC :&

call LAUNCH'NOTEPAD'ON'CLIENT &

else &

xcall EZTYP,F$

In the above example, if running Windows locally, we can just launch NOTEPAD using HOSTEX.SBR. Otherwise, if running ATE on the client over telnet, we could transfer the file to the PC and then launch NOTEPAD, both of which could be done via Tab(-10,x) commands. Otherwise, we could just use EZTYP on the server. (You might also want to test for other telnet emulators, such as ZTERM, which are capable of doing file transfers and launching commands on the client, but that exceeds the scope of this example.) Note that when testing multiple AND conditions, you need the extra set of parentheses and the #0 test as shown above to get the desired effect. Otherwise the confusion between the logical and arithmetic AND in BASIC will cause the test to fail.

If you merely wanted to test whether you were running under A-Shell Windows or A-Shell/UNIX (or some other platform, presumably AMOS), you could do this:

if (GUIFLAGS and AGF_ASH) then ! running A-Shell

if (GUIFLAGS and AGF_ANYWIN) ! any Windows platform

? "A-Shell Windows"

else

? "A-Shell UNIX"

endif

else

? "Non A-Shell (AMOS?)"

endif

History

2006 January, A-Shell 4.9.949: The following will return the ATE version if the fourth parameter is specified and the client is ATE.

xcall AUI, AUI_ENVIRONMENT, 0, FLAGS {,ATEVER$}

Subtopics

AGF_NOSTATUS


AGF_NOSTATUS

Added November 2010

AGF_NOSTATUS may be set to disable the return of cstatus information from AUI_CONTROL CTLOP_ADD operations. This may be useful in programs which contain many individual AUI_CONTROL calls but where you don't care about the return status (and don't need to reference the control IDs, or are using alphanumeric IDs). This is equivalent to specifying NUL_CSTATUS (or "") for the cstatus parameter in each call, so it is mainly useful when you have a lot of code doesn't take that refinement into account (perhaps because it was originally written for a local Windows environment where there is no performance penalty for returning the status).

Use AUI_ENVIRONMENT with opcode 1 to set this flag. It remains set for the duration of the session, or until specifically reset.

Note that this is purely a server-side enhancement.

History

2010 November, 5.1.1196: Added to A-Shell


AUI_MENU

Reviewed July 2009

xcall AUI, AUI_MENU, opcode, menuid, mnutxt, mstate, mtype, cmd, func, mstatus {,dlgid, itemid}

xcall AUI, AUI_MENU, opcode, mdfspec, mstate, mstatus {,dlgid}

The AUI_MENU class deals with the A-Shell menu bar, offering methods for adding and deleting menu items. The first form of the syntax above (AUI_Menu Traditional Method) is the original method, which is still the most flexible, but most difficult to use. The second form (AUI_Menu Simplified Method) vastly reduces the amount of code you need to write.

Note:

• When the GUI trace is active, AUI_MENU operations are traced.

• This operation can only take place on a GUI-enabled client, either ATE or some form of A-Shell/Windows.

Samples

Several sample programs illustrating menu operations may be found in [908,35] of the EXLIB.

History

2009 November, 5.1.1166: A-Shell permits an unlimited number of menu items; the menu table expands automatically as need.

Subtopics

AUI_Menu Traditional Method

AUI_Menu Simplified Method

AUI_MENU Techniques and Tips


AUI_Menu Traditional Method

xcall AUI, AUI_MENU, Opcode, Menuid, Mnutxt, Mstate, Mtype, Cmd, Func, {Mstatus, Dlgid, Itemid}

For detailed info on each parameter, click on the parameter names above, or click through them using the table of contents, or navigate through them all with the "Next" button.


Opcode

opcode (Num) should be one of the following:

Symbol | Value | Meaning
MNUOP_CHK | 0 | No change to the menus; just check to see if a menu item exists
MNUOP_ADD | 1 | Add new menu items
MNUOP_STA | 2 | Change state of existing menu items
MNUOP_DEL | 3 | Delete menu items
MNUOP_POP | 4 | Displays a previously defined context or popup menu, supports millirows: xcall AUI, AUI_MENU, mnuop_pop, menuid, "", row, col, "", "", status {,dlgid}
MNUOP_DSP | 6 | Force menu to be redisplayed/updated (needed after adding menu items to a dialog)
MNUOP_RST | 7 | Resets main A-Shell menu.


MNUOP_RST

This opcode, added in A-Shell 5.1.1129 of 31 Oct 08, can be used to reset the main A-Shell menu back to the way it was when A-Shell was first launched:

xcall AUI, AUI_MENU, MNUOP_RST, 0, mnutxt, 0, 0, "", "", mstatus

As with other AUI_MENU commands, mstatus will be set to 0 on success. But on failure, it will return the negative version of the OS error #, which you can translate using MX_ERRNOMSG.

Mnutxt can be "" for the standard menu (aka "MIAMEMENU") or you may select a language specific menus by specifying "MIAMEMENU-xxx" where xxx is the LDF language definition (e.g. "SPA", "ITA", "POR", "FRE", "CDN" etc.) If there is no specific menu for the requested language, the default version (American English) will be used. In this case, the return status will be -2 (indicating that the requested menu was not found).

In the case of ATE, the menu items will be reset to the way they are at the start of an ATE connection.


Menuid

menuid (any type) specifies the top level menu number or its name, according to the following table:

Value | Meaning
< 0 | Negative numbers are used to identify context menus. The number itself is arbitrary and only serves to identify the menu (for the purpose of adding items to it, deleting it, or displaying it under program control). See Sample.mdf.
0 | Top level menu as a whole. Use this when adding or deleting an item that appears on the horizontal menu bar (which starts with items "File", "Edit", "Settings", "Help".
1 | The "File" menu. Use this to add or delete items to the drop down menu that appears when you click on "File".
2 | The "Edit" menu. Use this to add or delete items to the drop down menu that appears when you click on "Edit".
3 | The "Settings" menu. Use this to add or delete items to the drop down menu that appears when you click on "Settings".
4 | The "Help" menu. Use this to add or delete items to the drop down menu that appears when you click on "Help".
5 or <name> | This would be the number of the first item added to the top level menu bar. You could also refer to it by the same text that you specified as mnutxt when you added it. Use this to add or delete items to the drop down menu that appears when you click on this menu.
6 – 14 or <name> | Same idea as for five, but for the sixth through fourteenth items on the top menu bar.
1000+ | Custom menu item identifier established by setting Itemid when the parent menu created. (This method of associating menu items with the parent menu is more flexible than the position-based method, and allows for multiple levels of submenu nesting.)


Mnutxt

Updated May 2011

mnutxt (String) specifies the text that will appear in the menu item, and optionally, a bitmap or icon to display alongside the text. You may precede one letter with "&" to allow that letter to be used with the Alt key as a hot key for the menu. For example, "&Custom" would display as "Custom" and could be selected via Alt+C. You may append a right-justified suffix to the text by preceding it with a TAB character, i.e. chr(9). For example:

MnuTxt = "Calculator" + chr(9) + "F6"

mnutxt may also serve as the identifier for the menu item, allowing it to be selected for later deletion, so it should be a unique string.

To include a bitmap or icon alongside the menu text, precede the text with the bitmap or icon specification enclosed in vertical bars. You may also specify a desired size in pixels by appending "=##" to the end of the image spec, where ## is a number between 10 and 99. (The images are assumed to be square. If no size is specified, for standalone BMP files, the actual size of the bitmap will be used; for icons, the size will be set to 16x16, which is the standard size of a menu icon). Best results will be obtained when the actual image size (or, in the case of icons, when one of the available images) matches the target size.

The image specification can be in any of the formats accepted for standard Icon Control or Bitmap Control (AMOS-style or native fspec, and/or in the case of icons, a resourcename::dllname). In the case of ATE, the image file must be present on the ATE client; if not present in the specified location, ATE will also look in the %ATECACHE% and %ATEPERMCACHE% directories. (A typical strategy is to copy all of the images needed by ATE into the %ATEPERMCACHE% directory, possibly using the ATSYNC.LIT utility.) Some examples:

mnutxt = "|images:fopen.bmp|Open File"

mnutxt = "|help.ico[7,57]=64|Help"

mnutxt = "|%MIAME%\images\exit.ico=32|Exit"

mnutxt = "|paste::ashico1v|Paste"

See Menu Icons for more details and examples of menus with images.

When modifying or deleting custom menu items, you must identify the item by setting mnutxt to the text used when the menu was created. Using the ordinal position may work for modifications, but will fail to fully delete the item, making it impossible to re-add it later. Menuid should identify the parent menu. See Adding/Deleting Internal Menu Items for details on dealing with the built-in menu items.

History

2013 May, A-Shell 6.1.1351: Icon images can now be attached to context menu items, just as they can for normal menu items, using the same "|image|text" syntax.

2013 May, A-Shell 6.1.1351: "\t" can now be embedded directly in mnutxt to signify a TAB, as an alternative to concatenating a chr(9) as described above. This is particularly convenient when menu item text is stored in a data file rather than assembled dynamically. For example, the menu items in the sample context menu above can now be created with the following:

"Edit MIAME.INI \t F5"

"Calculator \t F6"

2009 July, A-Shell 5.1.1155: You can also reference built-in menu items by setting mnutxt to the string representation of the item’s internal command ID (in the range of 100-199); see the Internal Menu Modifiers table, above.

2009 July, A-Shell 5.1.1154: You can specify a bitmap or icon to display next to the menu item; see Menu Icons.


Mstate

mstate (Num) indicates the state of the menu item:

Symbol | Value | Meaning
MBST_ENABLE | &h00000000 | Enabled
MBST_DISABLE | &h00000001 | Disable (grayed out)
MBST_CHECKED | &10000000 | Menu item is checked (see MBF_CHKMNU and MBF_RADIOMNU in Mtype)
MBST_HILITE | &h20000000 | Adds visual highlighting to the item. Under Vista and later, the effect is quite subtle, and basically the same as what you get when the mouse hovers over an item.
MBST_DEFAULT | &h40000000 | Menu item is the default


Mtype

mtype (Num) specifies any valid combination of options from the following table:

Symbol

Value

Meaning

MBF_CMDLIN

&h00000000

Normal. Selecting the menu item causes the contents of cmd to be executed as a Windows command line, as if it had been executed via HOSTEX.SBR. As with HOSTEX.SBR, you can refer to the current A-Shell executable (and its current miame.ini file) via the macro symbol $ASHELL, and you can use the suffix characters available to HOSTEX.SBR. For example, "$ASHELL –e run armenu" would launch a new A-Shell instance, run the program armenu, and suspend the current session until armenu exited.

MBF_DLL

&h00000001

DLL. Selecting the menu item causes the function (func) with the associated DLL (defined in cmd) to be loaded and executed.

MBF_CHKMNU

&h00000004

Menu item is "checkable". See MBST_CHECKED in Mstate

MBF_RADIOMNU

&h00000008

Menu item is part of a radio button group. Same idea as MBF_CHKMNU except only one item in a group of contiguous radio button items may be selected.

MBF_SUBMNU

&h00000010

Submenu. Selecting the menu item will cause a submenu to appear. As of 5.1.1154, nested submenus are supported. To create a nested submenu, assign a unique Itemid to the parent item, i.e. the one with the MBF_SUBMNU type, and then specify that itemid in the Menuid of the child items (one or more of which can themselves be submenus).

MBF_SEP

&h00000800

Separator. Item displays a s horizontal separator bar. Separators cannot be selected and only serve to visually organize submenus. Even though separators do not display the mnutxt contents, they still need a unique mnutxt string to allow the item to be deleted later.

MBF_KBD

&h00010000

Keyboard. Selecting the menu item causes the contents of cmd to be forced into the keyboard buffer. This technique may minimize the impact on the program, since to it, menu selections may appear just like ordinary keyboard responses, but you have to be careful to disable such menus when the program context is not correct to interpret such responses. See cmd for further notes on designing and encoding keyboard sequences.

MBF_SHLEXC

&h00020000

Shell execute. Selecting the menu item causes the contents of cmd to be interpreted as an object (file or URL) to be opened using the associated application defined in the Windows registry. For example, if CMD="http://www.microsabio.com", then selecting it would launch the browser and go to the specified web page. If CMD= "mydata.xls", selecting the menu would probably launch Excel to open the spreadsheet.

If the file object specified in CMD does not contain a drive or directory specifier, then it will be assumed to be in A-Shell’s "DOC" subdirectory (e.g. C:\VM\MIAME\DOC). Otherwise, you need to specify a native pathspec (unless the file is in the system search PATH). Refer to MX_FSPEC for converting AMOS directories to their native equivalents.

MBF_MENUID

&h00040000

Internal menu command identifier. This is the type of the internal or built-in menus. When clicked, then just send a message with their ID to the A-Shell message handler. See Adding/Deleting Internal Menu Items for further details.

Hex-Decimal Values


Cmd

cmd (String, in) should be set to the command, DLL, keystrokes, object, or internal ID, according to the mtype. It is ignored for the submenu (MBF_SUBMNU) and separator (MNU_SEP) menu item types.

Care should be taken so that your custom menu commands remain contextually compatible with the application. For example, creating a menu item labeled "Help" with cmd = "?" + chr(13) might make sense in the context of a screen or menu which understands that keyboard sequence, but may make no sense in a text editing context where those would simply be ordinary characters. Any of the following strategies might be employed to avoid the problem:

• Use menu types MBF_SHLEXC and MBF_CMDLIN, since they launch external windows without affecting the current application context.

• Disable or delete the menu items when switching to an application context where they no longer apply. This is usually a error prone and tedious to program and thus not highly recommended.

• For MBF_KBD menus, use universal control characters (that may be applicable everywhere, such as VK_ESC), or pseudo-function keys which are either context-independent or can be ignored by applications that don't recognize them. In either case, use Virtual Key Symbolic Names whenever possible, to avoid complications with the handling of literal control characters. (You can also encode them using the ^X notation, (where ^X is interpreted as Ctrl+X, for any character A-Z or [, ], \, underline, or another caret). Thus the cmd string "^GA" would be treated as Ctrl+G followed by the letter A, and "Hello^M" would be treated as the word "Hello" followed by a CarriageReturn (Ctrl+M).

Examples

mtype = MBF_KBD : cmd = "VK_xF213" ! virtual function key 213

mtype = MBF_KBD : cmd = "^C" ! Control C (using "^" notation)

mtype = MBF_CMDLIN : cmd = "CALC.EXE" ! launch calculator

mtype = MBF_SHLEXC : cmd = "www.me.com" ! launch browser


Func

func (String, in) must contain the name of the function to execute within the DLL whose name was specified in cmd. It will be ignored except when the mtype is MBF_DLL.


Mstatus

mstatus(signed numeric, out, optional) returns a code indicating the result of the operation:

Value | Meaning
0 | OK, or for opcode 2 indicates item was previously enabled
1 | OK, or for opcode 2 indicates item was previously disabled
-1 | Add or delete menu function failed
-2 | Menu (mnutxt) not found during change or delete operation
-3 | Out of memory (unable to allocate menu storage buffers)
-4 | Exceeded maximum number of added menu items (currently 125)
-5 | No menu buffer allocated
-6 | Illegal opcode
-7 | Menu (mnutxt) already exists
-8 | Menuid not found
-15 | ATE failed to respond to the server request within the normal time limit

If the mstatus parameter is omitted, or passed as a null string (if mapped, must be S,1), then no status will be returned. This will provide a speed improvement when setting up a lot of menu items (particularly over ATE), and is recommended especially if you aren't even bothering to check the returned status value anyway.

The normal time limit for a response from ATE is five seconds for most commands, ten to fifteen seconds for a few. Sometimes commands that "should" respond almost instantly will take a long time, either because ATE is "locked up", or there is some other Windows hang-up, such as waiting on "elevation" or some other critical event. In such cases, we return -15 to indicate time out.


Dlgid

dlgid (numeric, in, optional) adds a menu to the dialog. Note that:

• For dialogs using MBF_ALTPOS, the dialog height will be increased by the height of the menu (so as to leave the amount of usable space within the dialog unchanged. Otherwise (in the non MBF_ALTPOS case), the dialog height will remain fixed, but the addition of the menu will take away from the usable space within the dialog. In either case, any controls currently within the dialog will be shifted down by the height of the menu.

• It is not possible to delete the menu, once added. (In general, you would probably just delete the dialog.)

• The dialog display does not get automatically refreshed to show the newly added menu. To force this to happen after you have added all of your menu items, use AUI_MENU with opcode MNUOP_DSP:

xcall AUI, AUI_MENU, MNUOP_DSP, 0, "", 0, 0, "", "", mstatus, dlgid


Itemid

Updated May 2013

itemid (numeric, in, optional) allows you to specify a unique ID (in the range of 1000-32767) to assign to the item being added, or to identify the item being modified or referenced. Items can also be identified by their ordinal position or text, but these are less satisfactory because either may change at runtime due to forces outside the developer’s awareness at the time of writing the code. The use of itemid is also the only way to create nested submenus (i.e. assign an itemid to the parent of the submenu, then reference it as the Menuid of the child items).

History

2013 May, A-Shell 6.1.1351: ItemId no longer needs to be globally unique; it only needs to be unique relative to the DlgId—i.e., to the window to which the menu is attached. This makes it easier to generate menu item IDs when working with multiple dialogs, without having to worry about collisions.


AUI_Menu Simplified Method

The simplified menu calling syntax uses just five parameters, as shown here:

xcall AUI, AUI_MENU, opcode, mdfspec, state, status {,dlgid}

opcode, state, status, dlgid have the same meaning and usage as for the traditional method, described above.

mdfspec (String) should contain the filespec (AMOS or native format) of a "Menu Definition File" which consists of lines of the following format:

;(Blank lines and lines starting with semicolon are ignored)

;

MENUID,MNUTXT,TYPE,CMD

MENUID,MNUTXT,TYPE,CMD

etc.

By convention, the normal extension for such a file is MDF (Menu Definition File). If the mdfspec parameter is "", then it is assumed to refer to A-Shell's help menu definition file, $MIAME\doc\ashelp.mdf.

If running on a UNIX server with an ATE client, the mdfspec will be resolved on the PC side and must reside there in advance of the call. (You can transfer it via FTP necessary.) If just a filename and optional extension given, it will be treated as being in the local ATE current ppn, which by default is DSK0:[1,4].

The file can specify any number of menu items (subject to the maximum of 125 custom menu items at any one time), all of which will be added, deleted, or enabled/disabled in one operation.

Each of fields menuid, mnutxt, type and cmd have the same meaning as in the traditional calling format. As an added convenience, the TYPE field may also be specified as a three-character mnemonic:

Type | Mnemonic
0 | CMD
1 | <not supported in MDF format>
16 | SUB
2048 | SEP
65536 | KBD
131072 | REG

menuid can also be specified as a mnemonic, as shown in the following table. Note that this is the same table with the same values as shown and as used in the "Traditional Method." In the "Simplified Method," however, the mnemonics are allowed, whereas in the "Traditional Method" they are not.

MenuID | Meaning
0 or "Top" | Top level menu as a whole. Use this when adding or deleting an item that appears on the horizontal menu bar (which starts with items "File", "Edit", "Settings", "Help".
1 or "File" | The "File" menu. Use this to add or delete items to the drop down menu that appears when you click on "File".
2 or "Edit" | The "Edit" menu. Use this to add or delete items to the drop down menu that appears when you click on "Edit".
3 or "Settings" | The "Settings" menu. Use this to add or delete items to the drop down menu that appears when you click on "Settings".
4 or "Help" | The "Help" menu. Use this to add or delete items to the drop down menu that appears when you click on "Help".
5 or <name> | This would be the number of the first item added to the top level menu bar. You could also refer to it by the same text that you specified as mnutxt when you added it. Use this to add or delete items to the drop down menu that appears when you click on this menu.
6 – 14 or <name> | Same idea as for five, but for the sixth through fourteenth items on the top menu bar.

Any of the fields in the MDF may optionally be enclosed in quotes – this in only mandatory when the field itself contains a comma.

See the notes in the TYPE table and under the CMD definition for the traditional method above for details about how to format the CMD string for the various TYPEs.

As an example, consider the following call and sample MDF file. The comments in the sample.mdf should hopefully make clear what it does.

xcall MIAMEX, MX_WINMMU, 1, "sample.mdf", 0, STATUS

The Simplified Method does not support the more advanced capabilities added in 1154 (checked and radio button menus, nested submenus, menu icons.)

Subtopics

Sample.mdf


Sample.mdf

;Add a separator bar to File menu:

FILE,"fs1",SEP

;Add item to "Select Source" (implemented my launching another

; instance of A-Shell)

; (Note -e for auto exit)

FILE,"Select Source...",CMD,"$ASHELL -e run selsrc"

;Next, add a new top level menu called "Tools"

TOP,"&Tools",SUB

;Add a calculator and a website link to it...

"&Tools","Calculator",CMD,"calc.exe"

"&Tools","Web Search",REG,"http://www.google.com"

;Add a separator and two PDF document files to Help menu

HELP,"fs2",SEP

HELP,"User Guide",REG,"UserGuide.pdf"

HELP, "Troubleshooting Reference",REG,"TroubleRef.pdf"

If an error occurs, the operation will abort at that point, which should hopefully help you pinpoint the cause.

It is usually necessary to delete menus in the reverse order from the way they were added (in order to avoid the confusion caused by later menus changing position due to the deletion of earlier ones). The simplified method takes care of this difficulty for you, but only within a single MDF file. If you use multiple MDF files and want to be able to delete them independently of each other, you should not have more than one MDF file add menu items to the same top level submenu, and you will need to refer to the top level submenus by name rather than number.

Refer to the sample program ASMENU.BAS which is included in the A-Shell release (in [7,376]), and to the Application Developers Guide for more details.


Submenus

To create a submenu, use the MBF_SUBMNU flag and specify a menuid other than 0. (Submenus whose parent menuid is 0 are top-level drop-down menus.) To create the items within the submenu, set the menuid to match the itemid of the submenu itself.


Context Menus

AUI_MENU supports the creation of popup menus (aka "right-click" or "context" menus) for the main window and for dialogs. The syntax is the same the same as for the Traditional Method above, with the following differences:

• There can be only one context menu for the main window and one for each dialog. When the menu is created, if there is a dialog active, then it becomes associated with the dialog; otherwise it becomes associated with the main window. As of A-Shell build 5.1.1151.0, the dlgid parameter may be specified to override the menu/dialog association rule just stated.

• The menu ID of the context menu must be negative, although beyond that, the value is arbitrary and only serves to identify the menu. One way of assigning a unique value for each dialog would be to take the dialog's numeric ctlid, add 1, and negate it. (The offset of 1 would preserve the menu ID -1 for a menu attached to the main window, whose ctlid is effectively 0).

• To add the clipboard operations Copy and Paste to the popup menu, use the MBF_CMDLIN format with the special commands "$COPY" and "$PASTE". $CUT doesn't really apply in this context.

• Defining a context menu does not automatically change the cursor to an arrow, but you can do that with the AG_SETCURSOR;chr(32);chr(127); command and AG_SETCURSOR;chr(48);chr(127); to set it back to an I-beam.

• You can delete the context menu with a single AUI_MENU call with opcode=MNUOP_DEL, mnutxt="*", and menuid set to the same value used when creating the menu.

• The context menu will be active when the cursor is over the window or dialog, but not over a control which has its own click processing.

• To display the menu under program control (rather than waiting for the user to right-click), use AUI_MENU with opcode=MNUOP_POP, e.g.

xcall AUI, AUI_MENU, MNUOP_POP, MENUID, "", ROW, COL, "", "", STATUS

The ROW and COL parameters mark the position of the upper left corner of the popup menu (relative to the current dialog, if applicable, or else to the main window), in (milli) row and column units and replace what would otherwise be the mstate and mtype parameters.

See Also

AUI_MENU can only add context menus to dialogs or the main window. To add context menus to other control types, see:

• Static controls

• XTREE

• INFLD


Menu Icons

Beginning with A-Shell 5.1.1154, you can specify a bitmap or icon to display next to the menu item, by prepending "|imgspec{=size}|" to the text.

imgspec may be the filespec (native or AMOS-style) of a BMP or ICO file, or it may be in the "name::library" format used by standard controls which may contain icons. (name is the name of the icon, and library is the name of a DLL containing the icons, such as the ashico1.dll distributed with A-Shell.) The optional {=size} clause may be specified to request a specific size in pixels (menu images display as squares, so only one dimension is required).

Under Vista and above, menu images can be in any reasonable size (say, 10x10 to 99x99), and the menu spacing will adjust accordingly, and the size clause works for both bitmaps (BMP) and icons. The standard icon size is 16x16. Best results will be obtained when the natural size of the BMP file, or when one of the images contained within the ICO match the default or specified size.

Prior to Vista, the standard menu bitmap size was 13x13 and the resizing feature is not operable (and is essentially ignored). Icons will be automatically scaled to fit the standard space, while BMP files will be clipped. (This BMP files are not recommended unless you have a specific set of them for XP and prior that is naturally 13x13 or close to it.)

Example:

The following code excerpt (from the EXLIB sample program ASMNU4[908,35]) adds a new top level menu "Custom" and then adds eight items to that menu, each with a different bitmap, illustrating most of the syntax and image type possibilities (BMP file, ICO file, icon resource in library module, with and without scaling):

++include ashinc:ashell.def

map1 id'cusmnu,b,2,2000

map1 mstatus,f

xcall AUI, AUI_MENU, MNUOP_ADD, 0, "&Custom" , MBST_ENABLE, &

MBF_SUBMNU,"","",mstatus,0,id'cusmnu

xcall AUI, AUI_MENU, MNUOP_ADD, id'cusmnu, "|Back16.bmp|Back (16x16 bmp)", &

MBST_ENABLE, MBF_KBD,"VK_xF501",""

xcall AUI, AUI_MENU, MNUOP_ADD, id'cusmnu, "|Back24.bmp|Back (24x24 bmp)", &

MBST_ENABLE, MBF_KBD,"VK_xF502",""

xcall AUI, AUI_MENU, MNUOP_ADD, id'cusmnu, "|Clock24.bmp=16|Clock (24x24 as 16x16 bmp)", &

MBST_ENABLE, MBF_KBD,"VK_xF503",""

xcall AUI, AUI_MENU, MNUOP_ADD, id'cusmnu, "|add2.ico|Add+ (ico file, default size)", &

MBST_ENABLE, MBF_KBD,"VK_xF504",""

xcall AUI, AUI_MENU, MNUOP_ADD, id'cusmnu, "|coffee.bmp=64|Coffee (189x189 as 64x64 bmp)", &

MBST_ENABLE, MBF_KBD,"VK_xF505",""

xcall AUI, AUI_MENU, MNUOP_ADD, id'cusmnu, "|back12.bmp|Back (12x12 bmp)", &

MBST_ENABLE, MBF_KBD,"VK_xF506",""

xcall AUI, AUI_MENU, MNUOP_ADD, id'cusmnu, &

"|Arrow_left_green::ashico1v|Arrow_left_green (ashico1v, dft size)", MBST_ENABLE, &

MBF_KBD,"VK_xF507",""

xcall AUI, AUI_MENU, MNUOP_ADD, id'cusmnu, &

"|Arrow_left_green::ashico1=32|Arrow_left_green (ashico1 =32)", MBST_ENABLE, &

MBF_KBD,"VK_xF508",""

Note that in the above examples, we did not specify the optional Mstatus parameter since we weren’t checking the result code anyway, and eliminating any delays waiting for response codes from remote ATE client workstations.

Under Vista and beyond, the result looks something like the picture below. Note that the menu spacing adjusts to the size of the image, and furthermore that all the images can be displayed in a size other than the underlying native size.

Under XP and prior versions of Windows (see image below), the visual capabilities are more limited, with no image scaling, and with BMP images being truncated to 13x13. In that environment, either you need to have a set of custom bitmap images sized no larger than 13x13, or you should stick with icons, using either ICO files or taking them from an icon library (like ashico1).

See Also

Icons in XTREE Popup Menu

Icons in AUI_Control context menus


Checked and Radio Button Menu Items

As of 5.1.1154, you create checked and radio button menu items, using the Mtype flags MBF_CHKMNU and MBF_RADIOMNU, as shown in this example from the EXLIB sample program ASMNU2[908,35]:

To initialize the state of a checked or radio button menu item to checked (or selected), add the MBST_CHECKED flag to the Mstate parameter, as shown in the example below:

xcall AUI, AUI_MENU, MNUOP_ADD, id'optmnu, "Option 1", MBST_ENABLE+MBST_CHECKED, &

MBF_CHKMNU,"","",mstatus, dlgid, id’option1 ! checked item

xcall AUI, AUI_MENU, MNUOP_ADD, id’optmnu, "Option 2", MBST_ENABLE, &

MBF_CHKMNU,"","",mstatus, dlgid, id’option2 ! unchecked item

xcall AUI, AUI_MENU, MNUOP_ADD, id’optmnu, "Radio 1", MBST_ENABLE+MBST_CHECKED, &

MBF_RADIOMNU,"","",mstatus, dlgid, id’radio1 ! selected radio item

xcall AUI, AUI_MENU, MNUOP_ADD, id’optmnu, "Radio 2", MBST_ENABLE, &

MBF_RADIOMNU,"","",mstatus, dlgid, id’radio2 ! unselected radio item

In the above code sample, note that the Itemid is used to assign unique identifiers to each of the items, and to associate the items with the parent menu id’optmnu. Also note that since we didn’t specify anything in the Cmd parameter, the items do not do anything on their own when clicked, other than change their state. The application will have to query the items to determine their states as needed (see next). Alternatively, if we wanted to respond immediately with an action corresponding to the change in state of such a menu item, we could have had them generate exitcodes (as in the Menu Icons example above). They can also execute command lines or launch documents (using MBF_CMDLIN or MBF_SHLEXC) just like other normal menu items.

Querying item state: To query the current state of a checked or radio menu item, use MNUOP_CHK, identifying the item to query via the parent Menuid, Dlgid, and Itemid. The current state flags will be returned in the Mstatus parameter, as shown below:

xcall AUI, AUI_MENU, MNUOP_CHK, id’optmnu, "", 0, 0, "","", mstatus, dlgid, id’option1

If (mstatus and MBST_CHECKED) ? "Option 1 is checked"

xcall AUI, AUI_MENU, MNUOP_CHK, id’optmnu, "", 0, 0, "","", mstatus, dlgid, id’radio1

If (mstatus and MBST_CHECKED) ? "Radio 1 is selected"

Changing item state: The states of checked and radio menu items change automatically when clicked. You may also change the state under application control, using MNUOP_STA. For example, to select the "Radio 2" item in the menu shown above (which will automatically deselect the "Radio 1" item):

xcall AUI, AUI_MENU, MNUOP_STA, id’optmnu, "Radio 2", MBST_ENABLE+MBST_CHECKED, 0, "","", &

mstatus, dlgid, id’radio2


Deleting Menus

Added May 2011

When deleting a built-in menu, you can now set the menuid parameter to "" and put either the string representation of the internal menu id # in the mnutxt parameter, or the numeric value in the itemid parameter (in which case set mnutxt=""). The latter method apparently seems more natural to some users, whose efforts were previously failing.

AG_MENU supports simplified deletion of menu items using either of the following formats:

TAB(-10,AG_MENU);"3,,";str(IDM_PRINTS);chr(127);

TAB(-10,AG_MENU);"3,";MENUID$;",";MNUTXT$;chr(127);

The first example works for internal (built-in) menu items, where you must specify the str() of the IDM_xxx value for the menu (from ashell.def).

The second example works for custom menu items, where you specify the text of the parent menu and the text of the item to delete.

These formats are mainly useful with AGCMD.LIT, since they don't apply to AUI_MENU. They are faster than any other method for deleting individual items one at a time, since there is no return status.


Adding/Deleting Internal Menu Items

Added May 2012

In addition to menu items that send keyboard sequences (MBF_KBD), execute commands (MBF_CMDLIN) or launch object handlers (MBF_SHLEXC), typically via Virtual Key Symbolic Names, A-Shell and ATE come with a set of built-in or internal menus (e.g. File > Load Setting) that simply send their ID's to A-Shell, which has its own internal logic to deal with them. It would be pointless to add new menu items of this type, since A-Shell wouldn't recognize them. But, you can use the internal ID as a convenient and robust way to reference the built-in menus for purposes such as deleting, disabling, and/or later re-adding them.

The internal menu IDs are defined via IDM_xxx symbols in the ashell.def file, for which see the following section Internal Menu Identifiers.

Example 1: Deleting an internal menu

The most straightforward way to delete a built-in (but not top level) menu by its internal ID is by setting both the Menuid and Mnutxt parameters to "", the Mtype parameter to MBF_MENUID, and putting the internal menu ID in the Itemid parameter. (The Mstate, Cmd and Func parameters are irrelevant when deleting, and the the dlgid parameter isn't relevant for built-in menus.) For example, to delete the Edit > Copy menu:

menuid$ = ""

mnutxt$ = ""

mtype = MBF_MENUID

xcall AUI, AUI_MENU, MNUOP_DEL, menuid$, mnutxt$, mstate, mtype, cmd$, func$, mstatus, 0, IDM_COPY

Example 2: Alternate syntax for deleting an internal menu

And alternate syntax sets the Menuid parameter to "*", the Mnutxt parameter to the string representation of the internal ID, and the Mtype parameter to MBF_MENUID. For example, to delete the File > Save menu:

menuid$ = "*"

mnutxt$ = str(IDM_SAVE)

mtype = MBF_MENUID

xcall AUI, AUI_MENU, MNUOP_DEL, menuid$, mnutxt$, mstate, mtype, cmd$, func$, mstatus

This example deletes File > Exit, and adds a "New Exit" option to the Settings menu which performs the same function as the original File > Exit:

mnu'exit'id$ = str(IDM_EXIT) ! internal ID of File > Exit

xcall AUI, AUI_MENU, MNUOP_DEL, 1, mnu'exit'id$, 0, 0, "", "", mstatus

xcall AUI, AUI_MENU, MNUOP_ADD, 3, "New Exit", MBST_ENABLE, MBF_MENUID, mnu'exit'id$, "", mstatus

Note that the Menuid parameters 1 and 3 reference the top level File and Settings menu by position.

Example 3: Moving / renaming a built-in menu item

This example deletes File > Exit, and adds a "New Exit" option to the Settings menu which performs the same function as the original File > Exit:

mnu'exit'id$ = str(IDM_EXIT) ! internal ID of File > Exit

xcall AUI, AUI_MENU, MNUOP_DEL, 1, mnu'exit'id$, 0, 0, "", "", mstatus

xcall AUI, AUI_MENU, MNUOP_ADD, 3, "New Exit", MBST_ENABLE, MBF_MENUID, mnu'exit'id$, "", mstatus

Note that the Menuid parameters 1 and 3 reference the top level File and Settings menu by position.

Example 4: Deleting a Top Level Menu Item

Top level menu items (e.g. File, Edit, Settings, Help), unfortunately have no internal IDs, so they can only be deleted by position (first position = 0). The rest of the parameters have no particular significance here. For example, to delete the Settings menu (position 2):

menuid$ = "" ! must be "" or 0 to indicate top level

mnutxt$ = "2" ! position of Settings menu (2 = 3rd item)

xcall AUI, AUI_MENU, MNUOP_DEL, menuid$, mnutxt$, 0, 0, "", "", mstatus

Note that after deleting any menu item, the items following it are shifted up in position. So in this case, if we executed the above program sequence again, we would delete whatever menu was originally following the Settings menu (i.e. Help). Also note that deleting any menu item automatically deletes any and all sub-items beneath it. So the above sequence would delete (and clean up) all of the sub, sub-sub, etc. items beneath the Settings menu.

Subtopics

Internal Menu Identifiers


Internal Menu Identifiers

Symbol | Value | Description
IDM_ABOUT | 101 | Help..About
IDM_LOAD | 107 | File..Load Settings
IDM_SAVE | 108 | File..Save Settings
IDM_SAVEAS | 109 | File..Save Settings As
IDM_DEFAULTS | 112 | File..Default Settings
IDM_EXIT | 111 | File..Exit [216]
IDM_PRINTS | 110 | File..Print Screen [216][226]
IDM_AUTOMOUSE | 124 | Edit..AutoMouse [211]
IDM_COPY | 115 | Edit..Copy [211]
IDM_PASTE | 116 | Edit..Paste
IDM_SCHEDULE | 106 | Settings..Scheduling
IDM_BEVELING | 122 | Settings..Beveling
IDM_COLORS | 113 | Settings..Colors
IDM_FONTSYS | 123 | Settings..Font..System
IDM_FONTGUI | 132 | Settings..Font..GUI
IDM_FONTGRID | 144 | Settings..Font..Grid [211]
IDM_MISC | 130 | Settings..Misc Settings
IDM_DLGSIZING | 134 | Settings..Dialog Sizing
IDM_PVPREF | 142 | Settings..Preview Preferences [211]
IDM_KBDLOCK | 117 | Settings..Keyboard Lock


AUI_IMAGE

Updated May 2016; see History

xcall AUI, AUI_IMAGE, opcode, handle, status {,parameters...}

(Windows only) AUI_IMAGE allows you manage and manipulate images: scan, capture from screen, read from disk, display, convert, etc. Formats supported are BMP, PCX, JPG, TIF and PNG. The imaging operations require the use of external graphics library modules VIC32.DLL and VICTW32.DLL, which are included with the A-Shell installation package and reside in the \bin folder.

Parameters

Unlike most subroutines, the parameters for AUI_IMAGE vary with the opcode. Here are the parameters that apply to all opcodes:

opcode (Num) [in]

Symbol | Value | Function
IMGOP_LOAD | 1 | Load image file from disk
IMGOP_CLOSE | 2 | Close image
IMGOP_DISPLAY | 3 | Display image
IMGOP_LOADDISP | 4 | Open and Display image
IMGOP_INFO | 5 | Retrieve Information about an image
IMGOP_HIDE | 6 | Remove from Display
IMGOP_ACQUIRE | 7 | Scan and save image (TWAIN Acquire)
IMGOP_SELECTSRC | 8 | Select Data Source
IMGOP_TWERR | 9 | Get TWAIN Error code
IMGOP_CAPTURE | 10 | Capture Screen
IMGOP_SAVEAS | 11 | Convert image
IMGOP_PAGEINFO | 12 | Count Pages in multi-page TIF file

handle (Num) [in/out]

The Load operation returns this value to identify the image in subsequent calls. It must be passed to the other operations.

status (F,6) [out]

is returned from every call, with 0 indicating success. It should be mapped as a floating point, since it can be negative or positive. Possible values of status are given in the following Status Codes table.

All of the other parameters are documented with they opcodes where they are used. Click on the links in the table above for specific opcodes and functions.

History

2016 May A-Shell 6.3.1512: Source code reorganization: symbols related to AUI_IMAGE have now been separated out of ashell.def into image.def and augmented. Programs using them should now ++include ashinc:ashell.def and ++include:image.def.

AUI_IMAGE scanning enhancement: the IMGSF_HIDEUI (1) option in the scanflags parameter now works in single-page scanning mode. Previously single page scans (pages=1) always displayed the scanner's user interface regardless of the scanflags.

Subtopics

Load

Close

Display

Open and Display

Retrieve Information

Remove from Display

Acquire

Select Data Source

Get TWAIN Error

Capture Screen

Convert

Count Pages

Status Codes


Load

Updated September 2013

xcall AUI, AUI_IMAGE, IMGOP_LOAD, handle, status, filename {,pageno}

filename is the name of the image file (in either AMOS or native Windows format). Its extension should correspond to the image type.

handle will be set to an integer value which identifies this image in memory and which must be passed to other calls to indicate which image the call refers to.

Opening the image does not display it. It merely loads it into memory. Although good programming practice would suggest that you close up any open images at the end of your program, as with open files, A-Shell will automatically close them for you at the end of a program.

We have the technology to figure out the image type by looking at the image file itself, but did not see much point in exercising it due to the overhead and the questionable benefit of having images with non-standard extensions. If you see this differently, please contact us to discuss the need.

AUI_IMAGE supports loading up to 31 images at a time. Beyond that, you will need to close some before loading more. Note however that AUI_CONTROL also supports loading images into either buttons or static controls (see Image Control), and it has no limitation on the number of images that can be loaded at one time.

History

2013 September, A-Shell 6.1.1362: Added pageno to specify the page number of a multi-page TIF to display. The first page is considered 1. 0 is also treated as 1. Note that in order for this feature to be used with ATE, both server and client must be on A-Shell 6.1.1362.0 or later. Also note that since each page could potentially have a different configuration, in order to retrieve information on the page (with IMGOP_INFO), first load the page using IMGOP_LOAD.


Close

xcall AUI, AUI_IMAGE, IMGOP_CLOSE, handle, status

IMGOP_CLOSE removes the image from the screen and frees up the memory associated with it.


Display

xcall AUI, AUI_IMAGE, IMGOP_DISPLAY, handle, status, strow, stcol, erow, ecol, flags

IMGOP_DISPLAY displays the image (identified by handle) in the position specified by the starting row/column and ending row/column parameters. The image will be automatically scaled to fit in the allotted space, although by default the aspect ratio is preserved. So, for example, if the actual image is square, and you specify coordinates that mark out an elongated rectangle, not all of the space will be used for the image.

flags allows you to specify certain display options, such as whether to stretch the image to fit exactly in the space provided or to preserve its aspect ratio. See Open and Display for flags definitions.

The first two values apply only to printing. If IMGF_STRETCH is specified, the aspect ratio is not preserved and the image is stretched as needed to completely fill the specified display rectangle. IMGF_SCALEQ forces us to use linear bitwise interpolation (as opposed to simple bit replication) during scaling, which theoretically will achieve a higher quality, less "blocky" image when enlarging beyond the original image size.

The image display will overwrite any screen text that it overlaps, and is not affected by other screen operations such as clearing the screen or saving/restoring the screen. The only way to remove it from the screen is with opcode 2 or opcode 6.

Images in Dialogs

If a modal dialog is active when the image is displayed, it will be displayed within, and relative to the dialog. If the coordinates given exceed the size of the dialog, the image will be trimmed to the borders of the dialog. This is one good way to display the kinds of horizontal and vertical banner images which are often used in "wizard" dialogs.


Open and Display

Updated September 2013

xcall AUI, AUI_IMAGE, IMGOP_LOADDISP, handle, status, srow, scol, erow, ecol, flags, filename {,pageno}

IMGOP_LOADDISP combines opcodes 1 (Load) and 3 (Display) to save you a step. Note that like opcode 1, it leaves the image in memory, so you can later redisplay it using just opcode 3. caution: table is duplicated in ashev GDI Printing //image; update there if you update here.

Symbol | Value | Description
IMGF_HALFTONE | &h001 | Use halftone print method.
IMGF_SCATTER | &h002 | Use scatter print method.
IMGF_STRETCH | &h004 | Stretch image to fit bounding rectangle. Otherwise retain aspect ratio, meaning the image will likely be smaller than the rectangle in one of the two dimensions.
IMGF_SCALEQ | &h008 | Interpolate—i.e., use hq scaling.
IMGF_FORCEXFER | &h010 | (ATE) Force image filespec to be treated as relative to the host and transfer it to the client. Applies to IMGOP_LOAD and IMGOP_LOADDISP. See Transfer of Server-Side Images.

History

2013 September, A-Shell 6.1.1362: Added pageno to specify the page number of a multi-page TIF to display. The first page is considered 1. 0 is also treated as 1. Note that in order for this feature to be used with ATE, both server and client must be on A-Shell 6.1.1362.0 or later.

Subtopics

Transfer of Server-Side Images


Transfer of Server-Side Images

Added August 2011

One advantage of AUI_IMAGE over the otherwise nearly-identical IMAGE.SBR is that it has the ability to transfer the specified image from the host/server to the client, a necessary pre-requisite for displaying it on the client. Prior to A-Shell 5.1.1222, this only worked under UNIX hosts, and was triggered whenever the image filespec contained a forward slash (indicating a UNIX rather than Windows filespec), or the IMGF_FORCEXFER flag was specified. As of 5.1.1222, the transfer logic is also supported under Windows servers, using an ATE proprietary protocol to get around the usual lack of FTP support on Windows servers.

In addition, the server checks to see if the image is already cached on the client either in the specified directory or one of the client's cache directories or the %MIAME%\icons directory, eliminating redundant transfers and the corresponding need for a manual pre-transfer of all the images likely to be needed.


Retrieve Information

xcall AUI, AUI_IMAGE, IMGOP_INFO, handle, status, imginfo {,filespec}

MAP1 IMGINFO ! Image info packet

MAP2 IMG'OWIDTH,F ! Original image width (pixels)

MAP2 IMG'OLENGTH,F ! Original image length (pixels)

MAP2 IMG'DWIDTH,F ! Display width (pixels)

MAP2 IMG'DLENGTH,F ! Display length (pixels)

MAP2 IMG'BPP,F ! Bits per pixel

MAP2 IMG'NA,F ! not used

MAP2 IMG'TYPE,B,2 ! type: 1=tif,2=bmp,3=jpg,4=pcx,5=tga,6=gif,7=png

MAP2 IMG'BW'BLKPCT,F ! % black pixels (B&W TIF only)

IMGOP_INFO retrieves some information about a previously opened image (by specifying the image handle), or from the disk file filespec. The information is reasonably self-explanatory. Note that the operation can also be used merely to verify if a particular handle value is valid.

We may be adding fields to this structure in the future to accommodate additional pieces of information that developers discover a need for. The routine will however always be smart enough to look at the size of the packet you pass so as to not overrun the packet if new fields are added but not yet mapped in existing programs.

History

2016 April, A-Shell 6.3.1512: The IMGOP_INFO (5) opcode now returns the percent black for B&W TIF images. The calculation eliminates some noise (individual floating bits) and also ignores an outer margin equal to 1/40th of the width and/or length, and may be useful as a way of detecting blank (or perhaps too-light or too-dark) pages during scanning.

2006 April, A-Shell 4.9.955: Add support for the filespec parameter.


Remove from Display

xcall AUI, AUI_IMAGE, IMGOP_HIDE, handle, status

IMGOP_HIDE is similar to Close except that it leaves the image (still identified by handle) in memory so that it can be displayed again later without having to open it. This might be deemed more efficient in some applications than fully closing and reopening the image when switching between various screen displays.


Acquire

Updated May 2016; see History

xcall AUI, AUI_IMAGE, IMGOP_ACQUIRE, handle, status, filespec, attribs {,appname, pages, scanflags, pagesize}

IMGOP_ACQUIRE invokes a TWAIN "Acquire" to retrieve an image from the default TWAIN input device (aka "Data Source"). In the most common case, which involves scanners, this is equivalent to "scan-and-save-image". Manufacturers of image input devices such as scanners typically provide a TWAIN driver and user interface which allows the user to access the functionality of the device. This way, the application does not need to know any details about the device (such as what kinds of controls and options it has). It just knows that once the Acquire operation is started, it will return with a file (if successful) or an error code (if not).

IMGOP_ACQUIRE provides support for scanning multiple pages; see the following topic, Multi-Page Scanning, for more information.

Parameters

handle (Num) [in]

is not used here, is included only for conformity with the other opcodes.

status (Num) [out]

returns 0 for success, else an error; see Status Codes.

filespec

is the specification of the file (AMOS or native format) to store the image in. The extension you specify will determine the image format and must be one of the file types listed in the comp following table (e.g. TEST.JPG or DSK9:TEST.BMP[100,20]).

attribs [in]

defines various attributes for the scan, mapped as shown below. See History note for A-Shell 6.3.1510.

map1 attribs,b,4 ! compress, pixel type, resolution attributes

map1 attribsx,@attribs ! overlay to break out fields

map2 comp,b,1 ! compression options (as before)

map2 pixtype,b,1 ! pixel type: (see below)

map2 resx,b,1 ! x resolution (in multiples of 25 DPI)

map2 resy,b,1 ! y resolution (in multiples of 25 DIP)

comp [in]

is a compression-related factor determined by the image type:

Type | Explanation
JPG | Values range from 1 to 100, with 100 being maximum size and quality—i.e., minimum compression. 75 is the default and is generally considered the point below which you start to perceive the loss of quality.
TIF | Symbol | Value | Meaning
 | TIFCF_NONE | 0 | No compression
 | TIFCF_PACKBITS | 2 | Pack Bits
 | TIFCF_GROUP3 | 3 | Group 3
 | TIFCF_GROUP4 | 4 | Group 4
 | TIFCF_CCITT3 | 5 | CCITT Group 3
BMP,PCX | Ignored, not used
PNG | Symbol | Value |  | Meaning
 | PNGF_ALL | 0 |  | Use best filter for each row (best compression)
 | PNGF_NONE | 2 |  | No filter (fastest)
 | PNGF_SUB | 4 |  | Difference filter with adjacent pixel
 | PNGF_UP | 6 |  | Difference filter with previous row
 | PNGF_AVG | 8 |  | Average filter
 | PNGF_PAETH | 10 |  | Paeth filter
 | To save as an interlaced file, add PNGF_INTERLACE (+1) to any of the above.

pixtype [in]

The pixtype options are shown in the following table. The first three of these are standard for most scanners, the others are somewhat exotic and may not be supported.

Value | Definition
1 | Black and white (bi-level)
2 | Grayscale (8 bit)
3 | RGG (24 bit)
4 | Palette
5 | CMY
6 | CMYK
7 | YUV
8 | YUVK
9 | CIEXYZ

resx, resy [in]

these fields are scaled to multiples of 25 DPI (i.e. 12=300 DPI), in order to fit a reasonable range of possible resolutions in 8 bits.

For each of the pixtype, resx, and resy fields, 0 is interpreted as no change to the existing or default settings. So existing programs that pass only the old comp value will continue to work as before.

Note that for many scanners, setting the pixel type and resolution options may not have an effect unless the IMGSF_HIDEUI flag is set in the scanflags parameter. That is, displaying the scanner's user interface may override the application settings with the scanner's own previously saved settings.

appname (String) [in]

is an optional string containing the name of your application, which, depending on the particular TWAIN driver, may be displayed in the title bar of the device’s user interface window.

pages (Num) [in/out]

specifies the desired (or maximum) number of pages to scan. On return, it will contain the actual number scanned.

scanflags (Num) [in]

specifies flags (defined in ashell.def) affecting the scanning operation:

Symbol | Value | Meaning
IMGSF_HIDEUI | &h0001 | Hide the scanner's user interface dialog, forcing the user to scan based on the settings previously established.
IMGSF_ADFOUT | &h0002 | Quit when the Automatic Document Feeder (ADF) is out of paper (even if less than the number of pages requested)
IMGSF_CONTINUE | &h0004 | Keep scanning until the requested # of pages is received, or the operator terminates the operation, or an unrecoverable error. This may be the same as the default operation, although in cases where there is no ADF, it may be necessary in order to force the operation to continue for multiple pages, since otherwise the scanner may return an ambiguous status, making it unclear to the application whether the operator decided not to continue, or the scanner just didn't now how to do multiple scans in one call.

pagesize (Num) [in]

sets pagesize. Options are defined in the ashinc:ashell.def file, the most common options being: TWSS_A4LETTER = 1, TWSS_USLETTER = 3, TWSS_USLEGAL = 4

Comments

Note that the acquisition (scanning) of the image data is independent of the saving of the image file, so it is up to you to specify an image format (via the file extension) that is compatible with the type of scan. (Or conversely, for the scanning operator to select options compatible with the file format.) For example, PCX only supports 1 and 8 bit data, so a 24-bit scan will result in an error while attempting to save the file.

See the IMAGE.BP[908,32] program in the EXLIB for an example of using the pages and scanflags parameters.

History

2016 April, A-Shell 6.3.1512: Add ability to set the page size via the pagesize parameter.

2016 April, A-Shell 6.3.1510: Old comp parameter redefined as attribs. Note that existing/older programs which simply use the comp parameter remain upward compatible with the attribs interpretation; the layout above guarantees that the comp value is interpreted the same either way, and the other fields would just be considered zero, meaning use the current defaults.

2016 April, A-Shell 6.3.1510: the IMGSF_HIDEUI (1) option in the scanflags parameter now works in single-page scanning mode. Previously single page scans (pages=1) always displayed the scanner's user interface regardless of the scanflags.

2012 June, A-Shell 6.2.1306: Add support for multi-page scanning via the pages and scanflags parameters.

Subtopics

Multi-Page Scanning


Multi-Page Scanning

The individual pages of the scan will be saved using the filespec, but with the page # appended. So if you set filespec = "scan.tif", the resulting files would be "scan-1.tif", "scan-2.tif", etc. If you need more flexibility in the file naming, I could also allow you to embed a code within the filename to receive the page number, so that you could end up with files names "scan001inv.tif", "scan002inv.tif", etc.

Typical multi-page scanning scenarios:

• Documents with fixed number of pages (say, 5). Set PAGES=5, and IMGSF_CONTINUE flag. Depending on the nature of the scanner and whether the IMGSF_HIDEUI flags is set, the user may see a dialog containing SCAN/CLOSE/CANCEL buttons. Or maybe the scanner just returns after each scan (in which case the XCALL will internally keep calling it until it gets the 5 pages or an explicit CANCEL or other error is returned). Assuming all goes well, XCALL returns STATUS=0 and PAGES=5 to the caller. If we run into an error on page 3 and can't continue, we would return PAGES=2 (2 pages scanned) and STATUS=<some error code>.

• Documents with variable number of pages. Set PAGES to a suitably high maximum value, perhaps 999999. If you are using the feeder to determine the end of the document (i.e. the operator will load exactly one document at a time), set IMGSF_ADFOUT. Else rely on the user to terminate the scan job after the desired number of pages. (Although there is some question whether it will always be possible to distinguish between a true "cancel", which should return STATUS=15, and "done" which ideally would return STATUS=0 to the application, but necessarily will have to return some other status to the internal interface to get it to stop scanning.) The application would presumably look at STATUS to make sure that the scan operation terminated normally, and then at PAGES to see how many pages were scanned.


Select Data Source

xcall AUI, AUI_IMAGE, IMGOP_SELECTSRC, handle, status {,sourcename}

IMGOP_SELECTSRC allows you to specify which of the available TWAIN data sources (input devices) is to be used for subsequent "Acquire" operations. If sourcename is specified and non-blank, it will attempt to select the corresponding data source from among the available options. Otherwise it will pop up a dialog box allowing the user to select from among the available data sources.

This operation (with no sourcename) should be exactly equivalent to the "Select Source" menu option that appears on the File menu of most programs that support TWAIN.


Get TWAIN Error

xcall AUI, AUI_IMAGE, IMGOP_TWERR, handle, status

IMGOP_TWERR only applies when the status returned from another opcode is 11 (TWAIN error). In that case, you can use opcode 9 to retrieve a more specific error code, among the following:

Value | Meaning
1 | Failure due to unknown causes
2 | Not enough memory to perform operation
3 | No data source
4 | Source already in use
5 | Source/Manager error already reported
6 | Unknown capability requested
7 | Undefined error
8 | Undefined error
9 | Bad protocol
10 | Parameter out of range
11 | Message received out of sequence
12 | Unknown destination source app
13 | Could not create parent window
14 | TWAIN Source Manager not found


Capture Screen

Added May 2011

xcall AUI, AUI_IMAGE, IMGOP_CAPTURE, handle, status, fspec, comp, winid

IMGOP_CAPTURE captures the screen or a window to a file. The concept is similar to that for IMGOP_ACQUIRE, except that the source of the image is the screen/monitor rather than a scanner.

The parameter sequence and interpretation is also nearly identical to IMGOP_CAPTURE. The main exception is the last parameter (which in IMGOP_CAPTURE specifies the title to put on the scan dialog). Here it identifies the screen option to capture:

Parameters

winid (String) [in]

indicates the image source:

Symbol | Value | Meaning
IMGCWF_CURWIN | -2 | current A-Shell window or modal dialog (if applicable)
IMGCWF_SCREEN | -1 | entire screen (primary monitor only)
IMGCWF_MAIN | 0 | main A-Shell window
 | 0### | arbitrary window or control handle ###
 | ### | id of the AUI control to capture
 | name | name of the AUI control to capture

Note that options -2 and 0 capture the target window/dialog and anything above it.

comp [in]

In addition to the values shown in Acquire, comp in this context (screen capture) supports these additional flags:

Flag | Value | Meaning
IMGCF_CLIENT | &h00080000 | Capture just the client area of the target window. Else include window border, title bar, menu, etc.
IMGCF_GRAY | &h00100000 | Convert captured image to grayscale
All of the following imply grayscale
IMGCF_BI_SCATTER | &h00200000 | Convert to bi-level using scatter method
IMGCF_BI_DITHER | &h00400000 | Convert to bi-level using dither method
IMGCF_BI_THRESH | &h00800000 | Convert to bi-level using threshold method
IMGCF_NEGATE | &h01000000 | Negative image (useful with black window bg)
IMGCF_INKSAVER | &h02000000 | Save ink by converting most common color to white*

*The "ink saver" option attempts to address the common complaint about graphic screen images using up too much printer ink or toner. It analyzes the image to identify the color responsible for the most ink, then converts that color to white (requiring no ink). Any pixels that were originally white are changed to a light-gray so as to not completely disappear into the background.

History

2011 May, A-Shell 5.1.1215: function added to A-Shell


Convert

Added May 2011

XCALL AUI, AUI_IMAGE,IMGOP_SAVEAS, handle, status, fspec, comp

For IMGOP_SAVEAS the arguments and operation are nearly identical to IMGOP_CAPTURE, except that the source of the operation is a previously loaded image specified by the handle parameter. The image is saved to the specified fspec, converting it (according to the extension of fspec) and the compression and other options in the comp parameter.

For example, you could use this opcode to load a 24 bit color BMP and save it as an 8 bit grayscale PNG with the "Ink Saver" transformation. In fact, the print screen utility (APRNTSCRN.SBX) now uses this technique to process changes in the image attributes, which is faster than taking a new screen picture.

History

2011 May, A-Shell 5.1.1215: Function added to A-Shell


Count Pages

Added September 2013

IMGOP_PAGEINFO returns the number of pages in a multi-page TIF file.

xcall AUI, AUI_IMAGE, IMGOP_PAGEINFO, handle, status, filename, pages

Parameters

handle

Ignored. It is here only for uniformity with other opcodes

status (F,6) [out]

returns status; 0 for success

filename (str) [in]

file to examine, as for opcode 1

pages (num) [out]

returns the number of pages in the file. 0 indicates that the number is unknown—or more likely, the file does not support multiple pages

Note that in order for this feature to be used with ATE, both server and client must be on A-Shell 6.1.1362.0 or later.

History

2013 September, A-Shell 6.1.1362: function added to A-Shell


Status Codes

The variable status is returned from each XCALL IMAGE operation (except for opcode 9), with 0 indicating success. Common error codes are:

Value | Meaning
25 | ADF out of paper
24 | Unsupported platform
23 | Bad window id
22 | Unable to load icon
21 | Cannot center
20 | Unable to add/remove image to imagelist
19 | Bad imagelist handle
18 | Unable to write disk (full?)
17 | Bits per pixel either unsupported or incompatible with image type. For example, JPG requires 8 bpp.
16 | TWAIN function is busy
15 | User cancelled scan
14 | Could not open TWAIN Data Source
13 | Could not open TWAIN Source Manager
12 | Could not create TWAIN parent window
11 | TWAIN error (See OPCODE 9)
10 | Cannot load or link VIC32.DLL (the imaging library module)
9 | Misc. XCALL parameter error
8 | Error during attempt to scale image
7 | Bad image handle
6 | Bad OPCODE
5 | Unable to allocated memory needed
4 | Exceeded maximum number of open images (31)
3 | Unknown image type/extension
2 | Image file not found
1 | Too few parameters passed to XCALL
0 | OK

The remaining errors are returned from within the VIC32.DLL library

Value | Meaning
–1 | Range error
–2 | Digitizer board not detected
–3 | Disk full
–4 | Filename not found
–5 | Variable out of range
–6 | Unreadable TIFF format
–7 | 8 TIFF bits per sample not supported
–9 | Unreadable compression scheme
–10 | Cannot create file
–11 | Unknown file format
–12 | Compressed DIB not supported
–14 | Insufficient memory for function
–16 | Unreadable PCX format
–17 | Unreadable GIF format
–18 | Print error
–25 | Unreadable TGA format
–26 | Bits per pixel value not supported
–27 | Unreadable BMP format
–34 | Function timed out
–40 | Could not lock memory
–41 | Print function already executing
–42 | Invalid image buffer address
–43 | Unreadable JPEG format
–44 | Image is too complex for operation
–53 | LZW compression/decompress not enabled
–68 | Handle not valid
–69 | TIFF file is in Motorola byte order

The following errors apply only to PNG images.

-100 | Unknown critical chunk
-101 | Not enough IDATs for image
-102 | Invalid IHDR chunk
-103 | Invalid bit depth in IHDR
-104 | Invalid color type in IHDR
-105 | Invalid color type/bit depth combo
-106 | Invalid interlace method in IHDR
-107 | Invalid compression method in IHDR
-108 | Invalid filter method in IHDR
-109 | Invalid image size in IHDR
-110 | Bad PNG signature
-111 | Bad CRC value
-112 | Extra data at end of file
-113 | Unexpected End Of File
-114 | Memory error
-115 | Decompression error
-116 | Compression error
-117 | Out of disk space


AUI_WINDOW

xcall AUI, AUI_WINDOW, opflag {,lft,top,rgt,btm {,rows,cols {,tsts,bsts {,cid,hg,vg {,monitors {,winsts}}}}}}

The AUI_WINDOW class is used for querying and changing the parameters of the window or monitor(s), such as its size, position, display state, number of rows and columns, etc.

Parameters

opflag (Num) [in]

specifies the window state desired, or an option to query the current state, per the following table.

Symbol | Value | Meaning
SW_QRYCTLPIXCLI | -4 | Same as SW_QRYCTLPIX (-3), except that it returns the control's client rectangle in the lft,top,rgt and btm parameters, instead of the control's window rectangle relative to the desktop. The client rectangle always starts at 0,0, so that the rgt and btm parameters give the width and height of the "usable" area (not counting borders, menus, caption) of the control.
SW_QRYCTLPIX or SW_QRYPIX | -3 | Same as -1 (SW_QRYCTLUNV) but returns the coordinates of the target window or control in pixels rather than Universal units.
SW_QRYMONPIX or SW_QRYMON | -2 | Query (multiple) monitor information. See cid. Returns rectangle (in pixel coordinates) in lft, top, rgt, btm.
SW_QRYCTLUNV or SW_QUERY | -1 | Query the current settings and update all of the passed parameters accordingly, return values in Universal units. See cid.
SW_HIDE | 0 | Hide window (i.e. make it invisible)
SW_SHOWNORMAL | 1 | Show window in normal format (neither minimized nor maximized)
SW_SHOWMINIMIZED | 2 | Activate window and show it minimized (displayed on the task bar)
SW_SHOWMAXIMIZED | 3 | Activate window and show it maximized
SW_SHOWNOACTIVATE | 4 | Show window in its most recent position but do not activate it
SW_SHOW | 5 | Activate and show window in its current size and position
SW_MINIMIZE | 6 | Minimize window and activate the next window in the task list
SW_MINNOACTIVE | 7 | Displays the window as a minimized window. This value is similar to SW_SHOWMINIMIZED, except the window is not activated
SW_SHOWNA | 8 | Display window in its current size and position, but do not activate it
SW_RESTORE | 9 | Restore a minimized or maximized window to its original position
SW_WINDEFAULT | 10 | Display the window in the default state as defined in the shortcut or startup info associated with the application
SW_ASHDEFAULT | 65 | Causes the window to initially be reset based on the current settings file (as edited on the Settings menu and saved with the File..Save menu). Omit all other parameters, or set them to 0 (except -1 for tsts and bsts).

lft, top, rgt, btm (Num) [in/out]

specify or retrieve the coordinates of the Window or monitor. Window coordinates (cid > 0) are in standardized units that range from 0,0 for the upper left corner of the screen to 10000,10000 for the bottom right. You may leave these 0 to retain the current window coordinates (if you just want to change the rows / cols or status lines.) Monitor coordinates (opflag = -2, cid < 0) are in pixels (and may be negative for secondary monitors).

When opflag = -1 and cid < 0 (to retrieve desktop resolution), these parameters taken on new meaning. lft and top return the dialog (altpos) grid size in pixels, while rgt and btm return the primary monitor size in dialog (altpos) grid units. (This provides an idea of the maximum size dialog that will fit on the screen.)

rows ,cols (Num) [in/out]

(if cid = 0) specify or retrieve the number of rows and columns which the main window is logically divided into. You may leave these 0 to retain the current window coordinates (if you just want to change the coordinates or status lines).

(if opflag = -1 and cid < 0) retrieve the dialog size overhead (title bar, borders, margins). As a general rule, the vertical overhead is equivalent to one logical row (one vertical dialog unit) and the horizontal overhead is negligible.

Note that when cid=0 (main window), the rows and cols parameters return the defined number of rows and columns in the main window (e.g. as set by SET TERM or TAB(-5,rows) and TAB(-6,cols).). But when cid > 0, they return the size of the target control in millirows and columns.

tsts, bsts (Num) [in / out]

specify or retrieve the visible / invisible state of the top and bottom status lines (1=visible, 0=invisible). You may leave these -1 (or omit them) to retain the current status line state.

cid (String or Num) [in]

Identifies the window, control, or monitor that the operation is to be performed on, per the following table. Default is 0, i.e. the main window. See Comments.

cid | opflag | Target object, information returned (for queries)
>0 (or name) | 0-9 | Perform the display operation specified by opflag (e.g. show, hide, etc.) on the specified control or window. No information returned. Operations on non-window controls may be limited to SW_HIDE and SW_SHOW.
>0 (or name) | -1 or -3 | cid identifies the control to be queried by its control number or name. lft, top, rgt, btm return the coordinates of the control, in universal coordinates (if opflag = -1), or pixels (if opflag = -3). rows and cols return the logical size of the control in millirows and columns.
0 | -1 or -3 | Main window. lft, top, rgt, btm return the coordinates of the control, in universal coordinates (if opflag = -1), or pixels (if opflag = -3). rows and cols return the logical size of the control in millirows and columns. tsts, bsts indicate the status line presence.
-1 | -1 | Primary monitor. lft and top return dialog (altpos) grid size. rgt and btm return monitor size in dialog units. hg and vg return monitor resolution in pixels.
-1 | -2 | Primary monitor. lft, top, rgt, btm return pixel coordinates of monitor.
-2 | -1 | Primary monitor. Same as if cid = -1 except subtracts area of the task bar from the returned parameters.
-2 | -2 | Primary monitor work area. lft, top, rgt, btm return pixel coordinates of monitor less task bar.
-3 | -2 | Second monitor. lft, top, rgt, btm return pixel coordinates of monitor (which may be negative if second monitor is to left of primary monitor).
-4 | -2 | Second monitor work area. lft, top, rgt, btm return pixel coordinates of monitor less task bar.
-5 | -2 | Third monitor. lft, top, rgt, btm return pixel coordinates of monitor. If there are three monitors, the assumed configuration is with the second monitor on the left, the third on the right.
-6 | -2 | Third monitor work area. lft, top, rgt, btm return pixel coordinates of monitor less task bar.
-99 | -2 | Total virtual screen. lft, top, rgt, btm return pixel coordinates of the bounding rectangle for the combination of all the monitors. Note that in the case of multiple monitors, depending on their arrangement and configuration, there may be spaces within this rectangle which do not actually appear on any monitor.

hg, vg (Num) [out]

These parameters, horizontal and vertical grid units, are applicable only when opflag = -1 (i.e. for query mode). When cid = -1, these return the screen resolution in pixels. Otherwise, they return the grid size, in universal units (0-10000) of the specified window or control. You can compare these grid values to the values returned in the lft, top, rgt, btm coordinates to determine sizes and positions in terms of row/column units.

monitors (Num) [out]

When opflag < 0, returns the number of monitors currently enabled. (You can then use opflag = -2 to retrieve information about individual monitors.)

winsts (Num) [out]

If specified with one of the query opflags, winsts will return one of:

Symbol | Value | Description
SW_HIDE | 0 | Window is hidden
SW_SHOWNORMAL | 1 | Window is neither minimized nor maximized
SW_SHOWMINIMIZED | 2 | Window is minimized
SW_SHOWMAXIMIZED | 3 | Window is maximized

Example:

! retrieve status of main window

xcall AUI, AUI_WINDOW, SW_QUERY, 0,0,0,0, 0,0, 0,0, 0, 0,0,0, winsts

switch winsts

case SW_HIDE

...

Examples

See the sample program AUIWIN [908,28]

Comments

When it comes to querying an individual control, the functionality of AUI_WINDOW overlaps that of AUI_CONTROL (with opcode CTLOP_INFO). In choosing between them, note that CTLOP_INFO returns coordinate information in logical millirows and columns, and relative to the parent of the control or window. These values will not be affected by moving the window or dialog around on the screen, or even resizing it. AUI_WINDOW, on the other hand, returns raw coordinate information, typically in "universal coordinates", relative to the desktop.

If using AUI_WINDOW to hide or display a control other than the main window, set cid to the name of numeric ID of the control, and set all the intervening parameters to 0, except tsts and bsts which should be set to -1. This functionality overlaps with that of AUI_CONTROL using opcode CTLOP_CHG.


AUI_HTMLHELP

xcall AUI, AUI_HTMLHELP, opcode, status, hfile {,htopic{, row, col}}

The HTMLHELP class provides means of displaying context-sensitive help using Windows CHM/HTML help system. By establishing links between topics in your help file and operations in your program, you can call the appropriate topic when the user invokes help. As currently implemented, the specified CHM file opens and displays the referenced topic.

Parameters

opcode (Num)

Symbol | Value | Description
HHOP_DFLT | 0 | Set default application help file. This allows help topics to be specified to INFLD without having to specify the help file each time.
HHOP_DSPID | 1 | Display topic based on HFILE (or default), and a numeric topic ID in HTOPIC. (You will have to consult the creator of your CHM files to get a list of the numeric topic ID numbers.) If HTOPIC is 0, the help file is launched in its default state.
HHOP_DSPSTR | 2 | Same as 1 except HTOPIC should be a string which specifies the internal HTM name for the desired topic. These internal names are typically of the form "/topicname.htm", e.g. "/comio.htm". The leading slash is typically necessary. You might be able to determine these names by using a binary DUMP utility on the CHM file (such as DUMP.LIT). As with opcode 1, if HTOPIC is "", the help file is launched in its default state.
HHOP_POPUP | 3 | Display a pop-up message. The text of the message (up to 2048 characters) should be specified in HTOPIC, and HFILE should be "". If ROW and COL are specified and non-zero, then the top center of the pop-up box will be positioned at that point. Otherwise, the pop-up box will be positioned just below the current cursor location.

status

If you want a return status, specify an F,6 variable, in which case, >=0 indicates success, and <0 indicates failure (including -15 for ATE timeout). The most likely failures would be that the CHM system is not supported (due to running on UNIX without ATE or perhaps an old version of Windows), or the help file/topic could not be located. If you do not care about the return status, specify this parameter as "". (This eliminates the need for the ATE client to return anything, which is a minor optimization.)

hfile (String)

File filespec of CHM file. May be in AMOS or native format and may contain environment variables using the %ENV% syntax. Note that you may put your help files in the same directory as the A-Shell help files, in which case you can reference them by:

HFILE = "%MIAME%\doc\filename.chm"

(If the environment variable %MIAME% is not explicitly defined, it will be interpreted as pointing to the directory where the miame.ini is.)

htopic (must be String for opcode 2 & 3, may be Num for opcode 1)

Specifies the topic name (<topic>.htm) (opcode 2) or ID (opcode 1) or the actual text to display (opcode 3). Text may contain embedded CRLF characters for line breaks.

row, col (Num)

These apply only to opcode 3, and only if you want to position the help window somewhere other than just below the cursor location. (For large messages, you might want to position it at something like ROW=2,COL=40.)

This function works in A-Shell/Windows and ATE. It may also be called via MX_HTMLHELP (replacing "HTMLHELP" with 137).


B64ENC

xcall B64ENC, infile, och, status {,flag}

or

xcall B64ENC, indata, outdata, status, flag

B64ENC.SBR provides Base 64 (aka MIME) encoding and decoding. The first format encodes a file, writing the encoded output to another file, while the second format may be used for encoding and decoding of memory buffers.

Parameters

ifile (String) [in]

Specification of file to encode in AMOS or native format

och (Num) [in]

Channel of a file, previously opened for output, to which the encoded version of the input file will be written. The file remains open on return.

status (Signed Num) [out]

On return, will be set to the number of bytes written, or <0 for errors

Value | Description
>=0 | Number of bytes written
-1 | infile not found
-2 | unable to open infile
-3 | och not valid (not open for OUTPUT)
-4 | file error during input of file
-5 | error during output
-6 | outdata too small to hold encrypted output

indata (X or String) [in]

Variable containing data to encode or decode

outdata (X or String) [out]

Variable containing encoded or decoded version of indata. Since encoded data is 4/3 larger than raw data, the determination of whether the operation is encode or decode is based on the relative sizes of the indata and outdata parameters. If the physical variable outdata is larger than indata, then the operation will be to encode. Otherwise it will be to decode.

flag (Num) [in]

If not specified, or set to 0, the format is assumed to be that given in the first syntax line above (encode a file). Otherwise, to encode a memory buffer, flag must be set to the number of bytes in indata to encode. (Since raw data may contain binary values, including 0, we can not use the normal string length method of determining the logical size of the input data.) To decode data, flag should be set to 1.

Comments

Base 64 encoded data uses only 64 distinct bytes (all printable) for representation, which is often convenient for including binary data within formats that are otherwise string-oriented (such as email). Because only six bits are used in each byte of the encoded representation, the encoded version of the data is 4/3 larger than the raw data. The raw data does not have to be a multiple of three.


BASORT

Updated March 2011

Random file syntax:

xcall BASORT, ch, reccnt, recsiz,
k1siz, k1pos, k1ord,
k2siz, k2pos, k2ord,
k3siz, k3pos, k3ord,
k1typ, k2typ, k3typ,
k4siz, k4pos, k4ord,
k5siz, k5pos, k5ord,
k6siz, k6pos, k6ord,
k4typ, k5typ, k6typ

Sequential file syntax:

xcall BASORT, chin, chout, recsiz,
k1siz, k1pos, k1ord,
k2siz, k2pos, k2ord,
k3siz, k3pos, k3ord,
k1typ, k2typ, k3typ

Note that in the syntax shown above, spaces and line breaks have no meaning—i.e., they do not and should not exist in the actual program. They are used here strictly as visual aides to illustrate the structure of the commands.

For sorting arrays in memory, see SORTIT.

Parameters

All BASORT parameters are [in] and Num. The key type (k?typ) values are 0 for string (default), 1 for floating point, and 2 for binary.

Param | Description
ch | File channel (used only with random files).
chin | Input file channel (used only with sequential files)
chout | Output file channel (used only with sequential files)
reccnt | Number of records in the file.
recsiz | Record length. For sequential files, this should be equal to or greater than the longest line in the file.
k?siz | Size of the sort key, in bytes.
k?pos | First character position occupied by the key.
k?ord | Sort order of the key, where 0=ascending, 1=descending.
k?typ | Data type of the key: 0=String, 1=Floating Point (random files only), 2=Binary (random files only), 3=Integer (random only), 4=Natural Sort, 5=case-insensitive natural sort. See History note for A-Shell 5.1.1135 below for more details on types 3-5.

Comments

A-Shell's implementation of BASORT.SBR is fully compatible with that under AMOS, optimized to make the best use of memory available. The sorting process is based around the quicksort algorithm, but up to three different types of sort may be performed depending on the amount of free memory. In the default case, the free memory is taken from the A-Shell partition. However, under systems with large amounts of efficient virtual memory available (e.g. UNIX and Windows), you may specify the option SBR=MALLOCSORT to miame.ini to cause A-Shell to dynamically allocate, if possible, a chunk of memory large enough to sort the entire file in one quicksort operation. See the SBR system parameter |topic=SBR for more details on the SBR options.

In the case of the sequential file sort, there is no option for key types because the keys must be string type. Also, since the record lengths can be variable, you should specify a recsiz as large or larger than the largest line in the file, up to a maximum of 4096. The file to be sorted must be open for input on chin, and the program must supply the channel (chout) of an output file into which you want the file sorted. If you want to sort the file on itself, you may specify chout as the same value as chin, in which case it only needs to be open once for input. If you want to re-read the sorted output file, you will need to close it and reopen it for input.

Here is a description of the three sort algorithms:

Type | Description
Small | The entire file is loaded, quicksorted and then saved to disk. This will occur if there is sufficient memory to load the entire file. It is extremely fast.
Medium | The keys are extracted from the file, and then quicksorted. A new file is then created by reading the records from the old file in the order of the quicksorted keys. This will occur if there is sufficient memory to load a tag file consisting of the sort keys and record numbers. It is reasonably fast.
Large | The file is quicksorted in chunks into two separate files. A disk-based poly-phase merge sort is then used to repeatedly merge these until a single sequence of sorted records results. This type of sort occurs in all other situations. It is quite slow.

The type of sort being used may be determined by specifying:

TRACE=AMSORT

in the system configuration file or with the command:

SET TRACE AMSORT

from the dot prompt.

Among other uses, the tracing display may be useful for analyzing the performance of a LARGE model sort (since the individual phases are shown).

As with BASORT under AMOS, records with the same sort key are guaranteed not to be re-ordered in the resulting file. This also applies to direct memory sorting of files in MEM:.

The normal limit on memory allocation with the MALLOCSORT option is 8MB, but you can change this with the MALLOCLIMIT=<bytes>{K}{M} parameter in the miame.ini file. Bumping this up, to say, 32MB, on a typical modern desktop PC can make a huge difference when sorting files larger than 8MB but smaller than the limit you specify.

If you’re looking for a more powerful sort routine—i.e. faster, able to handle more keys, able to perform data massaging beyond mere sorting, etc.—A-Shell includes the OptTech Sort routine which has been customized to understand most of the standard A-Shell data structures. Aside from offering additional keys and functionality, it is considerably faster than BASORT at sorting large files. It can also perform fancy data manipulation tricks, like removing duplicate records, adding summary records, creating tag files, etc. But, the calling interface is different, it does not handle certain file types, and there is a licensing fee. If interested, please contact MicroSabio for more details.

The absolute limit for BASORT file size is 2GB. Above that, you must use the OptTech Sort.

Troubleshooting tip: if you're having problems with large sorts failing, the first recommendation is to activate and configure the MALLOCSORT and MALLOCLIMIT options so that the sort can be performed using the Medium, or preferably, the Small algorithm, which is not only the fastest but the simplest and thus the least likely to run into complications.

History

2009 January A-Shell 5.1.1136: Six sort keys are now allowed, as opposed to three keys in prior versions.

2009 January A-Shell 5.1.1135: BASORT now includes three new sort types:

3: Integer (I,1 or I,2 or I,4)

4: Natural Sort

5: Case insensitive Natural Sort

Warning about using signed integer sort keys (B5, I1, I2 and I4) in files with a control record: traditionally the technique for preventing the control record from getting sorted out of place was to temporarily set it to all nulls, prior to sorting. But this is not adequate for signed integer sort keys, since nulls = 0, which is not at the bottom but in the middle of the range of signed values. The lowest possible signed integer value is -2^N where N is the # of bits in the field (e.g. -128, -32768, etc.) Similarly, for descending sort, the maximum value is 2^N-1.


BITOPS

xcall BITOPS, opcode, chfld, pos, result, result2

BITOPS.SBR was developed to facilitate the use of large bit fields (bitmaps). These are quite useful when you want to keep a single binary flag for each of many items. The bit field can be held in memory in a variable of type X, or in a random file.

Parameters

opcode (Num) [in]

specifies the operation using the following values:

Value | Meaning
1 | Clear bit #<pos>; if <pos> = -1 or is omitted, clear all bits in bitmap
2 | Set bit #<pos>; if <pos> = -1 or is omitted, set all bits in bitmap
3 | Counts all bits in bitmap; return number of 0s in result, number of 1s in result2
4 | Set result to bit number of first zero bit on or after given pos. If no more zero bits, return –1. At same time, set result2 to bit number of first one bit on or after pos.

chfld [in]

is either the bit field (if type X) of any size (first bit is considered bit #0); if any type other than X, chfld is interpreted as an open random file channel (containing the bit field).

pos (Num) [in]

specifies the bit number we are operating on or starting from (see opcode table above).

result, result2 (Num) [out]

are used to return the results (see opcode table above).


BLOCKS

xcall BLOCKS, device, blks, cblks, {,tblks} {,unitscale}

BLOCKS.SBR allows a program to check how much disk space is free on the specified device and, optionally, the total space on the device.

Parameters

device (String) [in]

must be specified without the trailing colon (e.g. DSK0 or EXT1) and must be a device defined in the miame.ini file.

blcks, cblks (F,6) [out]

returns the number of free blocks (512 bytes per block) on the device. If the device cannot be accessed, the block count will be returned as –1.

tblks (F,6) [out]

returns the total number of blocks (both free and used) on the device.

unitscale (Num) [in]

specifies a scale factor for the returned "block" units:

Value | Size of "block"
0 or not specified | 512 bytes
1 | 1 KB
11 | 1 MB
21 | 1 GB

Note that the values for unitscale are actually powers of 2 to be used relative to the number of 512-byte blocks.

Comments

There are a few idiosyncrasies to note about BLOCKS:

• Under A-Shell, there is no particular significance to contiguous blocks, since there is no particular significance to them under Windows or UNIX. This is why it is always equal to the number of free blocks. You do not need contiguous blocks to allocate random files like you do under AMOS.

• 512-byte AMOS-style blocks have no particular significance to the host operating system. Under Windows and UNIX, the minimum allocation unit is related to something other than physical disk blocks (i.e. clusters or inodes) and for that matter, the physical disk block size may or may not be 512.

• Since A-Shell does not impose any kind of partitioning on the pseudo-AMOS devices, it is really the free space on the logical host disk that is being measured. For example, DSK0 may be mapped to /vm/miame/dsk0 and DSK1 to /vm/miame/dsk1, but both of those are part of the same UNIX file system. So they will both show the same amount of free space. (Do not get fooled into thinking that that much free space is separately available on both devices, since it is really only one device from the host operating system's point of view.)

Despite these quirks, for AMOS applications, it is still a useful approximation to the amount of free space available.

History

2014 May, A-Shell 6.1.1386: Add unitscale


BLOFSH

Added to A-Shell, August 2016

xcall BLOFSH, opcode(=1), impure, key

xcall BLOFSH, opcode(=2), impure, cleartext, ciphertext

xcall BLOFSH, opcode(=3), impure, ciphertext, cleartext

BLOFSH.SBR implements the Blowfish encryption algorithm. It is used to encrypt or decrypt data in memory using a variable length key of 32 to 448 bits.

Blowfish is a symmetric-key block cipher, designed in 1993 by Bruce Schneier and made available to the world for royalty-free use. See the Blowfish entry at Wikipedia for more information.

Parameters

opcode (Num) [in]

1 to load the key, 2 to encrypt, 3 to decrypt

impure (Raw, 4168) [in/out]

A block of 4168 bytes which must be provide to the XCALL for its use as a work area. Do not modify it between calls.

key (Raw) [in]

A variable containing your encryption key. The mapped size of key determines the length of the encryption key, which can be from 4 to 56 bytes—i.e. 32 to 448 bits. Note being a symmetric cipher, the same key is used for encryption and decryption. Obviously you should generate an unpredictable key and store it securely.

cleartext (Raw) [in/out]

An area containing or overlaying the clear data. For opcode 2 (encrypt), this is the source; for opcode 3 (decrypt), it is the destination. The size in bytes must be divisible by 4, and must match the ciphertext size. You can use an overlay or an assignment to up-size your actual clear text field. For example, to encrypt a string 29 bytes long, you might map it as follows:

map1 cleartext$,s,29

map1 cleartext,x,32,@cleartext$

ciphertext (Raw) [in/out]

An area containing or overlaying the encrypted data. Restrictions and comments given for cleartext apply here as well.

Example

MAP1 X,I,2

MAP1 BF'IMPURE,X,4168 ! internal work area

MAP1 BF'KEY ! (4 to 56 bytes, divisible by 4)

MAP2 BF'KEY(4),B,4 ! 16 bytes (128 bits)

MAP1 SECRETS

MAP2 NAME,S,36

MAP2 CODE,F,6

MAP1 CLEARTEXT,X,48,@SECRETS ! must be divisible by 8

MAP1 CIPHERTEXT,X,48 ! must be same size as CLEARTEXT

X = SRND2(0,0,&hFFFFFFFF) ! randomize, set 32 bit range

for X = 1 to 4 ! generate 4 32-bit random values for key

BF'KEY(X) = RND2()

next X

open #1, "BLOTST.KEY", output ! save the key

? #1, BF'KEY;

close #1

xcall BLOFSH, 1, BF'IMPURE, BF'KEY ! init cipher from key

NAME = "James Bond"

CODE = 0.007

xcall BLOFSH, 2, BF'IMPURE, CLEARTEXT, CIPHERTEXT ! encrypt

open #2, "BLOTST.DAT", OUTPUT

? #2, CIPHERTEXT; ! write encrypted data to file

close #2

! later, to decrypt...

open #1, "BLOTST.KEY", input ! retrieve the saved key

input raw #1, BF'KEY

close #1

xcall BLOFSH, 1, BF'IMPURE, BF'KEY ! re-init cipher from key

open #2, "BLOTST.DAT", input

input raw #2, CIPHERTEXT ! read encrypted data

close #2

xcall BLOFSH, 3, BF'IMPURE, CIPHERTEXT, CLEARTEXT ! decrypt

? "NAME = ";NAME;", CODE = ";CODE

end

Comments

When encrypting string fields, you can copy to/from the original (S format) field and the cleartext / ciphertext (X format) fields. But when encrypting numeric fields or structures, you must use the overlay method shown above. In all cases, you must save the entire ciphertext variable, not just the number of bytes in the actual data. In the example above, the actual data is only 43 bytes but the encrypted data is 48 bytes long, i.e rounded up to the next multiple of 8 bytes.

To generate truly unpredictable keys, see Random Number Generators. To avoid saving the key, you may be able to use some fixed function based on inputs unique to the situation—file #, customer #, ppn, etc.—to produce the seed from which you then can generate and later regenerate a pseudo-random sequence.

If you are exporting your application which encrypts or contains encrypted data, you may want to check your country's regulations. The US has loosened its requirements but there are still situations where Blowfish encryption with keys longer than 56 bits may be restricted.

History

2016 August, A-Shell 6.3.xxxx: Routine added to A-Shell


CCON, CCOFF

xcall CCON {,flag}

xcall CCOFF

CCON.SBR enables or disables Ctrl+C. When called with no arguments, or if the argument passed has a non-zero numeric value, then it enables Ctrl+C. When called with an argument that evaluates to zero, it disables Ctrl+C and is therefore equivalent to CCOFF.SBR.

CCOFF.SBR disables Ctrl+C. This might be useful in a program at the start of a critical update sequence that you did not want the operator to be able to interrupt. It is also equivalent to SET NOCTRLC (from the dot prompt).


CGIUTL

Updated September 2014; see History

xcall CGIUTL, opcode {,param1, param2 ...}

CGIUTL.SBR contains several utility functions which are very handy when writing CGI programs. The calling format and parameters beyond opcode depend on the value of opcode, so we will consider each case separately, with the value of OPCODE inserted into the syntax examples below. Opcode itself can be any numeric format. See A-Shell as a CGI Engine for more details on using CGIUTL.SBR.

Beginning with A-Shell 6.1.1390 of September 2014, A-Shell provides support for FastCGI.

Opcode | Value | Function
CGIOP_STATUS | 0 | CGI Status
CGIOP_STDIN | 1 | Retrieve stdin
CGIOP_GETPAR | 2 | Retrieve single parameter
CGIOP_MRGOUT | 3 | Copy disk file to stdout
CGIOP_STDOUT | 4 | Write string to stdout
CGIOP_GETENV | 5 | Retrieve envvar into envdef
CGIOP_MRGFIL | 6 | Generate custom file from template
CGIOP_GETPARX | 7 | Retrieve multiple parameters
CGIOP_UNESCAPE | 9 | Convert HTML Escapes
CGIOP_GETREQ | 10 | Support FastCGI
CGIOP_GETPARARY | 12 | Retrieve params into associative array
Definition file: ashell.def

History

2014 September, A-Shell 6.1.1394: Add opcode CGIOP_GETPARARY.

2014 September, A-Shell 6.1.1390: Add support for FastCGI and opcodes CGIOP_UNESCAPE and CGIOP_GETREQ.

2009 March, A-Shell 5.1.1140: The 16K limit on the size of a single expanded line of the template HTML file (using opcode 3 or 6) has been lifted. (It may take some ingenuity to create such long lines, but apparently some A-Shell developers are up to the challenge.) The only limits which remain are that 32K for the length of a template line prior to variable substitution and 256 total substitution variables (which may be distributed over 96 XCALL parameters). Also, increase the default maximum size of the parameter buffer passed by the web server to A-Shell from 4K to 16K (applies only in the case where the web server does not support the CGI standard by defining the CONTENT_LENGTH environment variable; IIS seems to fall into this category.)

2007 September, A-Shell 4.9.995: The previous limit of 1024 on the size of an individual line after variable expansion has been increased to 16K. This is mainly a factor when individual data fields (substitution values) are quite large, since otherwise you could avoid the limit by keeping the input template lines short.


FastCGI

FastCGI if an optimized variation of the normal CGI protocol, which differs primarily in that the application server instances persist across many requests, rather than having to be launched and terminated for each request. FastCGI thus vastly reduces the overhead of servicing web requests, particularly for relatively large/complex application servers (like A-Shell).

FastCGI is widely available on common web servers such as Apache and IIS, but almost certainly requires some configuration to enable. As of this writing, is has only been tested with Apache 2.4 under Windows.

To enable support for FastCGI protocol in A-Shell, change the -cgi command line switch to -cgifast. A-Shell will then determine whether the server is using FastCGI or normal CGI protocol, and will act accordingly—i.e. support either protocol.

Existing A-Shell CGI applications require a minor modification after which they can support either mode as well, without having to be aware of the difference. Since the main objective of FastCGI is to avoid the need to launch a new instance of the application server for each request, you need to introduce a loop into your application so that after servicing a request, instead of exiting, it loops back to wait for another request. In other words, you must convert this:

<process request>

<send response>

end

to this:

do

xcall CGIUTL, CGIOP_GETREQ, status

if status < 0 exit

<process request>

<send response>

loop

end

The CGIUTL opcode CGIOP_GETREQ waits until the request has been received as is ready to process in the normal way. For the first request after the instance has been launched, it will return immediately (be essentially a NOP). For subsequent requests, it waits until another client submits a request, or perhaps the server shuts us down. In the case of normal CGI mode, the second request will return -1, telling the app to shut down, as it would normally do for CGI.


CGI Status

xcall CGIUTL, CGIOP_STATUS, status

Opcode 0, CGIOP_STATUS, simply checks if A-Shell was launched with the –cgi switch, returning 1 (in status) if so, else 0. This can be useful when writing programs that work differently depending on whether they are running inactively or under control of a web server.


Retrieve stdin

xcall CGIUTL, CGIOP_STDIN, string, status

Opcode 1, CGIOP_STDIN retrieves the entire stdin into the string parameter. The web server will have put all of the form information to be passed to the CGI program into stdin, provided that you set the form method to "POST." Returns status=0 for ok, 1 for overflow (string too small), or -1 if not in CGI mode (i.e. –cgi switch not specified). This is considered a utility operation and is probably not necessary since most of the other operations are capable of reading the stdin directly.


Retrieve single parameter

xcall CGIUTL, CGIOP_GETPAR, parmname, parmval, status {, string}

Opcode 2, CGIOP_GETPAR, retrieves the web form parameter whose name is specified by parmname, into the string variable parmval. This requires that the web form was submitted with the "POST" action, and that the A-Shell session was launched via the CGI process, using the -cgi switch. (In this case, the parameters willl have been passed via the stdin channel.) Returns status=0 for OK, or -1 if the parameter is not found, or –2 if not in CGI mode.

If string is specified it is used in place of stdin. It must be formatted in the same way that stdin would have been formatted by the CGI interface, i.e.:

name1=value1&name2=value2&...nameN=valueN"

"+" characters are interpreted as spaces, and anything of the form %xx (where xx are two hex digits) is translated to the equivalent ASCII character.)

Note that if you use the form action GET instead of POST, you can query the variables by retrieving the definition of the environment variable QUERY_STRING (see MX_GETENV) into the string parameter.

Also note that when string is specified, you do not actually have to be in CGI mode, and thus the operation could be useful for non-CGI purposes.


Copy disk file to stdout

xcall CGIUTL, CGIOP_MRGOUT, file, status {varsub1, varsub2 ..., varsub27}

Opcode 3, CGIOP_MRGOUT, copies a disk file (typically a web page template) to stdout, thus completing the CGI operation. (The web server launches the CGI application, passes it input via stdin, then waits for the output to come back via stdout.) To simplify the process of generating a custom web page, you may specify up to 256 variable substitutions, allowing you to use use a common template which is thereby customized.

file (String) [in]

AMOS or native file specification for input file. In the case of ambiguity, AMOS-style will be assumed; you can force it to assume native-style by prepending a "./" to the name (e.g. "./NativeFile.html")/ There is no particular limit to the size of the input file, but each line must be less than 32K (prior to any variable substitutions).

varsubN (String) [in]

One or more variable substitution definitions of the form <name>=<value> (e.g. $CLIENTID=12345). To increase the number of substitution definitions (up to the maximum of 256) without exceeding the limit of 100 XCALL parameters, you may include multiple substitutions in one parameter by separating them with a "+" (e.g. $CLIENTID=12345+$NAME=Bits 4 Us). To include the literal character '=' or '+' in a substitution, precede it with a backslash (e.g. $FORMULA=1\+1\=2 )

The variable substitution names are case sensitive, but do not have to be terminated or delimited in any special way. To avoid inadvertent matches, you might want to prefix and/or suffix them with some special character, like $.

status (signed number) [out]

Will be set to 0 to indicate that a page was successfully generated, although it may still fail to meet the necessary syntactic requirements for a valid webpage. –1 indicates that file could not be opened.

Comments

This operation can be difficult to debug, since if the resulting page is not valid, the web server will not display any of it and it will not be available for inspection. A first debugging step would be to attempt to launch filein the browser directly, which should work (displaying the variable names instead of the replacement values) provided that variables are not used for critical elements of the HTML page structure. A second debugging step would be to add TRACE=XCALL, or otherwise arrange for the command SET TRACE XCALL ON to be executed before the program runs. This will not only log the XCALL parameters (for all XCALLs) to the ashlog.log file, but will also create a file CGIUTL.LOG containing a copy of the merged file that was output to stdout.

A common mistake in creating a template web page is to forget to include the "content-type" header line, which it not required in static web pages but is required in pages generated through CGI. As a minimum, the template and/or resulting page should contain the following elements (note the mandatory blank line following the "content-type" header:

content-type: text/html

<HTML>

<HEAD>

<TITLE>This is the page title</TITLE>

</HEAD>

<BODY>

bla bla bla

bla bla bla

</BODY>

</HTML>


Write string to stdout

Updated November 2014; see History

xcall CGIUTL, CGIOP_STDOUT, string, status

Opcode CGIOP_STDOUT writes string to stdout. A CRLF is appended to the string, analogous to a PRINT statement. Use this in place of PRINT statements to output individual characters or lines to the new web page. (In -cgi mode, the output of PRINT statements is sent to the stderr stream rather than stdout. For more information, see the A-Shell command line switch CGI.)

History

2014 November, A-Shell 6.1.1395: Binary output is now supported, specified variable must be type X. This provides the possibility of an A-Shell CGI program rendering a download to the browser. Which has some security advantages over statically storing the file to be downloaded and letting the web server handle it directly.


Retrieve envvar into envdef

xcall CGIUTL, CGIOP_GETENV, envvar, envdef, status

Opcode 5, CGIOP_GETENV, retrieves the contents of the environment variable envvar into the string variable envdef. status will be set to 0 for OK, or 1 if the variable had to be truncated to fit in envdef. If there was no such variable defined, envdef will be null.


Generate custom file from template

xcall CGIUTL, CGIOP_MRGFIL, file, status, outch {,varsub1, varsub2 ... {,varsub27}

Opcode 6, CGIOP_MRGFIL, is identical to opcode 3 (which see for further parameter details), except that instead of outputting to stdout, it outputs to an arbitrary open file channel, thus making it useful for all kinds of purposes besides CGI. (It was combined here rather than as a separate subroutine because it shares nearly all of the same logic as CGIUTL opcode 3.

file (String) [in]

AMOS or native file specification for input file.

status (signed number) [out]

Will be set to 0 to indicate that a page was successfully generated (although it may still fail to meet the necessary syntactic requirements for a valid webpage). –1 indicates that file could not be opened.

outch (Num), [in]

File channel (must be open for output)

varsubN (String) [in]

One or more variable substitution definitions of the form <name>=<value> (e.g. $CLIENTID=12345).


Retrieve multiple parameters

Updated January 2009

xcall CGIUTL, CGIOP_GETPARX, status, skipcount, parmname1, parmvalue1, ... parmnameN, parmvalueN {,string}

Opcode 7, CGIOP_GETPARX, provides an alternative to opcode 2 for retrieving parameter values. Instead of retrieving one value at a time by parameter name, it retrieves several sets of parameter name/value pairs based on parameter number:

skipcount (Num) [in]

should be set to the number of name/value pairs to skip. Set to 0 to start with the first parameter.

status (Signed number) [out]

returns status:

-1 = specified starting parameter number (skipcount+1) doesn't exist

-2 = not cgi mode and no string param passed

-3 = syntax error in parameter data (last parmname arg will contain the relevant part of the string)

>=0 = # of parameter name/value pairs available to process (after the skipcount). If this is larger than the number of sets of parmname/parvalue pairs passed, it indicates to the application that it can make another call (using skipcount) to get additional parameters.

parmname (String) [out]

returns parameter name

parmvalue (String) [out]

returns parameter value. You can specify up to 48 pairs of these (to stay within the 100 XCALL parameter limit). You use the returned status to determine how many of the pairs contain valid information. CGIUTL will also set the first ununsed parmname to "" so you could also process the pairs until the first empty parmname.

string (String) [in] optional

may be used to pass a string to use as input, instead of the stdin string normally passed to A-Shell in CGI mode. Note that CGIUTL recognizes the existence of the string argument by there being an even number of arguments > 5. So make sure your parmname/parmvalue arguments are paired or the last one will be confused with an input string. See opcode 2 for information on the format of the string input.


Convert HTML Escapes

xcall CGIUTL, CGIOP_UNESCAPE, in, out, status

Opcode 9, CGIOP_UNESCAPE, is a utility function used to convert a string containing HTML escapes (mainly %xx where xx is a hex value) to the ASCII equivalent. This is sometimes useful for logging and other auxiliary functions.

in

HTML-encoded string to unescape

out

is a string variable to receive the output (dynamic string ok)

status

returns a status code (0 for ok)


Support FastCGI

xcall CGIUTL, CGIOP_GETREQ, status

Opcode 10, CGIOP_GETREQ, is used to support FastCGI.

status (Num signed)

returns 0 if a request is available to process, or -1 if not, in which case the application should terminate.

For FastCGI mode requests after the first one for the instance of the application server, this call will sleep until a request is available or the web server tells us to exit, or an error occurs.


Retrieve params into associative array

Updated February 2015

xcall CGIUTL, CGIOP_GETPARARY, status, $ary() {,string$}

Opcode 12, CGIOP_GETPARARY, retrieves the entire set of name=value pairs into an ordered map (aka associative array)

Parameters

status (Num) [out]

Returns the number of name=value pairs loaded. 0 indicates either that no name=value pairs were passed into the CGI request, or that the version of A-Shell is prior to 6.1.1394 when this function was introduced.

$ary() (Ordered map) [out]

An associative array to be loaded with the name=value pairs. It should be declared as follows:

dimx $ary, ordmap(varstr;varstr)

As with other parameters, you can name the array as you like, but you must specify the empty parentheses as in the example. This is special code to the subroutine to treat the parameter as an entire array, rather than as just one element. Also note that any existing contents of the array will not be automatically cleared, although any conflicting name=value pairs will be replaced. If reusing the array for multiple requests, you should probably use the .CLEAR function to clear it.

Note: for a brief period prior to compiler edit 734, it was necessary to use the syntax $ary("") instead of $ary(). That usage is still accepted but deprecated, as it could be too easily confused with a reference to a single element.

string$ (String) [in]

If specified, the string$ parameter should contain the list of name=value pairs making up the request; see CGIOP_STDIN. Otherwise the request is taken directly from the stdin passed to the program by the web server.

Comments

The form of the request, whether in string$ or in stdin, should be:

name1=value1&name2=value2&...&nameN=valueN

For example, if assuming string$ = "fromCurrency=US&toCurrency=Euro", the following code...

dimx $req, ordmap(varstr;varstr)

xcall CGIUTL, CGIOP_GETPARARY, status, $req(), stdin$

print "fromCurrency = "; $req("fromCurrency")

will print:

fromCurrency = US

toCurrency = Euro

Or you can use a foreach loop to retrieve all of the name=value pairs without knowing in advance what to expect, i.e.

foreach $$i in $req()

switch .key($$i)

case "toCurrency"

tocurr$ = $$i

exit

case "fromCurrency"

fromcurr$ = $$i

exit

...

endswitch

next $$i


CHKONE

xcall CHKONE, c$

CHKONE.SBR is similar to TINKEY in that it allows you to check if a keyboard character is available, without getting stuck waiting if there is no character available. However, unlike TINKEY, which returns the actual character if available, CHKONE returns a "0" if no character is available, else "1". Any available characters remain in the input buffer, waiting for you to use another input routine to get them. c$ is a one-byte string.


CISAM

Added March 2013

xcall CISAM, opcode, ch, idx, recno {,status}

CISAM.SBR is an internal interface to the ISAMPLUS file system, generally only used by system-level utilities and thus not previously documented. In A-Shell 6.1.1140 of March 2013, the routine was "made public" because new functions expose a capability that is not yet available in regular BASIC/ISAMPLUS syntax. The limitation with the old ISAM'PUSH and ISAM'POP was that it is single-level, i.e. supports only one level of ISAM'PUSH for any given channel at a time. The XCALL functions documented here allow you to "push" an arbitrary number of file positions/states and "pop" them in an arbitrary order.

Opcode 33 is equivalent to ISAM'PUSH #CH, except that it returns to you the current IDX and RECNO.

Opcode 34 is equivalent to ISAM'GOTO #CH, IDX, RECNO (which does not yet exist). This is similar to ISAM'POP, except repositions the internal state and position according to the specified IDX and RECNO, rather than the previously pushed one.

Note that the IDX numbering starts from 1 here, contrary to the IDX numbering in Basic, which starts at zero.

Both functions return 0 in STATUS for success, else error.


CMDR

xcall CMDR

Calling CMDR.SBR has the same effect as if the line :R were executed in a command file. It can be particularly useful when trying to integrate command files and BASIC programs in order to implement more .LIT A-Shell commands.

CMDR.SBR has no effect if the command file is currently in either :R or :T modes.


COMIO

Updated and reviewed October 2010

xcall COMIO, opcode, channel, buffer, status, count {,msg, timeout}

COMIO.SBR is included with A-Shell/Windows to allow simple I/O on Windows serial ports, since you cannot open up a Windows serial port as a file, like you can on other platforms. COMIO supports ports beyond COM9, and logs read/write errors to ashlog.log. Also:

• Refer to the sample program, COMIO.BAS, which is included in the EXLIB.

• For more sophisticated applications involving serial communications, Autolog from Soft Machines is recommended.

Parameters

opcode (Num) [in]

specifies the operation according to these options:

Value | Meaning
1 | Open port specified in the buffer parameter, return channel in channel
2 | Close port specified by channel
4 | Check if any characters available to read; return count in count
8 | Input a maximum of count characters; see the count table below for special cases
16 | Write exactly count characters (or up to null if count=0)

channel (Num) [out]

specifies the channel number associated with the port. This value is returned from the open operation, and must be passed to the subroutine for all other operations.

buffer [in/out]

is usually a string variable to pass the data to be sent or received (for read/write operations). For the open operation, it is used to pass control information about the port settings, and must be mapped as follows:

MAP1 BUFFER

MAP2 BYTESIZE,B,1 ! 7=7 bits, 0 or 8 = 8 bits

MAP2 PARITY,B,1 ! 0=none, 1=odd, 2=even, 3=mark, 4=space

MAP2 STOPBITS,B,1 ! 0=1, 1=1.5, 2=2

MAP2 FLOWCTL,B,1 ! Add: 1=DTR/DSR, 2=RTS/CTS, 4=XON/XOFF

MAP2 MISC,B,2 ! Unused

MAP2 PORT,S,20 ! e.g. "COM1" (no colon)

status (Num) [out]

returns a status code or bit field indicating the level of success of failure of the operation:

Value | Meaning
0 | Success
-1 | Parameter error
-2 | No more memory handles available
-3 | Memory allocation failure
-4 | Unable to create write event
-5 | Unable to create read event
-6 | Invalid channel passed in CH argument
-7 | Unable to open connection to port
-8 | Ctrl+C received while waiting for input
-9 | Unable to set comm parameters; see History below.
>0 | Bit field containing one or more port status error flags from the following table:

Value | Port Status Error Flags
&h0001 | Input buffer overflow. (Either no room in input buffer, or char received after EOF)
&h0002 | Buffer overrun (next character is lost)
&h0004 | Parity error
&h0008 | Framing Error
&h0010 | Break detected
&h0100 | Output buffer full
&h0200 | Time out (parallel device)
&h0400 | I/O error
&h0800 | Device not selected (parallel device)
&h1000 | Parallel device is out of paper
&h8000 | Requested mode not supported

count (Num) [in/out]

usage depends on the operation, as given in the table. Also see History, below.

Operation | Value | Usage of COUNT parameter
Open | 1 | Must be set to the desired baud rate.
Close | 2 | Ignored
Check | 4 | Returns number of characters available to be read.
Read | 8 | Must be set to either the number of characters you wish to read, or a special code (<=0) indicating the character you want to terminate the read on. The read routine will continue reading (and waiting if necessary) until the requested number of characters, or the requested terminating character, is received (up to the time limit specified by a timeout parameter > 0). To input up to a specific terminating character whose ASCII value is N, set count to -N. (For example, set count = -3 to input up to a byte chr(3).) 0 and -1 are historical exceptions to this formula. 0 inputs up to a terminating LF, while -1 inputs up to a terminating CR. (The terminating character, and in the case of LF, the immediately preceding CR, will be stripped from the buffer.) On return, count will be set to the number of bytes received, including any terminating character(s).
Write | 16 | Must be set to the number of characters to write (from the BUFFER parameter). You may set it to 0 to output up to the first null byte in the BUFFER string. On return, it will contain the number of characters actually output.

msg (String) [out]

returns the text of the Windows error message if an error occurs. The text will be truncated to fit, but for best results map msg to eighty-plus characters. If no error, then msg will be "". Beginning with A-Shell 5.1.1170 of January 2010, the error message begins with the actual Windows error code, making it easier to identify with precision.

timeout (Num) [in]

timeout value (in seconds), applies only to check (4), read (8) and write (16) operations. This is particularly useful when reading with the option to read until CR or LF, since if the data ends without sending a CR or LF, you could otherwise be stuck waiting forever. If timeout occurs, msg will be set to "TIME" (or possibly "(#) TIME" where # is an internal error code). The status and count parameters may or may not indicate an error, so when using the timeout option, you should always check msg to see if it contains the substring "TIME".

History

2010 October, 5.1.1193: The timeout feature now applies to the check (4) operation as well as the read (8) and write (16) operations. Also, it now applies to all variations of the read operation. (Previously it only worked in the variation where it was reading up to a CR or LF.)

An internal timer interval which affected buffering and response time was reduced from 1 second to 1/10 second, potentially pauses of up to 9/10 of a second during sending and receiving operations.

2009 December, 5.1.1170: A new status code -9 (unable to set comm parameters) has been added to distinguish when the open operation fails because of fundamental reasons (status -7) or because of an error while initializing the port (status -9). Also, the system error message (returned in the msg parameter) now begins with the actual Windows error code, making it easier to identify with precision.

2009 December, 5.1.1168: In addition to the existing OPCODE 8 (read) special COUNT values of 0 (read to LF) and -1 (read to CR), you may now specify any character value for the terminating character to read to, by putting its negative ASCII value (-2 thru -257) in COUNT. For example,

COUNT = -3 ! read to ETX or chr(3)

xcall COMIO, 4, CH, BUF, STATUS, COUNT

Since -1 is interpreted as chr(10) (LF), to specify chr(1) (SOH) as the terminating character, set COUNT = -257.

To read up until an explicit null byte, set COUNT = -256. Note that this requires that we receive a explicit null byte in the input buffer, not to be confused with the implicit null byte used to terminate the buffer.

Consistent with previous operation, the terminating byte is discarded, although it is included in the returned COUNT (indicating the number of characters received). And in the case of COUNT = 0 (wait for LF), if the character preceding the LF is CR, the CR is also discarded. (The previous documentation described this option as waiting for CRLF, but in reality, it has always terminated on LF, with the preceding CR being optional.)

2006 April, A-Shell 4.9.955: Add support for the msg and timeout parameters, as well as the logging function and support for ports greater than COM9.


COMMON

xcall COMMON, send, msgnam, var

xcall COMMON, recv, msgnam, var

COMMON.SBR is a widely used (and widely modified) routine for sending a block of data from one program to another.

Parameters

MAP1 SEND,B,1,0

MAP1 RECV

MAP2 F'RCV,B,1,1

MAP2 RCVFLG,B,1,0

send, recv

must be mapped as shown above. As the names imply, send is used for sending a packet and recv for receiving one.

rcvflg [out]

will be returned as 0 if the requested packet is not found, else it will be set to a non-zero value.

msgnam (String, up to 6 characters) [in]

specifies the name of the packet. This is how packets are identified if more than one is being stored at the same time.

var (Raw)

supplies the data to send or returns the received data. Do not use a dynamic variable (X,0) variable.

Comments

Under AMOS, normal usage requires that you load COMMON into user memory, since it stores the data within itself. COMMON does not exist as a separate module under A-Shell; however, the command line .LOAD BAS:COMMON will have the same effect as under AMOS, in that all COMMON packets will be cleared.

The default packet set-up is 6 packets of 150 bytes. This may be changed by adding, for example, the following line to the miame.ini configuration file:

SBR=MSGNUM:4,MSGSIZ:1024

This would decrease the number of packets to 4, with a size of 1024 bytes each. More information is given in the documentation for the miame.ini file.

As with the standard version of COMMON under AMOS, a read operation is destructive. That is, the packet is cleared upon reading it. Thus, if you want to read the packet and then pass it on to another program, you have to rewrite it after reading. Some people use a modified version of COMMON which has a non-destructive read. To support this variation, add SBR=COMMONNDR to your MIAME configuration file (the NDR stands for Non Destructive Read).


CONDEV

xcall CONDEV, dev {,dns'flag}

CONDEV.SBR returns an identifier for the client workstation or console/terminal device. It is useful in situations where you want to identify the physical workstation, rather than the user or session.

The identifier can take one of several forms, depending on the operating system and other factors. Under Windows, it will return the NetBIOS machine name (e.g. "SALESPC"). Under UNIX, it will first check to see if the environment variable REMOTEHOST is defined, and if so, it returns its definition. (Many shells will define the environment variable REMOTEHOST to contain the IP address of the workstation). Otherwise, if it can determine the IP address of the client workstation, it will return that in ###.###.###.### format. Otherwise, it will return the terminal device (pseudo or real tty) name, e.g. "ttya02" or "pts/0".

Parameters

dev (String) [out]

receives the identifier (described above)

dns'flag (Num) [in]

If specified and non-zero, an attempt will be made to convert the IP address to the equivalent host name. This can sometimes introduce a delay if there is no local DNS server.

Comments

See GETUSN, which is similar.

If you are using the ZTERM terminal emulator (and possibly others) you can retrieve the client’s IP address using a ZTERM Escape Sequence. In the case of ATE, you can also use MX_GETIP.


CRC16

xcall CRC16, block, crc, size

CRC16.SBR calculates a 16 bit CRC (aka CRC-16) for the specified block of data.

Parameters

block (Raw) [in]

is an unformatted variable of arbitrary size.

crc (Num) [out]

will return the CRC-16 value.

size (Num) [in]

specifies the number of bytes within block to consider.


CRYPTO

Updated December 2016; see History

XCALL CRYPT, opcode, status, src, decoding, src, encoding, cflags {, cipher, key, keybits, cmode, padding {, cbsrc {, iv {, aad, authtag}}}}

CRYPTO.SBR provides a collection of cryptographic-related functions.

Parameters

opcode (Num) [in]

One of the following:

Symbol | Opcode | Description
CRYPTOP_ENCRYPT | 1 | Encrypt the src parameter into the dst parameter
CRYPTOP_DECRYPT | 2 | Descript the src parameter into the dst parameter
CRYPTOP_GENKEY | 3 | Generate a random symmetric key
CRYPTOP_ENCODE | 4 | Encode (or decode) src parameter into dst parameter
CRYPTOP_GENPUBKEY | 6 | Generate a Public/Private Key file pair, which see for details.
Definition File: CRYPTO.DEF

status (Signed Num) [out]

Returns the result status of the operation: >= 0 for success (number of bytes output to dst), <0 for errors (see CRYPTERR_xxx in CRYPTO.DEF)

src (String or Raw) [in]

Supplies the input data for the operation. May be either a filespec (AMOS or native), a string, or an arbitrary length of binary data. If the case of an X variable containing binary data, the number of bytes must be specified in the cbsrc parameter. Otherwise the length can be determined from the file size or the string length. See cflags.

decoding (String) [in]

Specifies a type of character decoding to perform on the src prior to any further processing, from the table below:

Encoding/ Decoding | Description
“raw” (or “”) | None
“hex” | Hexadecimal format (each byte of data represented by two hex characters)
“base64” | MIME/base64 (each three bytes of data represented by four bytes from the 64-byte MIME character set); typical format for storing encrypted text
"url" | url format (non-printable characters represented using %xx notation

dst (String or Raw) [in/out]

The output of the operation. May be a filespec in AMOS or native format (replacing an existing file or creating a new one), or a string (S) or unformatted (X) variable. If a dynamic variable is used (S,0 or X,0) it must be pre-sized to at least the required size. See cflags.

encoding (String) [in]

Specifies a type of character encoding to perform on the dst after the main cryptographic operation, from the same table of encoding choices listed above for the decoding parameter.

cflags (Num) [in]

Specifies zero or more options from the following:

Symbol | value | Description
CRYPF_NONE | &h0000 | placeholder for no flags (i.e. all defaults)
CRYPF_SRCFILE | &h0001 | src is a filespec (rather than the variable containing the source data)
CRYPF_SRCTEXT | &h0002 | src data (after decoding) contains text (as opposed to binary data)
CRYPF_DSTFILE | &h0008 | dst is a filespec (rather than a variable to receive the output)
CRYPF_DSTTEXT | &h0010 | dst (prior to encoding) will be a text string (as opposed to binary data)
CRYPF_KEYFILE | &h0020 | key is a file, rather than the variable containing the key. Applies to CRYPTO_CIPHER_RSA only
CRYPF_KEYHEX | &h0040 | key is hex encoded (decode before using)
CRYPF_PUBKEY | &h0200 | For RSA encryption/decryption, use the public key (otherwise the private key)
CRYPF_BIGENDIAN | &h0400 | Use big-endian (openssl) byte order rather than the default little-endian (Microsoft) order
CRYPF_IVHEX | &h0800 | IV is hex-encoded, else binary.
Definition File: CRYPTO.DEF

cipher (Num) [in]

For encryption/decryption, cryptographic algorithm to use.

cipher | value | Description
CRYPTO_CIPHER_NA | 0 | none / not applicable
CRYPTO_CIPHER_RSA | 1 | RSA (public/private key)
CRYPTO_CIPHER_AES | 2 | Advanced Encryption Standard (aka Rjindael) symmetric block cipher
Definition File: CRYPTO.DEF

key (String or Raw) [in]

Key to use for encryption/decryption. For the RSA cipher, must be a file in PEM format containing the public and/or private key. For the other ciphers, it may be the key itself, or the name of the file containing the key. As a convenience the key may be specified in hex-encoded format (see cflags). Note that the key size must correspond with the keybits parameter.

keybits (Num) [in]

Number of bits in the encryption key. Not required for the RSA cipher, since it can be determined from the PEM file. For AES, the options are 128, 192, or 256 bits. This corresponds 16, 24, or 32 bytes (or twice that if the key is hex-encoded).

mode (Num) [in]

For AES cipher, the cipher mode:

Cipher | Value | Description
CRYPTO_MODE_ECB | 1 | Electronic CookBook
CRYPTO_MODE_CBC | 2 | Cipher Block Chaining (block)
CRYPTO_MODE_RFC4716 | 3 |
CRYPTO_MODE_CTR | 4 | Counter Mode (stream)
CRYPTO_MODE_CFB | 5 | Cipher Feedback (stream)
CRYPTO_MODE_OFB | 6 | Output Feedback (stream)
CRYPTO_MODE_GCM | 7 | Galois/Counter Mode (stream)
Definition File: CRYPTO.DEF

padding (Num) [in]

For the AES cipher, the padding scheme to use:

Cipher | Value | Description
CRYPTO_PAD_NA | -1 | Padding not applicable; use with stream cipher modes CTR, CFB, OFG, GCM.
CRYPTO_PAD_PKCS5 | 0 | Each padding byte equal to the number of padding bytes. If message length an even multiple of the block size, an extra block of padding is added.
CRYPTO_PAD_FIPS81 | 1 | Last byte of padding indicates the number of bytes (including itself). Remaining padding bytes are random.
CRYPTO_PAD_RAND | 2 | Padding bytes are random. Decrypter must know the length of the message (i.e. the number of padding bytes)
CRYPTO_PAD_NULL | 3 | Padding bytes set to null. If message length is a multiple of the block size, no padding is used.
CRYPTO_PAD_SPACE | 4 | Padding bytes set to space. If message length is a multiple of the block size, no padding is used.
CRYPTO_PAD_SPACE | 5 | Padding bytes set to space. If message length is a multiple of the block size, no padding is used.
CRYPTO_PAD_SPACE | 6 | Padding bytes set to space. If message length is a multiple of the block size, no padding is used.
CRYPTO_PAD_SPACE | 74 | Padding bytes set to space. If message length is a multiple of the block size, no padding is used.
Definition File: CRYPTO.DEF

Note that the stream cipher modes (CTR,CFB,OFB,GCM) do not require or use padding and thus ignore the padding parameter; the use of CRYPT_PAD_NA is recommended for clarity. Without padding, the encrypted text is the same size as the plain text, assuming the same encoding. The block cipher modes (ECB and CBC) do require one of the other padding options, all of which will increase the encrypted text size up to a multiple of the block size (i.e. a multiple of 16).

cbsrc (Num) [in]

Number of data bytes in the src parameter. Only required when the src is not a file and contains binary data. (If not specified in this case, the raw parameter size will be used.)

iv (String or Raw) [in]

Initialization vector for optional use with CRYPTOP_ENCRYPT/DECRYPT opcodes with the AES cipher (all cipher modes except ECB). For cipher modes other than GCM or ECB, it should match the cipher block size, i.e. 16 bytes for AES (128 bits, not to be confused with the key size). For GCM cipher mode, 96 bits or less is recommended for best efficiency and interoperability. In all cases, it should be unique for any given key, preferably randomly generated. For GCM, it is only necessary that each IV not be used more than once. The same iv used for the encryption must be supplied to the decryption. The iv may be specified as raw bytes (preferably using an X format variable), or as a string of hex digits (in which case the CRYPF_IVHEX flag must be specified.)

aad (String, null terminated) [in]

Additional authentication data for use with the new GCM cipher mode (see below). Must be in the format of a string of hex digits. This is typically used to provide an identifying label or other association for the encrypted text, with the intent of making sure that the decrypted text is not just valid, but valid for a particular context/use. A corresponding authentication tag is generated (by combining the aad with the message and hashing and encrypting it) and output to the authtag parameter. The aad does not have to be kept secret, but both it and the corresponding authtag must be provided to the decryption routine in order to authenticate the result. The aad parameter can be null, but a unique authtag will still be generated and must be passed (along with the null aad) to the decryption.

authtag (String, 33+ bytes) [in/out]

Required for AES-GCM encryption/decryption. During encryption, an authentication tag is generated from the combination of the aad and the message text and output to this parameter in the form of a string of 32 hex digits. This computed value must then be passed along with the origional aad to the decryption.

Comments

AES is a symmetric block cipher, meaning that the same key is used for both encryption and decryption, and that the process works one block at a time. The block length for AES is 128 bits (16 bytes). This is independent of the key length, which can be 128, 192, or 256 bits. Several different cipher modes are available, which divide into the block modes (ECB and CBC), which pad the text to a multiple of the block size, and stream modes (CTR, CFB, OFB, and GCM) which do not use padding and thus generate encrypted text the same size as the plain text.

ECB mode is relatively weak, using the same key on every block, and thus is normally only used for very short messages for which a different random key is generated for each message. The other modes are suitable for any size message. CBC increases the security by deriving a new key for each block from the output of the encryption of the previous block. An initialization vector (IV) is typically supplied for use with the first block. In most cases it is essential that the IV be unique for each message, especially if the same key is used for multiple messages.

CTR, CFB, OFB and GCM are all variations of CBC, except that they are stream oriented (not requiring padding to a multiple of the block size). GCM also combines additional authentication data (AAD) with the message (to identify or label the message, i.e. supply metadata for it). An 128 bit authentication tag is generated for the combination of the AAD and the message, and is used along with the AAD to authenticate the decryption (i.e. make sure the decrypted data is not just internally valid, but valid in the context of the specified metadata).

The RSA public/private cipher is asymmetric (different keys used for encryption and decryption). It is extremely useful in situations where a private party (holding the private key) is exchanging messages with the public (which can share the public key). However, it is limited to messages no longer than the key modulus, which is typically 1024 or 2048 bits (128 or 256 bytes), so it is typically used for messages that are naturally short, such as AES keys and message digests.

See Also

• DIGEST.SBR

• HTTP.SBR

• MX_PWCRYPT

• CRYPTO.DEF in SOSLIB:[907,16]

History

2016 December, A-Shell 6.3.1539: Major upgrade of routine. Added parameters iv, aad, authtag; added five cipher modes (cmode) to use with AES algorithm; added support for Linux; updated ashinc:cipher.def. Note that CRYPTO as now documented above requires ASHNET.DLL 1.9.156+ (Windows) or libashnet.so.1.9.156 (Linux).

2014 May, A-Shell 6.1.1385: Added opcode 6, CRYPTOP_GENPUBKEY.

2013 July, A-Shell 6.1.1355: Routine added to A-Shell. Note that it requires ASHNET.DLL 1.5.137 or higher.

Subtopics

Public/Private Key

CRYPTO Examples


Public/Private Key

CRYPTO's opcode CRYPTOP_GENPUBKEY is used to generate a public/private key file pair. Its syntax differs slightly from the other opcodes:

xcall CRYPTO, CRYPTOP_GENPUBKEY, status, pubkeyfile, decoding, privkeyfile, encoding, cflags, cipher, passphrase, keybits, cmode

Parameters

status

Returns the result status of the operation: >= 0 for success (number of bytes output to dst), <0 for errors (see CRYPTERR_xxx in CRYPTO.DEF)

pubkeyfile and privkeyfile (in place of the src and dst parameters for other opcodes)

must be set to the filespecs for the generated public and private key files.

decoding and encoding

should be ""; there are no options for this opcode.

cflags

should be set to CRYPF_NONE, since output is always to file

cipher

should be set to either CRYPTO_CIPHER_RSA or CRYPTO_CIPHER_DSA

passphrase (in place of the key parameter for other opcodes)

must be set to the passphrase to encrypt the private key file or "" for none.

keybits

must be a multiple of 64, between 384 and 4096.

cmode

determines the format of the public key file:

• CRYPTO_MODE_OPENSSH (0) OpenSSH format

• CRYPTO_MODE_RFC4716 (3) RFC 4716 format

Comments

For Linux login authentication, the most typical options would be:

cipher = CRYPTO_CIPHER_RSA

keybits = 2048

cmode = CRYPTO_MODE_OPENSSH


CRYPTO Examples

Example 1: Symmetric key generation

Here we generate two 128 bit keys, returning the first one in a hex string format, and writing the other in raw binary format to a file. Note in both cases we are using the dst parameter (and not the key parameter) for the returned key. The src, decoding, cipher, and key parameters aren't used. Also note that although hex format for binary keys is convenient for string handling and printing purposes, handling it directly in an X variable would be the most compact (and would also eliminate the possibility of it being accidentally exposed in an xcall trace).

++include ashinc:crypto.def

map1 keybits,b,2,128 ! 128 bit key length

map1 hexkey$,s,32 ! 128 bits = 16 bytes (32 hex chars)

map1 status,f ! return status

! return hex key directly in hexkey$ (dst) param:

xcall CRYPTO, CRYPTOP_GENKEY, status, "", "", hexkey$, "hex", &

CRYPF_NONE, CRYPTO_CIPHER_NA,"", keybits

if status = 32 then ! (expecting 32 hex characters)

print "key (in hex format):";hexkey$

else

print "Error: ";status

endif

! now generate another, writing it in binary format to file

xcall CRYPTO, CRYPTOP_GENKEY, status, "", "", "testkey.bin", "", &

CRYPF_DSTFILE, CRYPTO_CIPHER_NA, "", keybits

if status = 16 then ! (expecting 16 bytes)

print "key written to testkey.bin"

else

print "Error: ";status

endif

Note: CRYPTOP_GENKEY provides the same functionality as the openssl rand utility. In fact, the second example (above) is directly equivalent to:

openssl rand 16 > test.key

Example 2: Encrypt/decrypt a string using AES-128-ECB

Here we generate a new random key (in raw binary format) and use it to encrypt a string, which is then encoded in base64. (This is a typical approach to encrypting sensitive fields within an XML web service request.) Error checking has been removed to simplify the example.

++include ashinc:crypto.def

map1 keybits,b,2,128 ! 128 bit key

map1 symkey,x,16 ! raw symmetric key (128 bits = 16 bytes)

map1 src$,s,50 ! plain text string to encrypt

map1 enc$,s,90 ! encrypted/encoded output

map1 dec$,s,50 ! decrypted string (to test decryption)

map1 status,f ! return status

! generate key into key var

xcall CRYPTO, CRYPTOP_GENKEY, status, "", "", symkey, "", &

CRYPF_NONE, CRYPTO_CIPHER_NA,"", keybits

! now use it to encrypt the src$

src$ = "This is a secret"

xcall CRYPTO, CRYPTOP_ENCRYPT, status, src$, "", enc$, "base64", &

CRYPF_SRCTEXT, CRYPTO_CIPHER_AES,symkey, keybits, CRYPTO_MODE_ECB, CRYPTO_PAD_PKCS5

print "status=";status;" cipher text = ";enc$

! now decrypt it to see if we get the original back

! (we'll use out of the encryption as the input of the decryption)

xcall CRYPTO, CRYPTOP_DECRYPT, status, enc$, "base64", dec$, "", &

CRYPF_SRCTEXT, CRYPTO_CIPHER_AES, symkey, keybits, CRYPTO_MODE_ECB, CRYPTO_PAD_PKCS5

if dec$ = src$ then

print "Success: decrypted string matches original!"

else

print "Error: decrypted string doesn't match original!"

endif

Note that the dst parameter here must be large enough to hold the encrypted/encoded message. For block ciphers like AES, the raw encrypted message length will be rounded up to the next multiple of the block (key) size, so for a 50 byte source, the encrypted version could be 64 bytes long. The base64 encoding will increase it further by a ratio of 4/3 (rounded up to next multiple of 4), so we would need 88 bytes to be safe. You can use a dynamic string output variable, but you must pre-initialize it to at least the minimum required size (if in doubt, err on the high side!).

Example 3: Encrypt/decrypt a file using AES-128-ECB

This is similar to Example 2 except that we'll use files for the source and destination, and a hex string variable for the key. This will be equivalent to the following openssl command strin1g:

"openssl enc -aes-128-ecb -in msg.dat -out msg.enc -a -e -nosalt -K " + hexkey$

++include ashinc:crypto.def

map1 keybits,b,2,128 ! 128 bit key

map1 hexkey$,s,32 ! hex encoded key

map1 status,f ! return status

map1 src$,s,50 ! source filespec

map1 dst$,s,50 ! dest filespec

map1 decoding$,s,10 ! source file decoding

map1 encoding$,s,10 ! dest file encoding

map1 cflags,b,4

! generate 128 bit key in hex format

xcall CRYPTO, CRYPTOP_GENKEY, status, "", "", hexkey$, "hex", CRYPF_NONE, CRYPTO_CIPHER_NA,"", keybits

src$ = "msg.dat"

decoding$ = "" ! no decoding of source (treat as raw)

dst$ = "msg.enc"

encoding$ = "base64" ! encode the dest after encryption

cflags = CRYPF_KEYHEX ! key is in hex format

cflags = cflags or CRYPF_SRCFILE ! source is a file

cflags = cflags or CRYPF_DSTFILE ! destination is a file

? "encrypting ";src$;" into ";dst$;" ..."

xcall CRYPTO, CRYPTOP_ENCRYPT, status, src$, decoding$, dst$, encoding$, &

cflags, CRYPTO_CIPHER_AES, hexkey$, keybits, CRYPTO_MODE_ECB, CRYPTO_PAD_PKCS5

if status >= 0 then

print status;" bytes output to ";dst$

else

print "error: ";status

end

endif

! now decrypt it into msg.dec (which should match the original msg.dat)

src$ = "msg.enc" ! source for decryption is the encrypted file

decoding$ = "base64" ! pre-decode encrypted file before decryption

dst$ = "msg.dec" ! decrypted file

encoding$ = "" ! no post-decryption encoding

? "decrypting ";src$;" into ";dst$; " ..."

xcall CRYPTO, CRYPTOP_DECRYPT, status, src$, decoding$, dst$, encoding$, &

cflags, CRYPTO_CIPHER_AES, hexkey$, keybits, CRYPTO_MODE_ECB, CRYPTO_PAD_PKCS5

if status >= 0 then

print "Decrypted file (";dst$;") should now match original"

else

print "error: ";status

endif

Note that in this case, it isn't necessary to specify whether the files contain text or binary data. (Treating it as binary is always safe.) Also note that for the decryption, the decoding option must match the encoding for the encryption. (We base64-encoded the encrypted file; so we need to first base64-decode it before decrypting.)

Example 4: RSA encrypt/decrypt a string

Here we RSA-encrypt the 16 byte raw symmetric key (generated in Example 2), using a public key stored in the file testpub.pem. This is similar to the openssl rsautl command sequence:

echo $KEY | openssl rsautl -encrypt -inkey tetpub.pem -pubin | openssl enc -base64

Note that the source for this operation may itself be a key (e.g. the symmetric key used to encrypt something else that we want to transmit secretly to the remote side), but from the perspective of the RSA encryption operation, it's just an arbitrary message to encrypt. This technique would apply to RSA public/private key encryption of any message, provided it is no longer than the RSA modulus (typically either 1024 or 2048 bits, i.e. 128/256 bytes).

++include ashinc:crypto.def

map1 symkey,x,16 ! raw 128 bit symmetric key (generated in Example 2)

map1 symkey2,x,16 ! (to test decryption)

map1 status,f ! return status

map1 dst$,s,346 ! dest string

map1 keyfile$,s,30 ! PEM file (public or private key)

map1 cflags,b,4

cflags = CRYPF_KEYFILE ! key is a file (cryptopub.pem)

cflags = cflags or CRYPF_PUBKEY ! use the public key

keyfile$ = "testpub.pem" ! public key file

if lookup(keyfile$)= 0 then

print keyfile$;" not found! See doc notes to create"

end

endif

xcall CRYPTO, CRYPTOP_ENCRYPT, status, symkey, "", dst$, "base64", &

cflags, CRYPTO_CIPHER_RSA, keyfile$

if status >= 0

print "Encryption success: ";status;" encrypted/encoded bytes output"

else

print "Encryption error: status=";status

end

endif

! now decrypt it into rawkey2 (which should match the original msg.dat)

! (this would normally be done by the remote counterpart)

cflags = cflags and not CRYPF_PUBKEY ! clear PUB flag (we're using private key here)

keyfile$ = "test.pem" ! private key file

xcall CRYPTO, CRYPTOP_DECRYPT, status, dst$, "base64", symkey2, "", &

cflags, CRYPTO_CIPHER_RSA, keyfile$

if status >= 0 and symkey = symkey2 then

print "Decryption success: decrypted symkey matches the original"

else

print "Decryption error: status=";status

endif

Notes:

• The size of the encrypted output for RSA encryption is always the same as the RSA modulus (1024 or 2048 bits), adjusted for the encoding. In this case, since base64 encoding expands the message by 4/3, we need at least 256 * 4/3 bytes (rounded up to next multiple of 4) or 344 bytes to hold the output. We mapped dst$ as 346 here to allow for a trailing null and even size.

• The keybits parameter is not used with the RSA cipher

• You can generate the test.pem (private key) and testpub.pem (public key) files for this example using openssl as follows:

openssl genrsa -out test.pem 2048

openssl rsa -in test.pem -pubout > testpub.pem

Example 5: Encode/decode a file

Here we encode 16 bytes of binary data as a 32 byte hex string:

++include ashinc:crypto.def

map1 xdata

map2 xdata'bytes(16),b,1

map1 hexdata$,s,32 ! hex encoded key (from example 1)

map1 status,f ! return status

map1 x,f

for x = 1 to 16 ! generate 16 binary bytes

xdata'bytes(x) = x

next x

! encode it in hex

xcall CRYPTO, CRYPTOP_ENCODE, status, xdata, "", hexdata$, "hex", CRYPF_NONE

? "hex encoded bytes: ";hexdata$


DATES

Updated Novemnber 2014

xcall DATES, opcode, result, <params...>

DATES.SBR performs several different date utility functions and has several calling formats, as shown below.

Parameters

opcode (Num) [in]

specifies operation to perform:

Symbol | Value | Operation | Syntax
DTOP_CVTFMT | 1 | Convert one format (date1) to another (date2) | xcall DATES, 1, result, date1, date2
DTOP_DATEAFTER | 2 | Compute date (date2) which is a specified number of days (days) after date1 | xcall DATES, 2, result, date1, date2, days
DTOP_DAYSAFTER | 3 | Compute number of days date1 is after date2 | xcall DATES, 3, result, date1, date2, days
DTOP_YWD | 4 | Compute date2 based on year, week, day of week in X,6 or X,5 format of date1 | xcall DATES, 4, result, date1, date2
DTOP_YWMD | 5 | Compute date2 based on year, month, week and day of week in X,6 format of date1 | xcall DATES, 5, result, date1, date2
DTOP_EOM | 6 | Compute date2 as last day of month in date1 | xcall DATES, 6, result, date1, date2
DTOP_ODTIM | 7 | Output formatted date (similar to ODTIM) | xcall DATES, 7, result, testdate, time, flags, outbuf'or'chan
DTOP_IDTIM | 8 | Input formatted date (similar to IDTIM) | xcall DATES, 8, result, inputstr, flags, outdate, outtime
DTOP_RANGE | 9 | Return out'of'range (F) <>0 if testdate is not between lodate and hidate (inclusive) | xcall DATES, 9, result, testdate, lodate, hidate, out'of'range
Definition file: ashell.def

result (Num) [out]

returns a code indicating if the operation was successful or what kind of error occurred:

Value | Meaning
0 | OK
1 | Function number out of range (1-9)
2 | Error in conversion of input date
3 | Invalid format for date
4 | Improper number/type of parameters
5 | Invalid format for days
6 | Error locating file channel (opcode 7)

days (signed Num) [out]

for DTOP_DAYSAFTER, returns number of days date2 is after date1

out'of'range (Num) [out]

for DTOP_RANGE, returns zero if testdate is within range defined by lodate and hidate (inclusive); else non-zero.

date1, date2, testdate, lodate, hidate

used for input and output, depending on the operation, with the format based on the way they are mapped:

MAP1 ADATE,S,8 ! MM/DD/YY format

MAP1 BDATE,S,10 ! MM/DD/CCYY format

MAP1 XDATE ! Separated format (3 to 7 bytes)

MAP2 MONTH,B,1

MAP2 DAY,B,1

MAP2 YEAR,B,1

MAP2 DOW,B,1 ! 1=Monday...7=Sunday (optional)

MAP2 YWEEK,B,1 ! Week of year (1-52) (optional)

MAP2 MWEEK,B,1 ! Week of month (1-5) (optional)

MAP2 MDAYS,B,1 ! Days in month (1-31) (optional)

MAP1 IDATE,B,4 ! Internal true Julian

MAP1 BDATE,B,3 ! Std AMOS date (same as 3 byte XDATE

MAP1 CDATE,B,2 ! Century Julian (days since 1/1/1900)

MAP1 JDATE,B,2 ! Yearly Julian (days since start of yr)

MAP1 FDATE,F,6 ! Special case (0=today on input)

Value | Meaning
>=0 | # of bytes processed; should match bytes
-1 | bad data type for srcdata
-2 | bad digtype
-3 | bad digest type or size
-4 | file not found

Notes

• DATES considers a 4 byte binary date to be in internal Julian format, rather than in the standard AMOS system date format (which is actually a separated date format). A common mistake is to pass DATES a date in B4 format which was returned from the system DATE function or IDTIM.SBR, leading to massive confusion, especially when using the range testing operation (9).

• the miame.ini parameter SBR=CCYY:## is used to determine the century cutoff on input dates in MM/DD/YY format. For more details, see the SBR command in the miame.ini configuration file.

Counting Weeks

DATES.SBR counts the days of each week from Monday=1 to Sunday=7. (That may be a little strange, since most calendars show Sunday as the first day of the week instead of the last. But DATES.SBR is a port of some existing AMOS routine, so it was A-Shell's task to preserve the existing behavior, not to justify it.)

The weeks are counted like rows in a calendar, again taking into account that our calendar weeks start with Monday and end with Sunday. So for 2011, the first week had only 2 days: Saturday and Sunday. Jan 3 was the start of the 2nd week.

If you want to convert to a more standard calendar arrangement, where each week starts with Sunday and ends with Saturday, then just add +1 to Mon-Sat and for Sunday, set it back to 1 and add +1 to the week.

On the other hand, if you want to say that each week of the year, including the first one, has seven days, then the week is simply the "yearly Julian" (DATES option 6) divided by seven, truncating the fractional remainder and then addding one (so the first week is one rather than zero). Under that scheme, Mar 15 is the 74th day; 74/7 = 10.57; truncate to 10 and then add 1 to get the 11th week (which it is).


DIGEST

Added May 2013

xcall DIGEST, digtype, srcdata, bytes, digest, status

DIGEST.SBR returns various cryptographic digests of strings or files.

Parameters

digtype (Num) [in]

indicates the type of digest desired:

Value | Type | Digest Length in Bits
3 | MD5 | 128
4 | SHA 1 | 160
5 | SHA 256 | 256

Note that the digtype values start at 3 rather than 1 to avoid possible conflict/confusion with the very similar HASH.SBR. See comments below.

srcdata (String or Raw) [in]

data to get the digest of. If bytes=-1, then this is interpreted as the filespec (AMOS or native) containing the data.

bytes (Num) [in]

number of bytes to process. If srcdata is type S, bytes may be set to 0 to mean the logical string length. If -1, srcdata is interpreted as the name of the file to process.

digest (String or Raw) [out]

returned digest. If X, the digest is returned in raw binary form. If S, it is returned in hex representation. Minimum sizes depend on the digtype:

Value | Type
MD5 | X,16 or S,32
SHA-1 | X,20 or S,40
SHA-256 | X,32 or S,64

status (Signed Num) [out]

returns status indicator:

Value | Meaning
>=0 | # of bytes processed; should match bytes
-1 | bad data type for srcdata
-2 | bad digtype
-3 | bad digest type or size
-4 | file not found

Comments

DIGEST.SBR and HASH.SBR are very similar and may eventually be merged, although at present only DIGEST supports the file option. HASH is more oriented towards maximum performance with relatively small keys, as might be useful in a hash table alternative to a traditional index. DIGEST is more oriented towards security applications and large keys (or files) where computational performance and compactness are less important than minimizing the possibility of different keys having the same digest.

See Also

• CRYPTO.SBR

• See EXLIB program DIGEST.BP for example of usage.

• MIAMEX 25: Get file hash total

History

2013 May, A-Shell 6.1.1353: Routine added to A-Shell


DSKCOM

Updated June 2012

xcall DSKCOM, opcode, msgnam, var

DSKCOM.SBR is identical to COMMON.SBR except that it is disk-based, allowing sharing of information between different jobs. Also, the package name (msgnam) may be up to twelve characters instead of the standard six. This allows you plenty of space to prepend the jobname if you want to identify which packets go with which jobs.

The file is OPR:COMMON.SYS, and will be automatically created on first access if it does not exist. You can erase it to forcefully reset any existing packets.

The number and size of packets is determined in the same way as for COMMON.SBR, i.e. via the SBR=MSGNUM:#,MSGSIZ:# parameters in the miame.ini. The default is six packets of 150 bytes.

You may ALIAS=COMMON:DSKCOM if you want to convert your existing COMMON to disk based.

History

2012 June, A-Shell 6.0.1251: Add new opcode 3 for destructive read. Opcode 1 remains for non-destructive read. Note that unlike COMMON.SBR, DSKCOM does not recognize the SBR=COMMONNDR switch.

2006 December, A-Shell 4.9.985: Added to A-Shell


DSKPPN

(1) xcall DSKPPN, disk, ppn

(2) xcall DSKPPN, a$, ppn2

DSKPPN.SBR retrieves either the disk and PPN, or just the PPN. In the second format, it mimics a custom subroutine used by some people under AMOS, called GETLOG.SBR. In that case, use ALIAS=GETLOG:DSKPPN.

Parameters

Parameter | Type | Comment
disk | S,6 | e.g. "DSK01"
ppn | S,7 | e.g. "7,13"
ppn2 | S,10 | e.g. "[7,13]"
a$ | S,1 | dummy parameter


DSTOI

xcall DSTOI, xdate

DSTOI.SBR converts a separated date (which is the format returned by the DATE system function in BASIC) into a Julian date which starts with 1/1/1900. You can use ODTIM or DATES to convert the Julian date back to various separated and printable formats.

Parameters

MAP1 Xdate

MAP2 Mon,B,1 ! Month 1-12

MAP2 Day,B,1 ! Day 1-31

MAP2 Yr,B,1 ! Year-1900

MAP2 Dow,B,1 ! Day of week (0=Mon, 6=Sun)

MAP1 Jdate,B,4,@Xdate ! # days since 1/1/1900

Example

Xdate = DATE ! load Xdate with separated date

xcall DSTOI, Xdate ! convert Xdate from separated to Julian

print "Julian date is:";Jdate


DYNLIB

Added January 2017

To load/unload an external library:

xcall DYNLIB, dlctl {,lib, convention, stackspace}

To call a function in the external library:

xcall DYNLIB, dlctl, funcsig {,parms...}

(Windows and Linux only) DYNLIB.SBR provides a mechanism for A-ShellBASIC programs to dynamically access routines in external libraries written in C (or compiled to a C compatible object format), without the need for any special compile-time linking or modifications to A-Shell to support the external library. The fundamental difficulty here is the fact that third-party libraries may have many different calling conventions, and there is almost no limit to the variety of return types and parameter lists for the functions involved. DYNLIB deals with this variability by supporting a wide variety of the most common library calling conventions, and a flexible scheme for specifying function signatures so that the function arguments can be properly passed and converted.

Parameters

dlctl (ST_DYNLIBCTL) [in/out]

This is a structure containing various control parameters used and/or updated for every call. It is defined in ashinc:dynlib.def as:

defstruct ST_DYNLIBCTL

map2 handle,DLHANDLE ! handle to the external module

map2 opcode,b,4 ! see DCOP_xxx

map2 flags,b,4 ! flags (see DLF_xxx)

map2 status,i,4 ! see (DYNLIBE_xxx)

map2 syserr,i,4 ! system error set by called fun, e.g. GetLastError() for Windows; else errno

map2 lastfunc$,s,64 ! function signature of last called function

endstruct

lib (String) [in]

Used only for the load routine (opcode DCOP_LOAD), lib specifies the name of the external library. For Windows, this is just the DLL name (no path or extension needed, provided the DLL is in the standard search path, or in the A-Shell bin directory). For Linux, it will be a name like "libxl.so.1" which references a shared library in the system library path (typically /usr/lib). By convention, typically file in the /usr/lib directory is actually a symbolic link to the actual library file.

convention (Num) [in]

Used only for the load routine to specify the calling convention for the external library. See the DLCC_xxx codes defined in ashinc:dynlib.def for the possibilities. Note that the most common options are DLCC_C_X86_WIN32_STD for Windows DLLs, and DLCC_C_X86_CDECL for Linux.

stackspace (Num) [in]

Used only for the load routine to specify the amount of stack space to reserve for the library. 4 to 8K is typically plenty.

funcsig (String) [in]

This string is used in conjunction with a call to a library function (opcode DCOP_CALL) to declare the function name, return type, and expected parameter list. The format is:

funcname(pppp....)r

where:

• funcname is the name of the function to call in the external library

• each p is a one letter code indicating the type of parameter from the table below

• r indicates the return type of the function, from the table below

Code | Description | Code | Description
A | const char* (convert ANSI to UTF8) | L | unsigned long long, uint64_t (?)
a | char * (convert ANSI to UTF8) | f | float (f4)
B | _Bool, bool (i,2) or i,4? | d | double (f8)
c | char (s,1) | p | void* (any output vars probably need to use this)
C | unsigned char (s,1) | Z | const char * (s,0)
s | short (i,2) | z | char * (s,0)
S | unsigned short (b,2) | W | const wchar_t * (s)
i | int (i,4) | w | wchar_t * (s)
I | unsigned int (b,4) | U | const wchar * (from UTF8 string)
j | long (i,4) | u | char * (from UTF8 string)
J | unsigned long (b,4) | v | void
l | long long, int64_t (?) |  |

Examples

C Function Prototype | funcsig
void f1(); | ”f1()v”
int f2(int, int); | ”f2(ii)i”
long long f3(void*); | ”f3(p)L”
void f3(int**); | ”f3(p)v”
double f4(int, bool, char, double, const char*); | ”f4(iBcdZ)d”

Following the function signature, the remaining parameters are the arguments being passed, followed by the parameter to receive the return value of the function.

Comments

See the libxl.bsi module in EXLIB:[908,68] for examples.

Because this is a bit tricky, if you have an external library you would like to interface with, you may want to consult with MicroSabio to help you evaluate it and get it started.

History

2017 January, A-Shell 6.3.1542: automatic conversion from ANSI to/from UTF8 now supported via the "A" (read only) and "a" (read/write) codes. This is used in the Linux version of the LIBXL API to handle accented and other special Latin1 characters.

2015 November, A-Shell 6.3.1500: Routine added to A-Shell. Initially for internal use only in conjunction with LibXL, later to be documented and made available to programmers. Documentation posted January 2017.


ECHO

xcall ECHO {,channel}

ECHO.SBR is used to turn terminal echo back on after disabling it with the NOECHO subroutine. It may also be used to return a serial port under UNIX to its normal settings. See the descriptions of GET and NOECHO.


EFS

Rewritten July 2016

xcall EFS, 0, status

xcall EFS, 1, status, key {,append}

xcall EFS, 2, status, fspec, isencrypted

xcall EFS, 3, status, ispec {,ospec}

xcall EFS, 4, status, ispec {,ospec}

xcall EFS, 5, status, key

xcall EFS, 6, buildno

xcall EFS, 7, enable'logging

xcall EFS, 14 , flags

xcall EFS, 15, flags

(Linux only) The A-Shell Encrypted File System (EFS) supports AES encryption of files at the I/O layer below that used by A-Shell/BASIC programs. There are various ways to specify which files are to be encrypted, such as in the miame.ini by category or extension, and explicitly by an XCALL. But once encrypted, provided the decryption key has been registered, normal A-Shell/BASIC file I/O operations will automatically decrypt and re-encrypt the data on the fly as needed. Although A-Shell provides various cryptographic routines which operate on strings or individual files, if you have a lot of files to encrypt, EFS provides a more encompassing, more secure, and easier-to-implement solution.

Parameters

opcode (Num) [in]

Operation to perform, per following table

Value | Function
0 | Check if EFS is supported
1 | Set key
2 | Check if file is encrypted
3 | Encrypt file
4 | Decrypt file
5 | Check key
6 | Check efslib build
7 | Enable/disable logging
14 | Set A-Shell/EFS flags
15 | Get A-Shell/EFS flags

status (Num) [out]

Status return code, per following table

Value | Meaning
0 | Available, licensed, okay
-1 | Available, not licensed
-2 | Not available
-3 | Opcode not supported
-4 | Parameter error
>0 | Errno

key (x,32) [in]

specifies encryption key, mapped as:

MAP1 KEY,X,32

MAP2 KEY$,S,32,@KEY

By specifying the unformatted key parameter, it will not show up in the trace log even if TRACE=XCALL is set. Furthermore, if your key is less than 32 bytes long, the remaining key bytes will be supplied from a default internal ashell key. By taking advantage of this feature, even if your part of the key was exposed and a copy of the file stolen, the culprit would still need a licensed copy of A-Shell to decrypt it.

append (Num) [in]

if specified and non-zero, specified key is appended to the default internal A-Shell key

fspec (String) [in]

filespec in native or A-Shell notation

ispec (String) [in]

input filespec in native or A-Shell notation

ospec (String) [in]

output filespec in native or A-Shell notation

isencrypted (Num) [out]

returns non-zero if file encrypted, else non-zero

buildno (Num) [out]

returns the EFS build # (version #), which will be an integer in the range of 1-9999

flags (Num) [in/out]

EFS system option flags, from following table:

ASH_EFS_CLEAR_KEY_ON_EXIT &h0001 Clear EFS key on exit to dot prompt; set by default

enable'logging (Num) [in]

Specify 0 to disable logging, 1 to enable it

Comments

When the EFS license option in enabled, A-Shell will automatically detect when a random, ISAM, ISAM-A or sequential file has been encrypted and thus there is no need to specifically identify to A-Shell which files are encrypted, except when you create a new file. In that case, for RANDOM files created with ALLOCATE, use xcall ASFLAG,AF_CRYPTE prior to the allocate to set the encryption flag. As with other ASFLAG values, the setting only lasts until the end of the current program. For ISAM-A, you can use the ISMUTL /E switch, which requires ISMUTL.LIT 1.3(128) or higher. For old ISAM, you can first use ISMBLD, then use xcall EFS,3,STS,ISPEC to encrypt the DAT and/or IDX file(s).

For encrypting sequential output files, you can either set the OPTIONS=EFS_OUT_AMOS or EFS_OUT_HOST option in the miame.ini, or the corresponding GOP2_EFS_OUT_xxx flags via MX_SETOPTIONS.

You can also request that particular file extensions be automatically encrypted when created via the EFSEXT option in the miame.ini.

DIR.LIT will display an "E" next to any encrypted files.

Because EFS is so powerful, and because the stakes are high, developers considering EFS are urged to carefully review the capabilities and configuration options before implementation. You don't want to go to a lot of trouble to lock all the windows but leave the front door open, and you don't want to lock yourself out of the house! We cannot help you recover a lost encryption key!!!

Also See

• EFSEXT in miame.ini

• OPTIONS in miame.ini

• MX_GETOPTIONS, MX_SETOPTIONS

• TRACE=EFS in miame.ini

• MX_GETTRACE, MX_SETTRACE

History

2014 March, A-Shell 6.1.1379: When ashell enters the interactive dot prompt state, it now (by default) clears the encryption key. This way, if a program should unexpectedly abort and drop to the dot prompt, it will not leave the user with access to encrypted files. You can override this behavior by using one or both of the new opcodes 14 or 15. Currently the only defined flag is:

&h0001 (AEFS_CLR_KEY_ON_EXIT) ! clear encryption key on exit to dot prompt

The AEFS_CLR_KEY_ON_EXIT flag is set by default. To disable the option (returning to the prior behavior), use xcall EFS, 14, 0 to clear the flag.

2004 May, A-Shell 4.9.889: EFS.SBR added to A-Shell.


EMAILP

command = sbx:EMAILP {,flags, subject, intro}

(Windows only) EMAILP.SBX is a print filter subroutine intended only for use in a COMMAND statement within a printer init file. It launches your local email client and embeds the specified printfile into the body of the message, allowing the user to then address and complete the sending process.

Note that since the way this subroutine can be called is from within a printer init file, the parameters must be specified as literals. (There are no "variables" within printer init files.) Remember to enclose strings in quotes if they contain embedded commas.

Parameters

flags

may optionally be specified as the sum of one or more of the following values:

Value | Meaning
1 | Receipt requested
2 | Send file as attachment instead of embedded within message. (Not yet implemented; consult source code EMAILP.BAS for update notes.)
4 | Use HTML coding to set fixed pitch (when embedding)

subject (String)

a literal string containing the desired subject of the email message.

intro (String)

contains the text that will be inserted at the top of the message.


EMAILX

xcall EMAILX, opflags, cfgfile, to, header, body, status {,from, attachments, signature, errmsg, socket, server, host, username, password}

EMAILX.SBX is an external subroutine which allows an A-Shell Basic program to send email. See the following sections for more information.

Note that EMAILX is not included in the normal A-Shell distribution package; details in EMAILX Adminicetera.

Subtopics

EMAILX Parameters

EMAILX Config File

EMAILX Header Specifications

EMAILX Scenarios

EMAILX Adminicetera


EMAILX Parameters

Parameter | I/O | Description
opflags | in | Operation flags
cfgfile | in | Name of configuration file
to | in | Address of recipient(s)
header | in | Header fields
body | in | Text of message
status | out | Return code
from | in | Email address of sender
attachments | in | Attachments
signature | in | AMOS or native filespec to be appended to bottom of message body. Like body, signature can also contain the actual text rather than a filename. See note below.
errmsg | out | If present, will receive a (possibly) useful text string if STATUS # 0 (elaborating on the error condition.).
socket | in/out | Ignored on input unless you use opflags to avoid opening and closing the SMTP session for each message; in which case it receives the socket # of the session on the open call and must be passed to all the subsequent calls. Note that you must manually close the socket if you use the EMF_LEAVEOPEN option.
server | in | Name or IP address of the SMTP server. (append :<port> if not using port 25). See note below.
host | in | Name to identify your domain to the SMTP server in the initial protocol exchange with the SMTP server. See note below.
username | in | Overrides the username field in the configuration file to specify the user name needed to authenticate with the SMTP server. If username and password are both specified (and not blank) and no AUTH mode was specified, AUTH = AUTO is used automatically.
password | in | Overrides the password field in the configuration file to specify the password needed to authenticate with the SMTP server. If username and password are both specified (and not blank) and no AUTH mode was specified, AUTH = AUTO is used automatically. Note that the password may be specified in encrypted form (provided it was encrypted with MX_PWCRYPT).

Note that if values for signature, server and host are not specified explicitly, the values for those parameters will be taken from the configuration file. If no host is provided, we use nothing, which may lead to your mail being rejected, or possibly sent with a warning that it comes from an unidentified source.


opflags

opflags (Num) specifies various operation flags, using the sum of one or more of the following:

Symbol | Value | Type | Description
EMF_NORMAL | 0 | B,2 | normal operation
EMF_LEAVEOPEN | 1 | B,2 | don't close session
EMF_ALREADYOPEN | 2 | B,2 | don't open; (already open)
EMF_OPENONLY | 4 | B,2 | open only; ignore all but SERVER & HOST
EMF_CLOSEONLY | 8 | B,2 | close only
EMF_HDRCAT | 16 | B,2 | concatenate HEADER+BODY (no CRLF)
EMF_HTMLBODY | 32 | B,2 | BODY contains <HTML>
EMF_MIMEBODY | 64 |  | BODY is a self-contained MIME part
EMF_TLS | 1024 |  | Use SSL/TLS for SMTP connection
EMF_STARTTLS | 2048 |  | Use STARTTLS (start with unencrypted connection, then elevate to TLS with the STARTTLS SMTP command)
Definition file: EMAILX.DEF

Note that in most cases you can get by with EMF_NORMAL. The next four flags (EMF_LEAVEOPEN, EMF_ALREADYOPEN, EMF_OPENONLY, and EMF_CLOSEONLY) are only of interest if you are sending a lot of emails in a batch and want to eliminate the overhead of having to open and close the connection with the SMTP server for each message. EMF_HDRCAT is only used when you want to include email header items in both the header and body parameters. And EMF_HTMLBODY is only recommended when you have used your own HTML formatting within the body of your message.


cfgfile

cfgfile (String, may be null) specifies the filename (AMOS or native) of a configuration file containing additional parameters of the type that are thought likely to vary by installation but otherwise remain fixed for that installation. See the subsequent section describing the configuration file in more detail. Note that all of the parameters after status are optional on the XCALL, but only to the extent that the corresponding parameter is defined in the configuration file. Alternatively, you can omit the configuration file entirely, in which case you must specify all of the parameters on the XCALL line.


to

to (String) specifies the email address(es) of recipient(s), each using standard unadorned email address format. (e.g. jack@microsabio.com). If you are specifying multiple addresses, separate them with chr(13) characters. (Up to 100 addresses allowed.)

Note that if you plan to use the CC: or BCC: header items to send copies of the message to other people, those people must be listed here in the to parameter. (This parameter is strictly used by the SMTP server for routing and does not (usually) show in the recipient’s message header.)


header

header (String) specifies zero or more header fields, separated by CRLF (i.e. chr(13)+chr(10)) and each conforming to the formatting rules in the appropriate RFC’s (such as RFC 822 and RFC 1521). EMAILX does not check your header items for validity. Note that you may decide to skip this parameter and put all of your header items in the body of the message (see body). Or you can put some here and some in the body parameter (provided you then specify the EMF_HDRCAT flag in opflags.) Here are some sample header lines:

To : "George Washington" <gw@cherrytree.com>

From : "Paul Revere" <prevere@patriots.net>

Subject : The Redcoats are Coming

Reply-To: <admin@federalists.org>

cc : <tj@montebello.net>

Although headers are technically part of the body of the message as far as the SMTP server is concerned, there is a core set of headers that SMTP servers, and especially email readers understand, plus an extended set that most understand, plus a specification for how to define your own headers. See the section on EMAILX Header Specifications for more details.

The Internet email (and most other) standards are documented in a series of "RFC’s" (Request For Comments) which fortunately are very accessible via the Internet; just search for "RFC 822."


body

body (String) specifies the body of the message, either directly by including the entire body in the variable (with each line terminated by a CRLF), or indirectly (by giving the name of a file which contains the body of the message.) If you are specifying a filename (either AMOS or native) rather than the body itself, this parameter must contain a string less than 128 characters long with no carriage returns. Otherwise, the parameter will be treated as the literal body of the message. Note that if the header parameter was not blank, and the EMF_HDRCAT flag was not specified, then a blank line will be automatically inserted into the message to separate the header from the body. (This is part of the standard mail format rules, but is so likely to be overlooked by Basic programmers that we do it automatically here.)

If you include HTML formatting within the body of the message, you should specify the EMF_BODYHTML flag in the OPFLAGS parameter. Most modern email readers are smart enough to figure it out for themselves, but some older ones may fail to recognize HTML formatting without a "Content-Type: text/html" header, which EMAILX will add for you if you specify the flag.


status

status (F,6) provides the return code. 0=success, else error. Negative numbers represent system or network errors (such as unable to connect, no route to host, etc.). The string associated with the error will be returned in errmsg (or output to the specified file.) Positive numbers>100 are the actual codes returned by the SMTP server (with the remainder of the message returned in errmsg.) Positive numbers between 71 and 99 are application or misc errors. The more common status values are defined in EMAILX.DEF (++include in your application) as shown below:

Symbol | Value | Type | Description
EMS'OK | 0 | B,1 | Ok
EMS'TOOFEW | 71 | B,1 | Too few parameters
EMS'TIMEOUT | 72 | B,1 | Timed out
EMS'NOTO | 73 | B,1 | No to address
EMS'NOBODY | 74 | B,1 | No body text
EMS'BADRESP | 75 | B,1 | Bad SMTP response
EMS'NOSOCKET | 76 | B,1 | No socket open
EMS'NOCFG | 77 | B,1 | Specified CFG file not present
EMS'BADCFG | 78 | B,1 | Syntax error within CFGFILE
EMS'BADSIG | 79 | B,1 | Bad signature file
EMS'BADATT | 80 | B,1 | Bad attachment
EMS'B64ERR | 81 | B,1 | Base64 encoding error
Definition file: EMAILX.DEF

Values 1-70 would indicate Basic error conditions. Consult SYS:ERRMSG.USA or use DERR.SBR to get the text message associated with the error number.

Negative values represent system network errors. To get the error message associated with a negative value of STATUS, use XCALL TCPX, TCPOP_ERRMSG, STATUS, MESSAGE$, TCPFLAGS (where TCPFLAGS must contain TCPXFLG_TLS if either of the EMF_TLS or EMF_STARTTLS bits are set in OPFLAGS). Also see the ERRMSG parameter, which may contain a useful message, typically the last command sent to the server or last response from it.

Values in the range of 200-599 are SMTP reply codes. (The SMTP protocol consists of a series of command/requests, each of which receives a response beginning with one of these reply codes. When the code indicates a failure, EMAILX will abort and return that code in the status parameter.) You can get a more complete picture of the conversation between EMAILX and the SMTP server by examining the log file (see the LOGFILE and LOGLVL parameters in the configuration file). For a complete understanding of the theory and interpretation of the SMTP protocol, including the reply codes, consult the relevant RFCs, particularly RFC 5321. The log file may also show additional enhanced "status codes", typically presented in the form of x.x.x, which may provide more information about the nature of the problem. A simple web search for "SMTP reply codes" or "SMTP status codes" will help you locate a variety of websites with simplified lists of the codes (the RFC is thorough and academic, but not conducive to a quick look-up), as well as forum/support/blogs discussing typical SMTP problems. Because these issues are generally specific to the particular SMTP server or network, EMAILX can do little more than report the information returned from the SMTP server, and this documentation can do little more than provide this general advice before sending you off to the web for more troubleshooting.


from

from (String, optional) specifies the email address of the sender. This is optional because it is likely to be the same for the entire application and thus can be specified in the configuration file (via the RTNADDR parameter), but if specified here, it will override the configuration file. Note that this is the address that will receive messages from the SMTP server itself about problems delivering the mail.


attachments

attachments is a formatted parameter which may specify any number of attachments:

MAP1 ATTACHMENTS

MAP2 ATT’COUNT,B,2 ! # of attachments

MAP2 ATTX(n) ! n >= value of ATT’COUNT

MAP3 ATT’FILE,S,128 ! attachment filespec

MAP3 ATT’CONTENT’TYPE,S,127 ! content’type string

MAP3 ATT’ENCODING,B,1 ! See CTE’xx in EMAILX.DEF

If you are not using attachments, you can specify the attachments parameter as a null string (mapped or literal) for simplicity.

The size of the ATTX() array (n as shown above) is up to you, but must be at least as large as ATT’COUNT, which in turn must equal the number of items in the array (i.e. attachments) which are to be used. The maximum is currently 10 (i.e. up to 10 attachments allowed.)

The ATT’FILE() items must contain the name of the file to be attached in either AMOS or native format.

ATT’CONTENT’TYPE() is optional; if non-blank, it should be a legal MIME Content-Type header, for example:

Content-Type: application/octet-stream; name="xyz.doc"

You may omit the "Content-Type:" preface to the string, since if not present, it will automatically be added. You can also omit the name= field, in which case the name will be set to the actual name of the attachment (stripped of its directory.) If the entire string is blank, EMAILX will build one using "application/octet-stream" as the type.

ATT’ENCODING() indicates the MIME Content-Transfer-Encoding to be used. The default (0) is base64, which should work for all attachments because it delivers an exact copy of the attached file. The only downside is that the encoding increases the size of the mail message by about 34%.

Note that EMAILX will automatically perform the Base64 encoding for you; you just supply the name of the file.

The encoding types are defined as:

Symbol | Value | Type | Description
CTE'BASE64 | 0 | B,1 | Base64 (default)
CTE'7BIT | 1 | B,1 | 7 bit unencoded text
CTE'8BIT | 2 | B,1 | 8 bit unencoded text
CTE'BINARY | 3 | B,1 | Binary unencoded data
CTE'QUOTED | 4 | B,1 | Quoted Printable encoding
CTE_ATT'ON'GW | 128 |  | Attachment fspec is on gateway machine
Definition file: EMAILX.DEF

CTE’7BIT, CTE’8BIT, and CTE’BINARY are all similar in that they indicate that no encoding has been done to the attachment. Of these, the first two should only be used with text consisting of reasonably short delimited lines. CTE’BINARY indicates that the data is truly raw, possibly not fitting into the line length requirements of SMTP. Both CTE’8BIT and CTE’BINARY require that all of the MTA’s (Mail Transfer Agents) can handle 8 bit data, which is not necessarily guaranteed. (This is why CTE’BASE64 is preferred, since it encodes anything using a 7 bit character set.)

Also note that most mail readers will display 7bit text/plain attachments as if they were simply part of the message body rather than clearly separating them as attachments.

CTE’QUOTED indicates that the attachment is already in "quoted printable" format. This is a format that consists mostly of plain text, with an escape mechanism use to encode special characters. The advantage of this over Base64 is primarily that it is still somewhat readable even if the mail reader doesn’t understand the encoding. (Base64, on the other hand, is not human-readable at all.) However, by now, virtually all mail readers support Base 64, so we have not bothered to implement quoted printable encoding, other than to allow you to do your own encoding and then indicate that it has been done.

It is worth repeating that if you want to use quoted printable (CTE’QUOTED) encoding, you must do it yourself. EMAILX will only supply the proper header for you.

Refer to RFC 1521 for more details on attachments and MIME headers.


EMAILX Config File

The EMAILX configuration file is designed to contain those parameters which are most likely to be user-definable yet constant for a given site or application. The file is normally called EMAILX.CFG, although you specify the name (and location; there is no search path) yourself in the EMAILX statement. The file is a typical text configuration file, and it uses this syntax:

<parameter name> = <value> ; <optional comment>

Note that the config file paramters are case INsensitive.

Parameters

Parameter | Description
AUTH | SMTP authentication.
DOMAIN | DOMAIN is a strictly optional parameter which specifies the domain to be added to any unqualified address, thus allowing you to abbreviate the addresses, say, for your local company by dropping the @ and everything after it. For example, if DOMAIN=microsabio.com, then if you specify the address "admin" in the to or from fields, it will automatically be expanded to "admin@microsabio.com".
HOST | HOST fulfills the same purpose here as it does in the XCALL parameter list, and is used only if HOST is blank or not specified in the XCALL. This is typically your domain name, and is used to identify your computer or domain to the SMTP server when making the initial connection. Theoretically, the SMTP server may decide to accept or reject you based on whether it recognizes or can resolve this domain name.
LOGFILE | Log file name
LOGLVL | Log level
PASSWORD | Password.
REPLYTO | REPLYTO is an important parameter often confused with the return address. This is where mail will be sent if the reader clicks the "Reply" button in their email client. It may or may not be the same as the address of the person (or cyber-entity) that actually sent the message. If specified, it inserts a line in the message header reading "Reply-To: " followed by the specified address.
RTNADDR | Return address
SECUREHELLO | Enable/Disable secure EHLO message
SECURE | Type of secure connection.
SERVER | SMTP server name
SIGNATURE | Signature file
USERNAME | USERNAME fulfills the same purpose here as it does in the XCALL parameter list, and is used only if the AUTH parameter is specified, and the USERNAME is blank or not specified in the XCALL.
WAIT | Maximum wait for SMTP response

Sample

;EMAILX.SBX configuration file

WAIT = 10 ; max wait (secs) for SMTP response

SERVER = localhost ; SMTP server

SECURE = STARTTLS ; use STARTTLS protocol

AUTH = * ; SMTP auth mode (LOGIN or PLAIN)

USERNAME = yo@micasa.com ; SMTP login username

PASSWORD = secret ; SMTP login password

HOST = microsabio.com ; HELO (sending domain)

DOMAIN = microsabio.com ; default domain to add to unqualified addrs

RTNADDR = ashell@microsabio.com ; return address (default FROM address)

REPLYTO = replyto@microsabio.com ; default Reply-To address

SIGNATURE = EMAILX.SIG ; signature file (text, amos or native spec)

LOGFILE = EMAILX.LOG ; log file name (amos or native)

LOGLVL = 3 ;


WAIT

WAIT specifies the maximum number of seconds we will wait for a response from the SMTP server before aborting and returning STATUS = EMS’TIMEOUT. If not specified, default is 30 seconds. Note that if you are using a dial-on-demand connection to your SMTP server, 30 seconds may not be long enough. On the other hand, if your SMTP server is on the local LAN, it is probably unnecessarily long (although the only harm there is that the user may get tired of waiting for the timeout, particularly during initial testing when the connection parameters may need tweaking.)


SERVER

SERVER fulfills the same purpose here as the SERVER parameter on the XCALL line and is used only if SERVER is blank or not specified. Since a given installation will probably always use the same server, it may be much more convenient to put the information here in the configuration file than having to embed it in the application. Note that although SMTP servers almost always use port 25, if for some reason yours doesn’t, you can append the port number to the host name or IP address with a colon separating them. For example:

SERVER = localhost:10025 ; local SMTP server on port 10025

SERVER = 1.2.3.4:9925 ; SMTP server at 1.2.3.4 port 9925

SERVER = mail.myisp.net ; SMTP server at ISP


SECURE

SECURE may optionally be used to specify the type of secure connection to establish with the SMTP server. The options are TLS (establish an SSL/TLS encrypted connection immediately, typically at port 465), STARTTLS (start with an unencrypted connection and then upgrade to TLS using the STARTTLS SMTP command), or NONE (unencrypted connection). If SECURE is not specified, the option defaults to NONE. Note that changing the SECURE option typically requires changing the port (see server above).

See Also

• SECUREHELLO

• EMAILX Adminicetera (for related requirements)


AUTH

AUTH is used to specify SMTP authentication. As of edit 116, EMAILX supports two authentication methods: AUTH=PLAIN and AUTH=LOGIN. You may also specify AUTH=* (or AUTH=AUTO) to have EMAILX query the SMTP server to see which methods it supports, and to then use AUTH=LOGIN or AUTH=PLAIN according to which is supported. If both are supported, it uses AUTH=LOGIN. You can omit AUTH entirely if your SMTP server does not require authentication. (Many SMTP servers distinguish authorized clients by their IP address and thus don't require authentication via username and password.) If you specify AUTH, then you must specify USERNAME and PASSWORD either in the configuration file or in the parameter calling list.

Note that SMTP servers will normally list their supported AUTH options in response to the EHLO message, e.g.

> EHLO microsabio.com

< 250-smtp.abc.xyz.com Hello

250-PIPELINING

250-ENHANCEDSTATUSCODES

250-AUTH LOGIN

etc.

You can see this in the Log file for Loglvl 4 or higher.

In the above case, the server is announcing that it supports just the AUTH LOGIN variation. Some servers, however, will not indicate which AUTH methods it supports until after a secure channel is negotiated, followed by a re-sending of the EHLO command. So the first list might omit the AUTH line, or show it with no options. Then, after the second EHLO, it will report another another list of supported options, similar to the above, but perhaps with variations or additions, corresponding to secure mode.

See Also

• SECUREHELLO


PASSWORD

PASSWORD fulfills the same purpose here as it does in the XCALL parameter list, and is used only if the auth parameter is specified, and PASSWORD is blank or not specified in the XCALL. As of EMAILX.SBR 5.1(122), you may supply the password text in encrypted form (using MX_PWCRYPT to encrypt it). When the encrypted password contains control characters which are not conveniently represented in a text editor, you may also supply the password as a comma delimited series of decimal values representing the ASCII characters, e.g.

PASSWORD = 2, 33,124, 1, 98, 13, 127, 52, 44


RTNADDR

RTNADDR is another optional parameter which specifies the default from address. Most email clients have a similarly named field in their setup parameters which saves you from having to type the "From" address on every message. (In the case of EMAILX, you aren’t likely to be "typing" any addresses, so the point may be moot.) Note that you can always supply this information directly in the message header (either in header or body) by including a line consisting of "From:" followed by your email address. Note that you can use the extended addressing syntax here (optionally including a text name followed by the real email address in angle brackets, e.g. "Administration <admin@microsabio.com>". You can of course skip this parameter and include it directly within the header and/or body parameters.


SIGNATURE

SIGNATURE is equivalent to the XCALL parameter of the same name, and is used only if the XCALL parameter is blank or not present. The theory behind putting it here is that you may wish to include the same "signature" text on every message, yet every installation will surely have their own (typically listing important contact information for the company), so why bother having to reference it explicitly on every email. Note that there is nothing magical about the "signature" – it is just text (possibly "styled text") which could just as easily be included with the body parameter or not at all.


LOGFILE

LOGFILE is an optional string specifying the name of a log file to which EMAILX will output (possibly) useful tracing and/or debugging information. The amount, or degree of detail, is determined by the next parameter (loglvl). Beware that if you send a lot of mail, and especially if you opt for a high degree of detail, this file can rapidly grow quite large. The expectation is that installations might temporarily use it for debugging problems with the SMTP server (for which it is extremely useful) and otherwise turn the feature off or set it to errors only. As with all of the other parameters which specify filenames, you can use AMOS or native syntax here.


LOGLVL

LOGLVL specifies the degree of detail to be written to the log file per the following table. It is ignored if LOGFILE is blank or not present, and it defaults to 1 (Errors only) if LOGLVL is not specified. The options are perhaps not completely self-explanatory, but the best way to understand them is just to experiment with a few sample messages and different settings. Typically you would just leave this set to 1 and check it periodically for error messages. Note that in the debug modes (4 and 5) the log file provides a rather graphic tutorial on how the SMTP protocol works, since it documents both the commands sent to the server and the responses received.

Value | Result
0 | Off
1 | Errors only
2 | Info summary (to, from, number of bytes)
3 | Full message (to, from header, body)
4 | Partial debug (most commands and responses)
5 | Full debug (everything)


SECUREHELLO

The STARTTLS protocol suggests that the EHLO (aka "Hello") message be re-sent after the secure channel has been negotiated, in which case the server should completely ignore anything it learned in the first (unencrypted) EHLO message. However, most servers do not actually require it, and prior to 5.1(124), EMAILX did not send it. Starting with 5.1(124), EMAILX automatically re-sends the EHLO via the secure channel, unless the SECUREHELLO option is specified in the config file as 0, N, or F (i.e. zero, no, or false). That would be necessary only if the server was unable to handle the re-send EHLO.


EMAILX Header Specifications

The specification for header fields is spelled out (in excruciating detail) in RFC 822, which any decent search engine can take you right to. However, if you are not interested in that level of detail, here are is a mercifully (but not very) brief overview.

The first thing to note is that from the standpoint of the STMP protocol, headers are actually part of the body or "data" of the message, and thus is it quite possible that an SMTP server would accept virtually anything, including nothing, in the way of headers at the start of your message. However, that is not to say that SMTP servers do not typically parse and possibly interpret your headers and add their own, nor that email readers do not depend on certain minimum standards for message headers.

Format wise, the main syntactic requirement is that the header section of the message consist of one or more lines with header keywords (e.g. To, From, Date, etc) followed by optional whitespace, followed by a colon, followed by more optional whitespace, followed by some kind of text, which may have further syntactic requirements depending on the header keyword.

For example, the To: field must contain validly formatted email addresses. If the data following the colon is too long to fit on one line, you may continue it by inserting a CRLF followed by at least one whitespace character followed by the continuation of your field. The whitespace at the start of the continuation line is essential to mark it as a continuation of the prior header field and not a new header field.

Header keywords (e.g. To, From, Subject, etc.) are not case sensitive. However, in order to slightly reduce the confusion between similarly named header keywords (e.g. To, From) and EMAILX parameters (e.g. TO, FROM) we will from here on reference the former using upper and lower case, followed by a colon (.e.g. To:) and the latter using upper case (e.g. TO). We highlight both in bold to make them stand out as keywords from the surrounding text.)

The end of the headers and the start of the body of the message is marked by a blank line (two CRLF’s in a row.) This may explain the need for the EMF_HDRCAT flag in opflags; it helps EMAILX decide if it should insert a blank line between your header parameter and your body parameter.

As a bare minimum, every message should have Date:, To:, and From: header fields. The normal—and universally recognized—header fields are shown in the following table.

It is also possible to have User Defined Header Fields, which see for more information.

Header | Description
Date | The SMTP server will automatically insert the Date: header field for you, so there is no need to manually include one.
To |
From |
Subject | A free format line describing the message. This is so common that most email readers have a space dedicated to it.
cc | A list of names this message is being copied to. To reiterate a critical point in the discussion above about the difference between the To: header and the to parameter, the cc: header field is just for aesthetics. If you want to actually send the message to the people listed, you must include them in the to parameter.
Bcc | A list of people this message is being blindly copied to. The comment above for the cc: field applies here as well, except that in practice, virtually all SMTP servers and/or email readers will interpret this field and hide the information from some or all of the recipients of the message.
Reply-To | Address to send replies to. Virtually all email readers will interpret this field and use it if you select the "reply" option within the email program.
Sender | Address of the person sending the message, as distinct from the composer of the message. For example, a secretary’s email address.
Comment | A free-format comment which is not technically part of the message body. For example, you might use this to include some explanatory remarks when a message is being forwarded, or when the message is being sent by someone other than the actual originator of the message. It might be considered analogous to a post-it note stuck to a typewritten letter.
In-Reply-To | An indication of what (and/or who) this message is in reply to.


To

The To: header field should not be confused with the to parameter. The former is used mainly by the email reader application to format the message, whereas the latter is a critical parameter given directly to the SMTP server prior to the message. The SMTP server only wants an unadorned address for routing purposes, whereas the email reader may appreciate a fancier one, possibly including a text name in addition to the actual address. The actual to parameter is typically not visible to the reader at all, whereas the To: header field is possibly the first thing he or she sees. An important ramification of this dichotomy between the to parameter and the To: header field is that if you want to send your message to multiple people, you must specify them all in the to parameter, but you do not have to (and may not want to) do so in the To: header field. (You might want to use the cc: or bcc: header fields instead, or not at all.). To see an example of this, just look at the headers generated by any mass-mailed message (or junk mail message.) Typically, the actual To: header line will have nothing to do with you, and your email address will not appear anywhere in the header at all.

Taking the example of traditional postal mail for comparison, the to parameter is analogous to the address on the outside of the envelope, whereas the To: header field is analogous to the heading or salutation at the top of the letter inside the envelope. Similarly, if you want to copy your letter to multiple people, you have the option of including a cc: header in your letter, but the only way the message will actually be delivered multiple recipients is if you use multiple envelopes (i.e. multiple to addresses.)


From

The From: header field differs from the from parameter in nearly the same way as the To: header differs from the to parameter. The from parameter is a separate command to the SMTP server, and is used to identify the sender to the SMTP server, not necessarily to the recipient of the message. Typically, however, they are the same, with the possible addition of an informal text version of the sender’s name in the From: header (e.g. "Big Brother <bigbro@us.gov>" instead of just bgpro@us.gov"). SMTP servers will often insist that the from parameter specify a valid address (since it needs this if it has to return the message because it was undeliverable.) They may or may not put restrictions on the From: header, but apparently this is not too common or we would not be deluged with junk-email with no usable From: address. Note that since your From: header is likely to be the same for all messages, you may want to put it in the configuration file and not bother with it in each message.


User Defined Header Fields

If you want to define your own header fields, the specification requires that you start them with "X-" to avoid any possible confusion with previously defined or other header fields that may be recognized and interpreted by the SMTP server or mail reader. The most common example of this is the field X-Mailer: which most email clients now add to identify the name of the software or server used to generate the message. For example, here are two commonly seen X-Mailer: headers:

X-Mailer: Microsoft Outlook Express 5.00.2314.1300

X-Mailer: QUALCOMM Windows Eudora Version 5.0

EMAILX adds its own X-Mailer header indicating its version number.


EMAILX Scenarios

Even though EMAILX goes a long way towards simplifying the process of sending email from an application, the need for flexibility combined with the underlying complexity of the email format rules make for a lot of confusion. To help clear away some of that confusion, we discuss a few "scenarios" here in more detail.

Subtopics

Scenario 1: Simple Plain Text Messages

Scenario 2: Simple HTML Text Messages

Scenario 3: Messages with Attachments


Scenario 1: Simple Plain Text Messages

This case does not require much elaboration. Just put your message either entirely in the body parameter (either as a text string with CRLF between each line, or as a file) or put the header items in the header parameter and the rest of the message in the body parameter. The signature is optional, and if present is treated logically just like a continuation of the message body. No special flags are needed in opflags. Here is an extremely simple example which does not even use on a configuration file:

MAP1 EMAIL’PARAMS

MAP2 EM’TO,S,200

MAP2 EM’FROM,S,50

MAP2 EM’HEADER,S,1000

MAP2 EM’BODY,S,2000

MAP2 EM’SERVER,S,20,"mail.king.net"

MAP2 EM’HOST,S,20,"looseheads.net"

MAP2 EM’ERRMSG,S,100

MAP2 CRLF$,S,2

MAP2 EM’STATUS,F

EM’TO = "louisxvi@versailles.gov" + chr(13) + "robespierre@reignofterror.org"

EM’FROM = "marie@foodnet.org"

CRLF$ = chr(13) + chr(10)

EM’HEADER = "To: Louis" + CRLF$ + "From: Marie" + CRLF$ &

+ "Subject: cake recipes"

EM’BODY = "Dear Louis," + CRLF$ &

+ "What is this ‘cake’ I keep hearing so much about?" &

+ CRLF$ + "Je t’aime, Marie"

XCALL EMAILX,0,"",EM’TO,EM’HEADER,EM’BODY,EM’STATUS,EM’FROM,"","",EM’ERRMSG,SOCKET,SERVER,HOST

IF EM’STATUS # 0 then print "Error #";EM’STATUS;" – ";EM’ERRMSG


Scenario 2: Simple HTML Text Messages

This case is identical to the plain text case above, except that you can include HTML markup commands in your text to give it "style". Most modern email readers understand HTML commands, even if you don’t bother to indicate in the header that you are using them. (But to be correct, you should set the EMF_HTMLBODY flag in OPFLAGS.) If the email reader does not understand HTML, then the reader will see your markup commands as if they were part of the text. But fortunately due to the nature of HTML commands, the text is still likely to be "readable", although the extent may depend on how complicated you make your HTML.

Here is a slightly more complicated example using a configuration file and a file for the body of the message:

EMAILX.CFG ------------------------------------------------

;EMAILX.SBX configuration file

WAIT = 10 ; 10 sec wait for server

SERVER = localhost ; SMTP server on local host

HOST = sabionet.com ; our domain id

DOMAIN = microsabio.com ; default domain for addresses

RTNADDR = email@microsbio.com ; default ‘FROM’ addr

REPLYTO = replyto@microsabio.com ; reply-to addr

LOGFILE = EMAILX.LOG ; name of log file

LOGLVL = 2 ; info summary

BODY1.TXT -------------------------------------------------

<HTML>

<HEAD><TITLE>This is the title</TITLE></HEAD>

<BODY>

<H1>This is Header #1</H1>

<H2>This is Header #2</H2>

<P>This is paragraph #1.

As you can see the formatting is based

on

the

P and /P notations and not on the

actual line breaks</P>

<P>This is paragraph #2</P>

</BODY></HTML>

EMHTML.BAS ------------------------------------------------

MAP1 EMAIL’PARAMS

MAP2 EM’OPFLAGS,B,2

MAP2 EM’TO,S,200

MAP2 EM’CFGFILE,S,20,"EMAILX.CFG"

MAP2 EM’FROM,S,50

MAP2 EM’HEADER,S,1000

MAP2 EM’BODY,S,30

MAP2 EM’ERRMSG,S,100

MAP2 CRLF$,S,2

MAP2 EM’STATUS,F

++INCLUDE EMAILX.DEF ! contains needed symbols

EM’OPFLAGS = EMF_BODYHTML

EM’TO = "test@microsabio.com"

CRLF$ = chr(13) + chr(10)

EM’HEADER = "To: HTML Test Department" + CRLF$ + "From: Field Research" + CRLF$ + "Subject: Testing HTML formatted message"

EM’BODY = "BODY1.TXT"

XCALL EMAILX,EM’OPFLAGS,EM’CFGFILE,EM’TO,EM’HEADER,EM’BODY, EM’STATUS,EM’FROM,"","",EM’ERRMSG

IF EM’STATUS # 0 then print "Error #";EM’STATUS;" – ";EM’ERRMSG


Scenario 3: Messages with Attachments

Attachments require the construction of MIME headers and usually the encoding of the attachment using "base64". Most people do not want to know anything about how that is accomplished, and would prefer to imagine that it is as simple as just listing the names of the attached files in the header of the message (an illusion happily fostered by most email client applications.) Fortunately, EMAILX is willing to go along with this charade, allowing you to specify nothing other the names of the files you want to attach.

Most email clients make assumptions about the types of file attachments based either on the extension of the filename, or possibly by scanning the file to see if consists of anything other than text. Rather than get mired in such hocus-pocus, EMAILX adopts a simpler approach. If you don’t tell it otherwise, it automatically treats each attachment as being of type "application/octet-stream" which is the most general type. If you want to be more specific, you can specify one of the content types defined in the email standard (see RFC 1521 and 1522), such as:

application/postscript

image/jpeg+

image/gif

audio/basic

video/mpeg

The following example uses the same configuration file (EMAILX.CFG) as in the previous example, and is otherwise very similar except for the inclusion of two attachments and the addition of a signature block:

EMSIG.TXT ----------------------------------------------------------

************************************************************

*************** EMAIL Field Research and Testing ***********

************************************************************

EMATT.BAS ----------------------------------------------------------

MAP1 EMAIL’PARAMS

MAP2 EM’OPFLAGS,B,2

MAP2 EM’TO,S,200

MAP2 EM’CFGFILE,S,20,"EMAILX.CFG"

MAP2 EM’FROM,S,50

MAP2 EM’HEADER,S,1000

MAP2 EM’BODY,S,1000

MAP2 EM’ERRMSG,S,100

MAP2 CRLF$,S,2

MAP2 EM’STATUS,F

MAP1 EM’ATTACHMENTS

MAP2 ATT’COUNT,B,2

MAP2 ATTX(10)

MAP3 ATT’FILE,S,128

MAP3 ATT’CONTENT’TYPE,S,127

MAP3 ATT’ENCODING,B,1

++INCLUDE EMAILX.DEF

EM’OPFLAGS = EMF_NORMAL

EM’TO = "test@microsabio.com"

CRLF$ = chr(13) + chr(10)

EM’HEADER = "To: Attachment Test Department" + CRLF$ &

+ "From: Field Research" + CRLF$ + "Subject: Testing Attachments"

EM’BODY = "There are two attachments to this message:" + CRLF$ + " EMAILX.SBX (binary) and miame.ini (text)" + CRLF$

ATT’COUNT = 2

ATT’FILE(1) = "BAS:EMAILX.SBX"

ATT’CONTENT’TYPE(1) = "" ! (let it default)

ATT’ENCODING(1) = CTE’BASE64 ! (base64 encoding)

ATT’FILE(2) = "/vm/miame/miame.ini"

ATT’CONTENT’TYPE(2) = "text/plain"

ATT’ENCODING(2) = CTE’7BIT ! 7 bit text, no encoding

XCALL EMAILX,EM’OPFLAGS,EM’CFGFILE,EM’TO,EM’HEADER,EM’BODY, EM’STATUS,EM’FROM,EM’ATTACHMENTS,"EMSIG.TXT",EM’ERRMSG

IF EM’STATUS # 0 then print "Error #";EM’STATUS;" – ";EM’ERRMSG

Note that there was no particularly good reason to not use base64 encoding (CTE’BASE64) for the second attachment as well, other than to save a few bytes. In fact, one possible problem with text/plain encoding is that the line terminators will be converted to CRLF, even if they were originally just LF. Base64 encoding eliminates this possibility.


EMAILX Adminicetera

Requirements

The requirements for using EMAILX are as follows:

· The minimum supported version of A-Shell is 5.0. EMAILX may work with later versions of 4.9 but this is not guaranteed. If you must use A-Shell 4.9, stick with EMAILX.SBX edit 112 or prior. For SSL/TSL and STARTTLS, the minimum A-Shell version is 5.1.1180.

· You must have an SMTP server which is within "routing distance." That is, we need to be able to open a socket connection to your SMTP server. The SMTP server may be on the same machine as A-Shell, or on the local network, or at your ISP connected via a full-time or dial-up connection. Wherever it is, it must accept mail from you. Note that some SMTP servers may have filters to protect "unauthorized users".

· EMAILX supports just two methods of SMTP authentication, known as "AUTH PLAIN" and as "AUTH LOGIN". You can also use an SMTP server which does not require authentication at all.

· For secure connections (see SECURE), EMAILX requires the LIBASHTLS library to be installed along with the A-Shell executable. LIBASHTLS in turn requires the GNUTLS package. This is typically pre-installed or available via yum for Linux. For Windows, it is available as a set of DLLs; contact MicroSabio for assistance. LIBASHTLS is not currently available for AIX.

Licensing

EMAILX is not included in the general release of A-Shell and A-Shell-related software. It is, instead, an add-on option which is purchased and licensed separately. For additional information on pricing, licensing and purchasing, contact MicroSabio or see the A-Shell price list.

Like all external subroutines (SBXes), EMAILX is written in BASIC. Source code is included with the license.

History

Version | Date | Description
5.1.130 | Dec 2014 | Adjust MIME attachment headers problem. Existing header format wasn't working with certain SMTP servers.
5.1.129 | Dec 2014 | Fix glitch failing to detect auth method due to slight format variations between servers. Fix redundant EHLO with using TLS/SSL (but not STARTTLS) mode (most servers ignore the redundant EHLO but some were aborting on it.)
5.1128 | May 2014 | Support auto-decryption of mode 3 passwords introduced in 6.1.1385. When generating the password, use the SMTP user name as the seed.
5.1.127 | Oct 2013 | Add EMF_NOAUTOHDR to disable unnecessary headers; useful for SMS messages.
5.1.126 | June 2013 | Return message for EMS_BADCFG error in ERRMSG param.
5.1.125 | June 2013 | Add CONNLOCK=1 option to CFG file to lock connection. Also add enhancements to log file.
5.1.124 | July 2012 | Upgrade STARTTLS protocol to deal with some servers; disable with SECUREHELLO=0.
5.1.123 | April 2010 | Silence some spurious screen output during appending operations.
5.1.122 |  | Add the PASSWORD decryption option.
5.1.121 |  | Add SECURE configuration option for SSL/TLS and STARTTLS connections.


ERRMSG

(1) xcall ERRMSG {,errarg}

(2) xcall ERRMSG, msg$, errnum

MAP1 ERRARG

MAP2 ERR'ID,S,6 ! (this field is ignored)

MAP2 ERR'CDE,B,2 ! app-defined error #

MAP2 ERR'MSG,S,50 ! app-defined error message

ERRMSG.SBR is a handy way to handle BASIC error trap reporting. Add the subroutine to your BASIC error trap, and it can display a standardized message at the bottom of the screen (listing information about the error) and log the error to file, and/or retrieve the text associated with the current error. The routine must be set up as an alias to DERR in the miame.ini file as follows:

ALIAS=ERRMSG:DERR

DERR is a Debug plc routine which is similar to ERRMSG. It is not documented here since we prefer that you use ERRMSG, but if you are already using DERR, feel free to continue, but note that it expects four arguments, rather than the 0-2 that ERRMSG expects.)

If 0 or 1 argument is passed and a BASIC error has occurred, then ERRMSG ignores the errarg argument (if passed) and displays a three line message at the bottom of the screen relating to the BASIC error, which looks something like this:

* ERROR MESSAGE * TSKAAA Illegal record number

Error 31 in Line 360 of MYPROG Last File: 5 (ERRMSG.TMP)

Press ESC to Abort

You may also call the ERRMSG directly (i.e. absent any BASIC error) to report application-defined errors. In that case, you must include the errarg parameter, assigning your own values to the fields. For example, consider the following code:

125 ERR'CDE = 142

130 ERR'MSG = "Something bad has happened!"

135 xcall ERRMSG,ERRARG

This would display the following message (where "MYPROG" is the current program name):

* ERROR MESSAGE * TSKAAA Something bad has happened!

Error 142 in Line 135 of MYPROG

Press RETURN to Continue or Retry

In either of the above cases, the subroutine will also log a similar message to the text file BAS:BASERR.LOG.

If two arguments are passed (as in the second sample format above) then it simply retrieves the BASIC error message associated with the specified error number. This can be useful for creating your own error message display within an error trap, since when error trapping is enabled, BASIC no longer displays the error message. (It only supplies you with the error number, last line number, and last channel number, via the ERR(0), ERR(1), and ERR(2) functions.)

ERRMSG (i.e., DERR) uses a Windows-style message box if GUI support is available.


EZSPL

Following this introduction are sections on EZSPL Old Format, EZSPL New Format, and EZSPL Processing.

EZSPL.SBR is a very useful utility, which is fully compatible with and may be used in place of the AMOS SPOOL subroutine. In A-Shell, in fact, SPOOL is implemented as an alias to EZSPL. EZSPL provides three main functions:

• It incorporates a screen preview facility, enabling the user to browse through the document either before or instead of sending it to a printer. This feature has been fully implemented under A-Shell. In fact, the A-Shell version of the viewer (known as EZ-TYPE or, under its latest incarnation, EZ-VUE) supports many enhancements over the AMOS version.

• It optionally provides a front-end printer selection, enabling the user to select the printer and various print options (such as banner, header, etc.). Many of the switches are specific to the AMOS environment, and so there is a fair amount of divergence here between the AMOS and A-Shell versions, but the concepts are similar and the differences can be handled in the configuration files, external to the application source code.

• It optionally provides transparent character translation through what it terms port filters. These enable programs written to generate escape sequences for specific printers to have their codes transparently modified to the sequences required for other printers as the documents are output.

Port filters are not implemented under A-Shell, but the equivalent functionality is available using either the COMMAND=SBX:<routine name> option in the printer initialization file, or traditional UNIX filters in the UNIX environment.

In addition to the above features, EZSPL, like SPOOL, performs the mundane task of sending the specified file to the specified print queue. Two calling formats are available, each described in the following topics, followed by t*he a brief discussion of the EZ-SPOOL configuration file processing.

SPOOL.SBR is handled by using the ALIAS facility in the A-Shell configuration file to redirect it to EZSPL.SBR, which supports a superset of the normal SPOOL.SBR capabilities.

History

2013 October, A-Shell 6.1.1373: SPOOL (or EZSPL) refinement: Under UNIX, spooling a print file that is still open does not generate any error or warning, but the spooled output may be truncated if the last block written hadn't been flushed to disk. To avoid this intolerable result that can nonetheless go without notice for an indefinite period, A-Shell now detects if the print file is still open, and if so, flushes its buffer to disk so the spooled output will be complete. It also logs a warning message to the ashlog.log file. It does not, however, close the print file, since that might lead to an I/O-to-unopened error if the file was closed later. And although that might be a good thing, forcing the underlying bug to be fixed, it's seldom appreciated when a new error occurs in a "working" program after installing an A-Shell update. Note that the issue didn't affect Windows because in that environment, attempting to spool an open file would generate an error.


EZSPL Old Format

Updated May 2016; see History

xcall SPOOL, file {,printer, switches, copies, form, lpp, width, prefix, suffix, overlay, totpages}

Parameters

file (String)

is the specification of the file to print, and is the only required parameter.

printer (String)

is the name of the printer to send the file to. If not specified, the default defined by the PRINTER statement of the miame.ini file will be used. In most cases, the printer name should correspond to a printer initialization file with a matching name, either SYS:<printer>.INI or ASHCFG:<printer>.PQI. The exceptions to this rule are as follows.

Under Windows, you may specify the pseudo printer name "PROMPT", which is interpreted as a printer whose initialization file contains the following:

DEVICE = PROMPT:

PASSTHROUGH = OFF

PITCH = AUTO

If the name you specify is longer than 6 characters (which was the maximum for AMOS printer names and remains the maximum for A-Shell printers which have corresponding initialization files), then it is interpreted like the PROMPT example above, except with the DEVICE set to the name you specify. (This "implied printer" technique can be taken to its logical extreme by specifying a \\machine\sharename name for the printer, in which case there does not even need to be a local printer driver definition.)

Under UNIX, if you specify a printer name which has no corresponding initialization file, then it is treated as if the initialization file were simply:

DEVICE = <printer>

Refer to the printer configuration documentation for more information about printer initialization files.

switches (Num)

may be any combination of the following:

Symbol | Value | Equivalent PRINT.LIT switch
SPSW_BANNER | &h000001 | BANNER (applies only to UNIX, if at all)
SPSW_NOBANNER | &h000002 | NOBANNER
SPSW_DELETE | &h000004 | DELETE
SPSW_NODELETE | &h000008 | NODELETE
 | &h000010 | HEADER (ignored by A-Shell)
 | &h000020 | NOHEADER (ignored by A-Shell)
SPSW_FF | &h000040 | FF (formfeed after printing)
SPSW_NOFF | &h000080 | NOFF
SPSW_WAIT | &h000100 | WAIT; applies only to PDFX, see note 4 below
 | &h000400 | INFORM (ignored by A-Shell)
 | &h000800 | KILL (ignored by A-Shell)
SPSW_PASSTHROUGH | &h002000 | PASSTHROUGH (Windows only)
SPSW_NOPASSTHROUGH | &h004000 | NOPASSTHROUGH (Windows only
SPSW_LANDSCAPE | &h008000 | LANDSCAPE (Windows only); see Note 2 below
SPSW_PORTRAIT | &h010000 | NOLANDSCAPE (Windows only); see Note 2 below
SPSW_PREVIEW | &h080000 | Force Preview on; see Note 3 below
SPSW_NOPREVIEW | &h100000 | Force Preview off; see Note 3 below
SPSW_APEX | &h400000 | Force APEX Preview on; see Note 3 below
Definition file: ashell.def

Hex-Decimal Values

Notes on Switches:

1 Any switches specified this way will override the corresponding switches in the printer’s initialization file.

2 The LANDSCAPE and NOLANDSCAPE switches are equivalent to the printer init commands ORIENTATION=LANDSCAPE and ORIENTATION=PORTRAIT, respectively.

3 In the standard Windows GUI environment, the Force Preview On switch (&h080000) will use the GUI-mode APEX previewer rather than the EZVUE text-mode version. But in the case of a telnet connection to a server, the default is to preview the file using EZVUE on the server side, unless the Force APEX Preview switch is set. Set both switches to automatically use APEX whenever applicable, and to fall back to EZVUE otherwise.

4 The WAIT switch (see History) applies only to PDFX version 5 or higher. When set, the subroutine will wait until the PDFX driver has written the PDF file to disk before returning to the application. This is useful when you need to do something with the PDF file immediately after creating it. Note since it is not always possible to predict the final PDF filespec, particularly if the user is allowed access to the Save As dialog, the application may want to use MX_LASTPRTFIL to retrieve the filespec after return from SPOOL.

copies (Num)

is the number of copies to print (default 1).

form (String)

is the form name. Note that names are not generally used in the Windows or UNIX world and are thus ignored by A-Shell. To get the equivalent effect, you would probably define multiple logical printers associated with a single physical printer.

lpp (Num)

is the number of lines per page (ignored).

width (Num)

is the number of columns per page (ignored).

prefix (String)

specifies the name of a file to be prepended to the front of the printfile before sending it to the printer. This is useful for sending printer initialization codes or routing instructions.

suffix (String)

specifies the name of a file to be appended to the end of the printfile.

overlay (String)

specifies the name of an overlay file. This has the same affect as setting OVERLAY= in the printer init file, but any overlay specified in the XCALL statement will override an overlay in the printer init file.

totpages (Num)

This parameter, which works only in the Windows GDI printing environment, specifies the number of pages in the printout. If specified, any occurrence of "%#" in the printfile will be replaced with the total number of pages. For example, a string in the printfile of the form "Page 1 of %#" would be converted to "Page 1 of 100", assuming that the total pages had been set to 100. Obviously you could have done this directly in your application, but it is often difficult to know in advance how many pages you are going to generate, whereas it is easy to count them as you generate them and then pass the total to SPOOL/EZSPL.name of a file to be appended to the end of the printfile.

History

2016 April, A-Shell 6.3.1509: Re-define WAIT function to be PDFX-specific, add MX_LASTPRTFIL to A-Shell also.


EZSPL New Format

xcall EZSPL (or SPOOL), file, table

The table parameter layout is as follows. Fields marked with an asterisk are ignored by all A-Shell platforms.

MAP2 PRINTER,S,64 ! spooler name (was 6 under AMOS)

MAP2 CPU,F,6 !*CPU id

MAP2 SWITCHES,F,6 ! option switches

MAP2 COPIES,F,6 ! copies to spool

MAP2 BANNER,S,50 !*banner

MAP2 LPP,F,6 !*lines per page

MAP2 WIDTH,F,6 !*columns per page

MAP2 FORMS,S,6 ! printer form

MAP2 PRI,F,6 !*priority

MAP2 ADATE,B,4 !*spool after date

MAP2 ATIME,B,4 !*spool after time

MAP2 RESTART,F,6 !*restart

MAP2 START,F,6 !*start page

MAP2 FINISH,F,6 !*finish page

MAP2 LIMIT,F,6 !*limit form feeds

MAP2 OPTIONS,F,6 ! (EZ-SPOOL) options

MAP2 SEQNO,F,6 !*(EZ-SPOOL) sequence #

MAP2 COUNT,F,6 !*(EZ-SPOOL) # blocks queued

MAP2 ITCERR,F,6 !*(EZ-SPOOL) ITC error

MAP2 NONITC,F,6 !*(EZ-SPOOL) spooler

MAP2 FILERR,F,6 !*(EZ-SPOOL) file error code

MAP2 EXTOPT,F,6 ! (EZ-SPOOL) extended options

MAP2 PREFIX,S,28 ! (A-Shell) prefix file

MAP2 SUFFIX,S,28 ! (A-Shell) suffix file

MAP2 HOSTROWS,F,6 ! (A-Shell) number of rows reserved for host in EZTYP

MAP2 EZCOLORS ! User-defined color scheme

MAP3 EZFG'TXT,B,1 ! text colors

MAP3 EZBG'TXT,B,1 !

MAP3 EZFG'BDR,B,1 ! border colors

MAP3 EZBG'BDR,B,1 !

MAP3 EZFG'CMD,B,1 !

MAP3 EZBG'CMD,B,1 ! command colors

MAP3 EZFG'STS,B,1 !

MAP3 EZBG'STS,B,1 ! status colors

MAP3 EZFG'HLP,B,1 !

MAP3 EZBG'HLP,B,1 ! help colors

MAP3 EZFG'HLT,B,1 !

MAP3 EZBG'HLT,B,1 ! highlight colors

MAP3 EZFG'MNU,B,1 !

MAP3 EZBG'MNU,B,1 ! menu colors

MAP3 EZFG'BRF,B,1 !

MAP3 EZBG'BRF,B,1 ! brief colors

MAP2 OVERLAY,S,28 ! overlay file

MAP2 TOTPAGES,F,6 ! total pages

The fields marked (EZ-SPOOL) were not part of the original AMOS specification and were added by EZ-SPOOL (as developed for AMOS). The fields marked (A-Shell) are A-Shell extensions that were not part of either the original AMOS or EZ-SPOOL specifications. All of the fields for both types of extensions are optional under A-Shell.

The PRINTER field was 6 bytes under AMOS and up until 4.7(827) of A-Shell. We expanded at that point to allow for the possibility of using UNIX and especially Windows printer names (which can be quite long.) If you use the 64 byte version of the PRINTER field, then you MUST specify all of the other fields (even the ones which we just got through saying were optional.) A-Shell can only determine which version of PRINTER you used by considering the total size of the TABLE parameter.

The EZCOLORS fields, if specified, will override the normal default color scheme used by EZ-SPOOL. The only exceptions to this are that they will be ignored if they are ALL ZERO, and that that can be overridden themselves by the EZCLR section of the INI.CLR file. For information on the color configuration file format, see Color Configuration and MX_INICLR.

The OPTIONS parameter above may be set to any combination of the values in the following table. Values that are ignored by A-Shell have been omitted (which is why there are gaps).

Value | Meaning
&h0000001 | PRINTER selection menu on
&h0000002 | PRINTER selection menu off
&h0000004 | OPTION menu on (questions at bottom of PRINTER menu)
&h0000008 | OPTION menu off
&h0000010 | TYPE (preview) allowed (by selecting printer X)
&h0000020 | TYPE (preview) not allowed
&h0020000 | ASKPRT on (Prompt to confirm user wants to print the file)
&h0040000 | ASKPRT off
&h2000000 | BRIEF on (single line printer selection prompt)
&h8000000 | Preview file only (same as XCALL EZTYP)

Hex-Decimal Values

The EXTOPT parameter above may be set to any combination of the values in the following table. These may also be set via the EXTOPT=### parameter in the EZSPL configuration file. Values that are ignored by A-Shell have been omitted (which is why there are gaps).

Value | Meaning
&h0004 | Disable screen save/restore
&h0020 | Allow exit from EZVUE with LeftArrow
&h0040 | Allow exit from EZVUE with Tab
&h0080 | Allow exit from EZVUE with F1-F16
&h0100 | Do not ask questions on PRINT from within EZVUE
&h0200 | Hitting Home when already at the top of the file in EZVUE acts like the PRINT command.

Hex-Decimal Values

Notes

The PRINTER, SWITCHES, COPIES, FORMS, LPP, WIDTH, PREFIX, SUFFIX, OVERLAY, and TOTPAGES fields are interpreted in the same way as the individual parameters of the same names in XCALL SPOOL.


EZSPL Processing

Lots of this section (above and below) is copied from Setup Guide. Fix after docs are consolidated.The A-Shell version of EZ-SPOOL is quite similar to the AMOS version, but with some limitations and some extensions. Perhaps most importantly for those not interested in these features, they remain silent and hidden unless you go out of your way to activate them. Such people may safely skip this section. For the rest of you, we will give a very brief overview of EZ-SPOOL configuration, concentrating mainly on the areas of difference between the AMOS and A-Shell versions. Those wanting to know more about EZ-SPOOL should contact MicroSabio for a copy of the EZ-SPOOL User’s Guide.

Subtopics

EZSPL Config Files

EZSPL Commands


EZSPL Config Files

The first thing EZSPL (SPOOL.SBR) does upon being called is look for configuration files. The A-Shell version of the configuration file search path is much more abbreviated than the AMOS version, consisting only of the following:

EZ:<printfilename>.SFL

EZ:<programname>.SPG

EZ:<printername>.SPR

EZ:<termname>.SPL

MEM:SYSTEM.SPL

SYSTEM.SPL[p,pn]

SYSTEM.SPL[p,0]

EZ:SYSTEM.SPL

If none of these are found, then printing proceeds as if EZ-SPOOL did not exist. Otherwise, it opens the first file it finds and process the parameters contained within. The parameters supported under A-Shell are:

ASKPRT=<boolean>

AUTOWIDTH=<boolean>

BRIEF=<boolean>

DEFAULT=<default printer name>

EXTOPT=<sum of extended options flags>

MENU=<boolean>

OPTIONS=<boolean>

PRINTER=<forced printer name>

PRTSPL=spooler1,description (up to 64 PRTSPL statements)

SWITCHES=<sum of spooler switch flags>

TYPE=<boolean>

WAIT=<# seconds>

Each of these statements must be in all upper case, with no spaces, except within a description field. (e.g. "MENU = ON" and "menu = On" are invalid). Boolean options are "ON", "OFF", "YES", "NO", "TRUE" and "FALSE".

The lines of the configuration file are scanned from the top. For most parameters, if more than one instance of the parameter is processed, the last instance overrides earlier instances. The main except is the DEFAULT option, which only has an effect if no printer has been set (and no previous DEFAULT option processed). PRTSPL parameters are additive. The file may be broken into sections pertaining to individual users by prefixing the section with a line formatted as [username]. Lines between one [username] header and another are skipped unless the current username matches the name in the header. Two special [username] values may be used: a section with the header [always] is always processed, while a section with the header [default] is only processed if no previous username-specific section has yet been processed. ([always] and [default] don't count as username-specific sections.)

User name is determined by the native operating system logon procedure, and can be seen in the SYSTAT display or retrieve with GETUSN. It is not case sensitive in this context.

See Also

EZSPL Config File.

Subtopics

EZSPL Sample Config File


EZSPL Sample Config File

MENU=OFF

TYPE=OFF

ASKPRT=OFF

PRTSPL=PDFX,PDF Printer

[jack]

MENU=ON

TYPE=ON

ASKPRT=ON

DEFAULT=JET2

PRTSPL=JET2,Jack's Jet Printer

[always]

PRTSPL=JET1,Common Jet Printer

PRTSPL=DRAFT,Oki draft

[default]

DEFAULT=JET1

In the above case, the first four lines are always processed. They could have been preceded with another [always] header, or combined with the other [always] section. The five lines under [jack] are only processed if the user is jack, in which case the boolean options would override the previously set ones, the DEFAULT printer would only apply if no printer had been previously specified (by the application or in the miame.ini), and the PRTSPL line defining the JET2 printer would be added to the previous set of printers (currently containing only PDFX). The [always] section always gets processed. The [default] section would only be processed for users other than jack.

The capability of adding sections for individual users allows a great deal of flexibility for large systems.


EZSPL Commands

Following is a brief rundown on the EZ-SPOOL configuration file commands. These are also supported under EZ-SPOOL for AMOS.

Command | Argument | Description (default)
ASKPRT | Boolean | Provides an option to not go through with the spooling operation. If MENU=ON, the operation is aborted by entering choice Z. If MENU=OFF, the user is prompted on line 24 of the terminal whether to print. (OFF)
AUTO WIDTH | Boolean | OFF affects the initial display width of the preview utility (see Type) Normally (when on) it scans the first several dozen lines of the file to be previewed, and if any are longer than 80 columns, it switches automatically to 132 columns. (ON)
BRIEF | Boolean | ON activates a single-line menu (on line 24) asking for the name of the printer only. The user can TAB through the available choices. If OPTIONS=ON (or omitted) it will also prompt for the number of copies. (OFF)
DEFAULT | printer name | Defines the default spooler name to be used if no spooler name is passed in the XCALL SPOOL. This overrides the default established by the PRINTER= statement in miame.ini.
EXTOPT | Numeric | Enable various options.
LEFT MARGIN | Numeric | Leaves the specified number of columns untouched by EZVUE. This may be useful if you want to retain a sense of context with the underlying screen (or perhaps the underlying screen has some useful information you want to be able to see while looking at a report).
MENU | Boolean | ON causes a printer selection menu to appear. The choices on the menu consist of the printers defined in the PRTSPL statements. (OFF)
OPTIONS | Boolean | OFF eliminates the question about number of copies from the BRIEF menu. (ON)
PRINTER | printer name | PRINTER (in the EZ-SPOOL configuration file, as opposed to miame.ini) is like DEFAULT but overrides the spooler choice specified in the XCALL. (The confusion with miame.ini PRINTER parameter is regrettable, but this terminology matches EZ-SPOOL under AMOS.)
PRTSPL | spooler name, desc | These statements (e.g. PRTSPL=JET,LaserJet) establish choices that appear on the printer selection menu. If MENU=OFF, these statements have no effect. You may define up to 64 printer choices this way.
ROWS | number of rows | Establishes the initial number of display rows, when set to a legal value within the range of 24-50, subject to the capabilities of the terminal. The default setting is equal to the screen height at the time EZTYP is called. Note that the operator can also toggle between 24 and 42 row mode from the EZTYP command prompt with the "T" command or with the Shift+UpArrow or Shift+DownArrow keys.
SWITCHES | {+/-}##### | Allows you to add, remove, or replace the SWITCHES passed in the XCALL EZSPL, xcall SPOOL, or even XCALL EZTYP.
TOP MARGIN | Numeric | Leaves the specified number of rows untouched by EZVUE. (Same idea as LEFTMARGIN.)
TYPE | Boolean | ON provides an option to preview the file on the screen. If MENU=ON, this becomes choice X. Otherwise, the user is prompted on line 24 whether to preview the file.
WAIT | number of seconds | Specifies the number of seconds that various EZ-SPOOL screen prompts will wait for an answer before using the default value. "0" produces an unlimited wait. The default value (no WAIT specified) is 300 seconds.


EXTOPT

Argument is a sum of zero or more of the following flags values:

Flag | Description
&h0004 | Disable screen save/restore
&h0020 | Allow exit from EZVUE with LeftArrow
&h0040 | Allow exit from EZVUE with Tab
&h0080 | Allow exit from EZVUE with F1-F16
&h0100 | Don’t ask questions on PRINT command from within file viewer. This is mainly useful in conjunction with the SBR=EZPRTX option in the miame.ini file, which causes EZVUE to XCALL EZPRTX instead of XCALL SPOOL when printing from the viewer. Since you can customize EZPRTX.SBX, you may not want EZVUE to ask about starting and ending pages, or even about the printer choices.
&h0200 | Hitting the Home key before any other cursor motion keys while in the file viewer will act like the print command. This is a bit obscure, but apparently there are some people who feel it is just the ticket.


SWITCHES

Updated January 2008

The EZ-SPOOL configuration file command:

SWITCHES = {+/-}#####

allows you to add, remove, or replace the SWITCHES passed in the EZSPL, SPOOL, or even EZTYP.

For example, SWITCHES = +&h80000 would force EZSPL (including EZTYP) to act as if the &h80000 (GUI PREVIEW) switch had been set by the caller, and thus would launch the new GUI Preview utility instead of the text preview.

The main value of this switch is that it allows you to force EZTYP to use the APEX preview utility, provided you are running under A-Shell/Windows.

See Also

EZSPL Configuration File.


EZTYP

Updated June 2010

xcall EZTYP, fspec {,topmgn, leftmgn, exitcode}

EZTYP.SBR provides a simple way to call the text/print file viewer within the EZ-SPOOL subsystem. Note that it is possible to print individual pages or page ranges (including the entire file) within EZTYP.SBR, so it could in some circumstances be used in place of EZSPL.SBR. See EZTYP.LIT for more information on the capabilities of the print file viewer.

Note that EZTYP.SBR behavior may be affected by the WAIT (timeout) and AUTOWIDTH parameters in the EZSPL configuration files, as well as the EZCLR entry in the INI.CLR file. Refer to EZSPL Configuration Files and Color Customization for more information.

Parameters

topmgn, leftmgn

allow you to preserve the specified number of rows and columns at the left and top of the screen to be untouched by the EZTYP display. If you are not using these parameters, set them to 0.

exitcode

optionally returns the exitcode (INFLD-compatible) which caused the preview session to exit. Exitcode should be a floating point since many of the return values are negative. The typical exitcode would be 1 (Escape).

History

2010 June, 5.1.1184: The "Default Printer" option in the brief printer menu now clears the field as soon as you type a character.


F2HOST

xcall F2HOST, alphaflt, hostflt

F2HOST.SBR converts a six-byte AlphaBASIC-format floating point value to the equivalent IEEE 4 byte (single precision) or 8 byte (double precision) floating point format. Although this is done internally by A-Shell all the time, since it uses the IEEE format for internal calculations, the subroutine may be handy when exporting data to outside sources.

Parameters

alphaflt (F,6)

will return the converted value.

hostflt

should be mapped as X,4 or X,8 depending on the size of the IEEE floating point value to be converted.

Comments

See HOST2F for the reverse conversion. Note that when exporting data, it is usually more practical to output in string CSV format; see WRITECD for an easy way to do this.


FIFO

xcall FIFO, opcode, ch, buffer, flags, status

FIFO.SBR (UNIX only) provides a general-purpose technique for communicating with other processes, including those outside of A-Shell and possibly even on other machines (connected via a network) using named pipes. Named pipes (sometimes called FIFOs because that is the way they act) are supported under most implementations of UNIX and are similar to sockets, except that they are disk based and therefore somewhat removed from the details of networking.

Parameters

MAP1 OPCODE, F

! opcode (any numeric type)

! 0 = create FIFO

! 1 = open FIFO

! 2 = close FIFO

! 3 = read FIFO

! 4 = write FIFO

MAP1 CH ,F

! channel returned from open; passed to other

! opcodes (any numeric type)

MAP1 BUFFER, S

! data used in various ways depending on

! opcode. May be type X or S as appropriate

MAP1 FLAGS, F

! misc. flags, based on OPCODE (any numeric type)

! opcode 0: permission bits (modified by umask)

! opcode 1: open flags (0=read, 1=write, +4 for 'NDELAY'

! +100 for 'NONBLOCK' (see explanation below)

! opcode 2: ignored

! opcode 3: maximum number of bytes to read (if 0, use map size of BUFFER)

! opcode 4: maximum number of bytes to write (if 0, use map size of BUFFER;

!if –1, use length of BUFFER up to first null)

MAP1 STATUS, F

! result code (any numeric type)

! opcode 0: 0=OK, else –errno (see notes below on errno)

! opcode 1: >0=file number, else –errno

! opcode 2: none

! opcode 3: number of bytes read; else –errno

! opcode 4: number of bytes written; else –errno

Comments

NDELAY and NONBLOCK are mode options controlling how the routine attempts to read or write to a FIFO when the other end is not ready. The exact behavior may differ from one UNIX to another, so some experimentation may be required. In general, without either flag, read and write operations will suspend the caller until the operation can be completed. With NDELAY set, the operation will generally succeed and return immediately. That is, data written is buffered if the other end is not ready to read it, and read operations will just return NULL if no data is available. With NONBLOCK set, the routine will return immediately but will fail with an error code if the operation cannot be complete immediately.

Under SCO OpenServer (and possibly others) NONBLOCK is probably not practical for the writing end of a pipe, and in all cases it is not practical for both ends to use NONBLOCK.

Error Codes: Aside from the standard UNIX errno values, two special STATUS values are possible:-999 indicates that you passed a bad opcode, and –998 is returned when in NONBLOCK mode and the operation could not be carried out immediately.

A sample program, FIFO.BAS, which demonstrates the use of this subroutine, is available from the Other Downloads page at the MicroSabio website.


FILNAM

xcall FILNAM, ch, fname

FILNAM.SBR returns the filename when only the file channel is known. This is frequently useful in conjunction with error trapping, where the trapping routine identifies the file only by channel.

Parameters

ch (Num) [in]

the channel that the file is open on

fname (String) [out]

will return the filename (as specified in the open statement) corresponding to the specified file channel. If no file is open on that channel, fname returns a null string.


FLOCK

Updated March 2016; see History

xcall FLOCK, action, mode, status, file, rec

FLOCK.SBR provides a scheme for implementing shared and exclusive file and record locks, with an option to wait or return an in-use code. The A-Shell version is fully upward compatible with the AMOS version, and in addition goes beyond the various 64K limits in the AMOS version to support file channels and record number values up to 2 billion.

Parameters

action (Num) ([in]

Numeric code indicating the action to perform:

Value | Description
0 | Request permission to open file (see File)
1 | Inform FLOCK that file has been closed
2 | Program terminating – requests all locks on all files for this user to be released
3 | Request permission to read record (see File, Rec)
4 | Request permission to read/write all records of File
5 | Release Rec (previously locked with Action 3)
6 | Release File (previously locked with Action 4)

mode (Num) [in]

Flags for exclusive and wait options:

Value | Description
0 | Non exclusive lock, wait until request can be granted
2 | Exclusive lock, wait until request can be granted
4 | Non exclusive lock, no wait (return immediately with Status = 1 if request cannot be granted)
6 | Exclusive lock, no wait (return immediately with Status = 1 if request cannot be granted)

status (F,6)

Return code (for actions indicated in parentheses):

Value | Description
0 | Success
1 | Resource unavailable (0,3,4)
2 | Open request already granted (0)
3 | Permission to open must first be granted (1,3-6)
4 | Duplicate request for some record in file (3,4)
5 | Permission to use record must first be granted (5,6)
100 | Unimplemented action
101 | File channel not open for random processing (3-6)
102 | File channel already open for ISAM (0)
103 | Less than 15 queue blocks available (0,3,4)
104 | Illegal record (3-6)

file (Num)

Numeric value indicating the file channel

rec (Num)

Numeric value indicating the record number

Comments

FLOCK.SBR uses the queue block system to store the locks. You can specify the number of available queue blocks, and the location of the queue file (on disk or in memory) using the QUEUE= statement of the miame.ini. Note that since the memory option (available under UNIX/Linux only) is much faster, it is highly recommended if you are using FLOCK or XLOCK.

The QUTL.LIT utility can be used to display the locks in use and to manually clear locks left by an aborted job. It also displays locks that are pending (i.e. that a job is waiting on), which can be very useful in determining why a job appears to be hung. (An application can, and probably should, warn the user directly when it is stuck waiting on a lock, by using the no-wait mode flags 4 and 6.)

A-Shell’s implementation of FLOCK.SBR has an additional feature in that after waiting for more than 10 seconds for a lock, it will write out a "pending" lock record to the queue. This has no effect except that it can be displayed in the QUTL utility (which can also be executed under program control to create a list file) and thus allows for possibility of reporting to the user who has the lock that he or she is waiting for.

The miame.ini option TRACE=LOCKS causes information about the conflicting lock that you are waiting for to be displayed on the bottom status line of the terminal.

History

2016 March, A-Shell 6.2.1425: FLOCK bug fix/refinement: The memory allocation for the FLOCK cache now registers the name "FLKCACHE" in the log, which is useful when debugging memory handle use with the MALLOC TRACE. Also, close a memory leak whereby the cache was needlessly reallocated if FLOCK called within an SBX.


FORCE

xcall FORCE, job, string {,status}

FORCE.SBR is a programmatic equivalent to the FORCE.LIT user command, both of which provide a scheme for forcing characters into another job’s input stream.

FORCE relies on the same mechanism as SEND, which see for notes on limitations specific to particular operating system environments.


FTPDLX

Updated April 2015; see History

xcall FTPDLX, host, user, password, localpath, hostfile, hostdir, opcode, status {, port, emsg, privkey, passphrase}

(Windows only) FTPDLX.SBR sends and receives files via FTP from A-Shell. FTP2, which see for details, provides the same service in a slightly different way while using the same syntax and parameters.

Parameters

host (String) [in]

Specifies the name or IP address of the HOST computer you want to send files to or receive files from.

user (String) [in]

Specifies the user login name for the remote HOST. For anonymous FTP, use "anonymous"

password (String) [in]

Specifies the login password. For anonymous FTP, use your email address (e.g. myname@mydoman.com)

localpath (String) [in]

Full pathspec (PC format) for the local file (whether sending or receiving.) If no directory specified, the current login directory will be used. Note: you may want to use MIAMEX, MX_FSPEC to translate an AMOS directory specification to a PC version. See Comments below for wildcarding.

hostfile (String) [in]

May be the full pathspec of the remote file, or just the filename and extension. In the former case, leave HOSTDIR blank, otherwise specify the directory in HOSTDIR. HOSTFILE is case sensitive. See Comments below for wildcarding.

hostdir (String) [in]

If not blank, it is prepended to the hostfile field to form the full pathspec of the remote file. hostdir is case sensitive.

opcode (Num) [in]

Note that while most of the codes apply to both FTPDLX and FTP2, some apply—as indicated—only to one or the other.

Symbol | Value | Description
XFTPF_GET | &h000000 | Transfer from server to client PC.
XFTPF_PUT | &h000001 | Transfer from client PC to server.
XFTPF_ASCII | &h000002 | ASCII transfer mode. Note that some FTP servers will ignore the ASCII option as a security precaution.
XFTPF_NOERRMSG | &h000010 | Disable the error message dialog box display that will otherwise appear in the case of errors. In either case, the error code is also returned in the STATUS parameter.
XFTPF_PASSIVE | &h000020 | Passive transfer mode. This is often needed to get past firewall restrictions.
XFTPF_NOBANNER | &h000040 | Suppress the transfer banner.
XFTPF_DEBUG | &h000080 | Activates debug mode, which writes out a very detailed log file to C:\DEBUG.LOG. This is mainly of use when trying to solve low-level protocol problems. FTPDLX only.
XFTPF_SFTP | &h000100 | Use SFTP protocol instead of FTP. This requires a SSH2 service on the server side, typically at port 22.
XFTPF_RMVEXT | &h000200 | Rename host file after transfer, removing the last extension. This may be useful to prevent the file from being accessed by the remote system until the transfer is complete. Since it removes the last extension, you probably want to set the host file to have two extensions, such as MYFILE.DAT.UP. After the transfer is complete, the file would be renamed to MYFILE.DAT. FTPDLX only.
XFTPF_VERSION2 | &h010000 | Request FTP2. FTPSYNC mode only.
XFTPF_KEEPOPEN | &h020000 | Keep connection open. FTP2 only.
XFTPF_REUSE | &h040000 | Reuse previous connection if available. FTP2 only.
XFTPF_CLOSE | &h080000 | Close connection, no transfer. FTP2 only..
XFTPF_DEL | &h100000 | Remote delete. FTP2 only.
Definition file: ashell.def

status (F,6) [out]

*Return status. 0=success. Negative numbers are internal errors in FTPDLXcall which you can see from the source code and which are listed in the table below. -1 indicates a user abort. Numbers 1000 and up are EZFTP.OCX errors.

port (Num) [in]

Specifies the control port to connect to the FTP server on. Default is 21 for FTP and 22 for SFTP.

emsg (String) [out]

May return a message on error.

privkey (String) [in])

contains the filespec of private key file in OpenSSH format. If specified and non-blank, FTPDLX will use public/private key authentication rather than standard password authentication.

passphrase (String) [in]

is the passphrase for the private key. May be omitted if the private key is not passphrase-protected.

Comments

• Nothing is displayed during the transfer, unless an error occurs and opcode +16 is not specified .

• You can rename FTPDLX to another name, provided that you change the ALIAS statement in miame.ini accordingly (change only the part to the left of the colon)

• The source file specification (in localpath or hostfile, depending on the directory of the transfer) may contain the "*" wildcard. For example, "/vm/miame/dsk0/007006/*.dat", or "/vm/miame/dsk0/007006/ab*", or even "c:\vm\miame\dsk0\007006\cyxz*.d*"

• FTPDLX is actually an internal front-end to an external COM routine, and is dependent on the following entry in the miame.ini:

ALIAS=FTPDLX:FtpDLXcall.FTP

It relies on two dlls: FTPDLXcall2.dll and wodFtpDLX.dll, both of which are normally stored in the %MIAME%\bin directory, and both of which must be registered (using regsvr32.exe). (The ALIAS, dlls, and registration are handled automatically by a typical installation, but might require a manual assist if the installation was set up manually using COPY commands rather than the installer.)

Environmental Notes

FTPDLX is based on a commercial COM FTP control called wodFTPDLX by WeOnlyDo Controls, the runtime license for which is included with A-Shell.

FTPDLX relies on two DLLs, wodFTPDLX and FTPDLXcall, being in the bin directory (where ashw32 is loaded from), and it requires the following miame.ini statement:

ALIAS=FTPDLX:FTPDLXcall.FTP

FTPDLX is used internally by ATE to implement the AG_FTP and ZTERM file transfer escape sequence. See also:

• ZTXFER.LIT and ATSYNC.LIT.

• ATEAPX.SBX

History

2015 April, A-Shell 6.1.1406: Added FTP/SFTP remote delete.

2014 May, A-Shell 6.1.1385: Add parameters privkey and passphrase.

2014 February, A-Shell 6.1.1379: Rewrote opcode table to add new options for FPT2 and to improve clarity.

2008 June, A-Shell 5.1.1116: FtpDLXcall2.DLL 5.1.0.204 supports flag 512 (rename host file after copy) in conjunction with wildcarding. Also, when wildcards are specified, an additional log file, ftpdlx.lst, will be created showing the wildcard and the matching files, and if the renaming option is on, the ftpdlx.log file will also show each individual rename. Also, if the remote server doesn't allow renaming if the target already exists, FTPDLX will send an explicit delete command and then try renaming

Negative Error Codes Returned in status

Value | Description
-1 | too few params
-2 | can't malloc (or out of malloc hdls)
-3 | no such Opcode
-4 | misc param error
-5 | can't dynamically link library
-6 | license failure
-7 | error during adding file (upload)
-8 | error during SyncRequest
-9 | error processing file for post
-10 | unable to allocate string buf
-11 | error during put
-12 | error during download
-13 | unable to log in to server (FTP OR SSH)
-14 | unable to log to directory on server (FTP)
-15 | failure to connect (ssh)
-17 | open session failure (ssh)
-18 | pty (termtype?) failure (ssh)
-19 | shell startup failure (ssh)
-20 | error receiving data (ssh)
-21 | error sending data (ssh)
-22 | connection lost (ssh)
-23 | no channel (ssh)
-24 | received eof (ssh)
-25 | cert problem
-26 | get failed (no access?)
-27 | bad cipher type
-28 | invalid key len
-29 | bad cipher mode
-30 | bad padding value
-31 | bad file (or file error)
-32 | catch-all CRYPT errors
-33 | bad encoding
-34 | bad public key (or error extracting it)
-35 | bad private key (or error extracting it)
-36 | failure to open remote file
-37 | attempt to call function already executing
-38 | error uploading (possibly local file doesn't exist?)
-39 | error close remote
-99 | unsupported platform (Windows only)

Subtopics

FTP Debugging


FTP Debugging

Note: these debugging tips do not apply when the FTP2 protocol is being used (i.e. XFTPF_VERSION flag set in FTPDLX.SBX, /2 switch used in ZTXFER.LIT, /V2 switch in ATSYNC.LIT, etc.). See FTP2 for more details.

Aside from the error codes listed in this section, the FTPDLX.SBR also writes a human readable log file, FTPDLX.LOG in the current directory, which may identify discrepancies between what you thought you were asking it to do and what it was actually trying to do. In addition, if the environment variable ASHFTPDEBUG is defined, a more detailed, lower-level log will written to %TEMP%\ftpdebug.log (or, prior to A-Shell 5.1.1153 of June 2009, c:\debug.log).

The two DLLs mentioned early must be recorded in the Windows Registry, and this process will normally be taken care of automatically by the A-Shell installation program. However, if FTPDLX doesn't work even if the DLLs and the ALIAS statement are in place, you may need to manually register to the two DLLs:

Start..Run..REGSVR32 <bin-path>\WODFTPDLX.DLL

Start..Run..REGSVR32 <bin-path>\FTPDLXCALL.DLL

FTPDLX Error Codes

The following error codes may be returned from the FTPDLX control based on logic within the XCALL itself.

Value | Description
-1 | User abort
-2 | Error retrieving xcall parameters
-3 | Error setting remote address
-4 | Error setting username
-5 | Error setting password
-6 | Error setting port (may suggest you have the 1.0 version of EZFTP.OCX)
-7 | Error setting remote directory and file
-8 | Error displaying progress dialog
-9 | Error during connect
-10 | Error setting binary/ASCII transfer mode
-11 | Error in get or put operation
-12 | Error setting local file

wodFTPDLX.DLL Error Codes

Value | Description
30001 | Cannot connect at this time. Use Disconnect first.
30002 | Cannot execute, not yet connected.
30003 | Component busy.
30004 | Cannot change Hostname at this time. Use Disconnect first.
30005 | Cannot change Port at this time. Use Disconnect first.
30006 | Cannot change Protocol at this time. Use Disconnect first.
30007 | Please set login, and password/certificate first.
30009 | Invalid local file name or path.
30010 | Could not resolve given Hostname.
30011 | Invalid data received from remote server. Protocol error.
30012 | Protocol version mismatch error.
30013 | Server signature does not match. Aborted by user.
30014 | Bad server public DH value.
30015 | Server signature does not match.
30016 | Invalid username or password reported by server.
30017 | Could not obtain pty on remote server.
30018 | Server does not support password authentication.
30019 | Server rejected due to bad fingerprint/certificate information.
30020 | Failed to open channel on the server.
30021 | LocalPath should specify a file, and such file does not exist.
30022 | Error occurred trying to open local file.
30023 | Error occurred trying to read from local file.
30024 | Error occurred trying to write to local file.
30025 | Server replied with invalid response ID.
30026 | Failed to load key or certificate. Password invalid?
30027 | Cannot use Append method when Resume property is set to True.
30028 | Please set Hostname property.
30029 | Component was busy while disconnected by the server.
30030 | Given path on the server is a directory.
30031 | Server returned an error:
30032 | Failed to create temporary file.
30033 | Server returned invalid response to FXP_ATTRS.
30034 | Server cannot write to a given path.
30035 | Data connection has timed out.
30037 | Not enabled in SFTP protocol.
30038 | Selected proxy type cannot be used with selected protocol.
30039 | Selected proxy type requires passive mode connection.
30040 | Proxy server has closed the connection.
30041 | Proxy server rejected supplied login credentials.
30042 | Crypto algorithm could not be negotiated.
30043 | Buffer size out of range 1kb-1mb.
30044 | Only valid in SSL secured protocols.
39999 | License key missing. You can not use this component in design environment.

FTP Protocol return codes

Value | Description
40110 | Restart marker reply.
40120 | Service ready in few minutes.
40125 | Data connection already open; transfer starting.
40150 | File status okay; about to open data connection.
40200 | Command okay.
40202 | Command not implemented, superfluous at this site.
40211 | System status, or system help reply.
40212 | Directory status.
40213 | File status.
40214 | Help message.
40215 | System type.
40220 | Service ready for new user.
40221 | Service closing control connection.
40225 | Data connection open; no transfer in progress.
40226 | Closing data connection.
40227 | Entering Passive Mode.
40230 | User logged in, proceed.
40250 | Requested file action okay, completed.
40257 | Path created.
40331 | User name okay, need password.
40332 | Need account for login.
40350 | Requested file action pending further information.
40421 | Service not available, closing control connection.
40425 | Can't open data connection.
40426 | Connection closed; transfer aborted.
40450 | Requested file action not taken. File unavailable (e.g., file busy).
40451 | Requested action aborted: local error in processing.
40452 | Requested action not taken. Insufficient storage space in system.
40500 | Syntax error, command unrecognized.
40501 | Syntax error in parameters or arguments.
40502 | Command not implemented.
40503 | Bad sequence of commands.
40504 | Command not implemented for that parameter.
40530 | Not logged in.
40532 | Need account for storing files.
40550 | Requested action not taken. File unavailable (e.g., file not found, no access).
40551 | Action aborted: broken pipe.
40552 | Requested file action aborted. Exceeded storage allocation (for current directory or dataset).
40553 | Requested action not taken. File name not allowed.

Certificate Errors

Value | Description
50000 | Certificate ok
50002 | Certificate error: Unable to get issuer certificate.
50003 | Certificate error: Unable to get CRL (Certificate revocation list).
50004 | Certificate error: Unable to decrypt certificate signature.
50005 | Certificate error: Unable to decrypt CRL (Certificate revocation list) signature.
50006 | Certificate error: Unable to decode issuer public key.
50007 | Certificate error: Certificate signature failure.
50008 | Certificate error: CRL (Certificate revocation list). signature failure.
50009 | Certificate error: Certificate not yet valid;
50010 | Certificate error: Certificate has expired.
50011 | Certificate error: CRL not yet valid.
50012 | Certificate error: CRL has expired.
50013 | Certificate error: Certificate does not have 'before' field.
50014 | Certificate error: Certificate does not have 'after' field.
50015 | Certificate error: CRL does not have 'last update' field.
50016 | Certificate error: CRL error in 'next update' field.
50017 | Certificate error: Out of memory while reading certificate.
50018 | Certificate error: Depth zero self signed certificate.
50019 | Certificate error: Self signed certificate in chain.
50020 | Certificate error: Unable to get issuer certificate locally.
50021 | Certificate error: Unable to verify the first certificate.
50022 | Certificate error: Certificate chain too long.
50023 | Certificate error: Certificate revoked.
50024 | Certificate error: Invalid Certificate Authority.
50025 | Certificate error: Path length exceeded.
50026 | Certificate error: Invalid certificate purpose.
50027 | Certificate error: Certificate not trusted.
50028 | Certificate error: Certificate rejected.
50029 | Certificate error: Subject issuer mismatch.
50030 | Certificate error: Authority and subject key identifier mismatch.
50031 | Certificate error: Authority and issuer serial number mismatch.
50032 | Certificate error: Key usage does not include certificate signing.
50050 | Certificate error: Application verification failure.

Winsock Errors

Value | Description
10004 | Interrupted function call. A blocking operation was interrupted by a call to WSACancelBlockingCall.
10009 | Generic error for invalid format, bad format.
10013 | Permission denied. An attempt was made to access a socket in a way forbidden by its access permissions. An example is using a broadcast address for "sendto" without broadcast permission being set using setsockopt (SO_BROADCAST).
10014 | Bad address. The system detected an invalid pointer address in attempting to use a pointer argument of a call. This error occurs if an program passes an invalid pointer value, or if the length of the buffer is too small. For instance, if the length of an argument which is a struct sockaddr is smaller than sizeof(struct sockaddr).
10022 | Invalid argument. Some invalid argument was supplied (for example, specifying an invalid level to the setsockopt function). In some instances, it also refers to the current state of the socket - for instance, calling accept on a socket that is not listening.
10024 | Too many open files. Too many open sockets. Each implementation may have a maximum number of socket handles available, either globally, per process or per thread.
10025 | The IP address provided is not valid or the host specified by the IP does not exist.
10038 | Socket operation on a non-socket. An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.
10048 | Address already in use. Only one usage of each socket address (protocol/IP address/port) is normally permitted. This error occurs if a program attempts to bind a socket to an IP address/port that has already been used for an existing socket, or a socket that wasn't closed properly, or one that is still in the process of closing. For server programs that need to bind multiple sockets to the same port number, consider using setsockopt(SO_REUSEADDR). Client programs usually need not call bind at all - connect will choose an unused port automatically.
10049 | Cannot assign requested address. The requested address is not valid in its context. Normally results from an attempt to bind to an address that is not valid for the local machine, or connect/sendto an address or port that is not valid for a remote machine (e.g. port 0).
10050 | Network is down. A socket operation encountered a dead network. This could indicate a serious failure of the network system (the protocol stack that the WinSock DLL runs over), the network interface, or the local network itself.
10051 | Network is unreachable. A socket operation was attempted to an unreachable network. This usually means the local software knows no route to reach the remote host.
10052 | Network dropped connection on reset. The host you were connected to crashed and rebooted. May also be returned by setsockopt if an attempt is made to set SO_KEEPALIVE on a connection that has already failed.
10053 | Software caused connection abort. An established connection was aborted by the software in your host machine, possibly due to a data transmission timeout or protocol error.
10054 | Connection reset by peer. An existing connection was forcibly closed by the remote host. This normally results if the peer program on the remote host is suddenly stopped, the host is rebooted, or the remote host used a "hard close" (see setsockopt for more information on the SO_LINGER option on the remote socket.)
10057 | Socket is not connected. A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using sendto) no address was supplied. Any other type of operation might also return this error - for example, setsockopt setting SO_KEEPALIVE if the connection has been reset.
10058 | Cannot send after socket shutdown. A request to send or receive data was disallowed because the socket had already been shut down in that direction with a previous shutdown call. By calling shutdown a partial close of a socket is requested, which is a signal that sending or receiving or both has been discontinued.
10060 | Connection timed out. A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
10061 | Connection refused. No connection could be made because the target machine actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host - i.e. one with no server program running.
10063 | Specified host name is too long.
10064 | Host is down. A socket operation failed because the destination host was down. A socket operation encountered a dead host. Networking activity on the local host has not been initiated. These conditions are more likely to be indicated by the error WSAETIMEDOUT.
10065 | No route to host. A socket operation was attempted to an unreachable host. See WSAENETUNREACH
10091 | Network subsystem is unavailable. This error is returned by WSAStartup if the Windows Sockets implementation cannot function at this time because the underlying system it uses to provide network services is currently unavailable.
10093 | Successful WSAStartup not yet performed. Either the program has not called WSAStartup or WSAStartup failed. The program may be accessing a socket which the current active task does not own (i.e. trying to share a socket between tasks), or WSACleanup has been called too many times.
10094 | Graceful shutdown in progress. Returned by recv, WSARecv to indicate the remote party has initiated a graceful shutdown sequence.
11001 | Host not found. No such host is known. The name is not an official hostname or alias, or it cannot be found in the database(s) being queried. This error may also be returned for protocol and service queries, and means the specified name could not be found in the relevant database.
11002 | Authoritative host not found. This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server. A retry at some time later may be successful.


FTP2

Updated February 2017; see History

xcall FTP2, host, user, password, localpath, hostfile, hostdir, opcode, status {, port, emsg, privkey, passphrase }

(Windows and Linux - see History). FTP2 supports the client side of FTP and SFTP file transfers. Similar to FTPDLX and mostly upward compatible with it, FTP2 differs in the following ways:

Parameters

host (String) [in]

Specifies the name or IP address of the HOST computer you want to send files to or receive files from.

user (String) [in]

Specifies the user login name for the remote HOST. For anonymous FTP, use "anonymous"

password (String) [in]

Specifies the login password. For anonymous FTP, use your email address (e.g. myname@mydoman.com)

localpath (String) [in]

Native file specification (Windows or Linux format, depending on the platform) for the local file (whether sending or receiving). If no directory specified, the current login directory will be used. Note: you may want to use MIAMEX, MX_FSPEC to translate an AMOS directory specification to a PC version. Otherwise, beware of case sensitivity under Linux. See Comments below for wildcarding.

hostfile (String) [in]

May be the full pathspec of the remote file, or just the filename and extension. In the former case, leave HOSTDIR blank, otherwise specify the directory in HOSTDIR. HOSTFILE is case sensitive. See Comments below for wildcarding.

hostdir (String) [in]

If not blank, it is prepended to the hostfile field to form the full pathspec of the remote file. hostdir is case sensitive.

opcode (Num) [in]

Note that while most of the codes apply to both FTPDLX and FTP2, some apply—as indicated—only to one or the other.

Symbol | Value | Description
XFTPF_GET | &h000000 | Transfer from server to client PC.
XFTPF_PUT | &h000001 | Transfer from client PC to server.
XFTPF_ASCII | &h000002 | ASCII transfer mode. Note that some FTP servers will ignore the ASCII option as a security precaution.
XFTPF_PASSIVE | &h000020 | Passive transfer mode. This is often needed to get past firewall restrictions.
XFTPF_SFTP | &h000100 | Use SFTP protocol instead of FTP. This requires a SSH2 service on the server side, typically at port 22.
XFTPF_VERSION2 | &h010000 | Request FTP2. FTPSYNC mode only.
XFTPF_KEEPOPEN | &h020000 | Keep connection open. Automatically set for FTP2.
XFTPF_REUSE | &h040000 | Reuse previous connection if available. Automatically set for FTP2.
XFTPF_CLOSE | &h080000 | Close connection, no transfer. Automatically set for FTP2.
XFTPF_DEL | &h100000 | Remote delete. Automatically set for FTP2.
XFTPF_RECURSE | &h00200000 | recurse subdirs, with wildcards.
The following are mutually exclusive (SFTP only); M=missing, N=newer, S=size.
XFTPF_SYNC_ALL | &h00000000 | All matching files.
XFTPF_SYNC_M | &h01000000 | All files that don't exist in destination.
XFTPF_SYNC_MN | &h02000000 | All files that don't exist in destination, or are newer in source.
XFTPF_SYNC_N | &h03000000 | Only files that exist in both places but are newer in source.
XFTPF_SYNC_MS | &h04000000 | All files that don't exist in destination or are different size.
XFTPF_SYNC_MNS | &h05000000 | All files that don't exist in destination or are different size or newer.
XFTPF_SYNC_DELM | &h0F000000 | With XFTPF_DEL, only remote files not existing locally.
Definition file: ashell.def

status (F,6) [out]

Return status. Greater than zero indicates success. In some cases (primarily wildcard operations with SFTP protocol), status will return the number of files actually transferred or deleted. Negative values indicate errors; see table below.

port (Num) [in]

Specifies the control port to connect to the FTP server on. Default is 21 for FTP and 22 for SFTP.

emsg (String) [out]

Will contain a debug trace in the case of an error. Since this can be lengthy, you should provide a string of at least 1500 bytes to contain it all. In the case of wildcard transfers or deletions using the SFTP protocol, on success it will contain a list of the files actually transferred or deleted.

privkey (String) [in])

contains the filespec of private key file in OpenSSH format. If specified and non-blank, FTPDLX will use public/private key authentication rather than standard password authentication.

passphrase (String) [in]

is the passphrase for the private key. May be omitted if the private key is not passphrase-protected.

Comments

Nothing is displayed during the transfer, unless an error occurs and opcode +16 is not specified .

The source file specification (in localpath or hostfile, depending on the directory of the transfer) may contain the "*" wildcard. For example, "/vm/miame/dsk0/007006/*.dat", or "/vm/miame/dsk0/007006/ab*", or even "c:\vm\miame\dsk0\007006\cyxz*.d*"

FTP2 is used in ZTXFER and ATSYNC if the /2 switch is specified.

The XFTPF_SYNC opcode options apply only to the SFTP protocol (XTFPF_SFTP), and only come into play when a wildcard is specified in the relevant source argument and the destination is just a directory. The wildcard source argument acts as the first level of filtering on files to be transferred, with further filtering determined by the XFTPF_SYNC_xxx options.

Note that unlike most of the XFTPF_xxx flags, which are coded as unique bits and thus could theoretically be combined in any way, provided it makes functional sense, the XFTPF_SYNC_xxx options are all mutually exclusive—i.e., choose only one. Also note that XFTPF_SYNC_DELM only applies in conjunction with XFTPF_DEL.

When doing wildcard transfers or remote deletions, the status parameter now returns on success the number of files transferred or deleted, rather than just zero. Also, the emsg parameter in that case will contain a list of the files transferred or deleted, delimited by line breaks.

See program FTPTST in SOSLIB:[907,33]

History

2017 February, A-Shell 6.3.1544: FTP2.SBR now exposed to Linux via libashnet.so.1.9.157. Wildcards are now supported in the SFTP protocol; previously they were only supported for the FTP protocol. New opcode options added.

2015 April, A-Shell 6.1.1406: Added FTP/SFTP remote delete.

2015 March, A-Shell 6.1.1405: ASHNET.DLL 1.7(147) refinement: you can now override the default timeout for FTP2.SBR (60 seconds) by defining the environment variable FTP2TIMEOUT as the desired timeout in seconds, e.g. .SETENV FTP2TIMEOUT=10. Note that this is implemented entirely in ASHNET.DLL.

2014 February, A-Shell 6.1.1379: Added routine to A-Shell


GDIPRT

command = sbx:GDIPRT {,<option1>, <option2>, <option3>...}

(UNIX/Linux only.) GDIPRT.SBX is a print filter subroutine intended only for use in a COMMAND statement within a printer init file, which performs the function of transferring the file from the UNIX/Linux server to the workstation, where it be will be resubmitted to an AshLite printer of the same name (as the printer originally requested on the server). The usual motivation would be to take advantage of Windows printing features that would otherwise be unavailable on a UNIX or Linux server.

The standard version of GDIPRT requires that the workstation have a network connection to the server, using the ZTERM 2000 terminal emulator, as it uses ZTERM escape sequences to perform an FTP file transfer. (You could modify the source code to work for other terminal emulators or other file transfer methods.)

The procedure works as follows:

• The file is submitted to the print on the server (say, to printer "prt1").

• The printer init file (e.g. ASHCFG:PRT1.PQI or SYS:PRT1.INI) invokes the GDIPRT subroutine via the COMMAND statement as shown above.

• The GDIPRT subroutine first attempts to detect if the terminal emulator is ZTERM, it aborts with STATUS=-2.

• It then opens the print file and scans it, looking for //IMAGE and //METAFILE statements. For any that are found, the corresponding files are transferred to the PC’s temp directory (see <dir> option in the following table.)

• The print file itself is then transferred to the PC.

• AshLite is launched on the PC, passing it the command PRINT PRT1=<print file>. (Note that the printer name, in this case PRT1, will be the same as for the original print request.) If the AshLite launch fails, it will return STATUS=-3.

• Otherwise, we assume that the operation succeeded and return STATUS=0 (so that we do not try to print it on the server.)

The option parameters may be used to specify any of the following options (expressed as quoted, literal strings):

Value | Meaning
"VERBOSE" | Causes a dialog box to appear during the transfer operation showing details of the various steps. Useful for debugging, or just to have something to look at.
"DEBUG" | Causes AshLite to be launched with a visible window, and to not automatically exit on completion of the print command (thus making it easier to see what may have gone wrong). If VERBOSE was also specified, then the subroutine (on the server) will wait for an acknowledgment from the user before removing the display box.
"LOG" | Causes the subroutine to log details about the operation to the log file OPR:GDIPRT.LOG
"<dir>" | (Any string containing a backslash or colon, e.g. "C:\TEMP") will cause the routine to use the specified directory as the temporary working directory on the PC. Otherwise, if ZTERM build 143+ is detected, it will use the %TEMP% environment variable, else it will use "C:\TEMP"


GET

Updated October 2016

xcall GET, buffer {,chan, bytes'req, bytes'rcvd, timeout, flags}

GET.SBR is useful for simple or sophisticated input of raw characters from the keyboard or a file. Under UNIX/Linux, it may also be used for Inputting from a serial device. See COMIO for serial I/O under Windows.

Parameters

buffer (String, may be dynamic) [out]

receives the byte(s) input. Note that no trailing null byte is added by the subroutine, so you may want to pre-clear this variable before calling GET. In the simplest case of GET where no parameters beyond buffer are specified, it will input a single character from the keyboard, waiting as long as necessary.

chan (Num) [in] (optional)

File channel number of a file that has been opened for input, and from which the character(s) are to be read. If not specified, or zero, input is from the keyboard.

bytes’requested (Num) [in] (optional)

Number of bytes to input. If not specified, default is 1. You can specify 0 in conjunction with the timeout feature if you just want to know if a character is available without actually inputting it. Two special values are supported: -1 requests a line of input terminating with LF (and ignoring CR); -2 requests a line of input terminating with CR (and ignoring LF). Note that for the special values -1 and -2, the terminating CR and/or LF will not be included in buffer, but will be included in the count in bytes'received.

bytes’ received (Num) [out] (optional)

Returns the number of bytes that were actually input (and returned into the Buffer parameter). Normally this will be the same as bytes’requested, except in the following circumstances:

If bytes’requested was 0, then bytes’received will be 1 if there was one or more characters available to be input, or 0 to indicate no characters available.

If we hit the end of the input file, or the timeout period expires before reading the number of requested bytes, then bytes’received will be less than bytes’requested.

If an I/O error occurs, or if a timeout period is specified and no characters are input because the file was already at the end-of-file mark, bytes’received will be set to -1. This distinguishes the case of end-of-file from timeout.

When bytes'requested is set to -1 or -2, bytes'received will be set to the total number of bytes received, including the terminating character(s). However, the terminating characters (CR and/or LF) are not returned in buffer.

timeout (Num) [in] (optional)

Number of milliseconds to wait for input before aborting. If set to 0 or not specified, there is no timeout. Note that the actual elapsed time may be substantially longer that the specified period. This is both because of CPU time dedicated to other processes and because the total timeout period is actually divided into slices equal to the number of characters to be input, with each slice being used up only if no characters are available.

For example, if you have a 5000 millisecond (5 second) timeout and are requesting 5 characters, then you will actually be allotted 5 one-second timeout periods, and each period is only spent if no characters are input during that period. If exactly one character arrived every 0.75 seconds, then you would still have five unused seconds after four characters had be input, even though three seconds had actually elapsed. This scheme may seem a bit strange, but is actually a reasonable compromise between the two extreme approaches of treating the timeout period as an absolute maximum or of resetting it entirely after each character.

Note: In order for the timeout to be reliable when inputting from a device such as a serial port, you must first disable buffering on the input channel (see MX_NOBUF). Failure to do so could result in apparently flaky behavior, since the timeout mechanism may not be aware of buffered characters, thus leading to false timeouts.

flags (Num) [in] (optional)

Setting flags to 1 activates 'raw' mode input, which eliminates all input processing and filtering (such as function key support, terminal driver input translations, and adds the ability to input null bytes). Otherwise, null bytes are stripped out of the input stream before your application gets a chance to see them. Note the following restrictions on the flags parameter:

• Under UNIX, setting flags=1 and bytes'req=0 (in order to check if any characters are available without inputting anything) will properly return bytes'rcvd=1 if anything is available to input, but if the first byte available is a null, it will be lost. So it is best to just set bytes'req to the number of bytes you want, and use timeout to avoid getting stuck in an input wait.

• Under Windows, input processing occurs asynchronously as characters arrive, not as they are requested by the application. So the raw flag will only be useful if the XCALL GET occurs before the characters in question arrive.

Comments

• When inputting from the keyboard, NOECHO will be set automatically and left that way on exit.

• Function key translations are not processed by GET.SBR. Use GETX or ACCEPT if you need that feature.

• GET.SBR may also be used to check if a character is available without waiting and without actually inputting the character, by setting bytes’requested and timeout to zero. This is equivalent to GETKEY(-2).

History

2012 October, A-Shell 6.1.1318: Performance enhancements added.

When reading large chunks of data from a file directly into memory buffers, setting the flags argument to 1 (timeout must be 0) will streamline the operation. The effect is mainly noticed only with large read requests, but can be dramatic in that case. A 20MB fully-cached read operation was about 60 times faster (15 versus 900 milliseconds) with the new mode using flags=1 versus the old mode with flags=0.

Of course, in both cases the total time was < 1 sec, so the difference may not be significant except in extreme cases. But with the large amount of RAM available today, loading a 500 MB file into RAM is not out of the question, and there the difference might be 250 milliseconds versus 20 seconds.

2006 August, A-Shell 4.9.963: GET may also be used to check if a character is available without waiting and without actually inputting the character, by setting bytes’requested and timeout to zero. (Previously, this would have waited indefinitely until a character was available.) This is equivalent to GETKEY(-2).

Subtopics

Inputting from a serial device


Inputting from a serial device

To input from a serial device under UNIX or Linux, open it as an input file, e.g.:

OPEN #9, "/dev/cua0", INPUT

Then pass the file channel to XCALL GET just like any other input file channel. Beware, however, that under UNIX, such serial ports will be by default set to "line input" mode. Thus, while you may be asking for only 2 characters, you would not actually "see" them until a line terminator (usually LF) had been received. To avoid this annoyance and get the characters immediately as they are transmitted from the other end, you need to take the port out of "line input" mode. One way to accomplish this is to use XCALL HOSTEX with the UNIX stty command to turn off "icanon" mode, for example:

xcall HOSTEX, "stty –icanon < /dev/cua0"

Comments

• Use the stty command only after opening the file channel. Otherwise, the settings may be wiped out by the open operation. Also, note that stty and its arguments are case sensitive, usually all in lower case.

• If inputting from a serial device under UNIX/Linux, you may want to adjust port settings, such as flow control, baud rate, etc, which can be done by executing an stty command (via HOSTEX.SBR) after opening the port and before using GET.SBR. Consult the UNIX stty man page or other documentation for details on the available settings.

• You may need to use chmod 666 on the port device file to allow it to be read and its settings modified by a non-root user.


GETADR

Updated June 2012; see History

xcall GETADR, var, varaddr {, varsize}

GETADR.SBR retrieves the memory address, and optionally the size, of the variable specified as the first parameter. This technique was used in the so called "Speed Optimized Interface" of INFLD under AMOS, and is preserved here just for backward compatibility. (The so called interface is a misnomer under A-Shell, where it actually requires more overhead, and thus is not recommended for new programming.) Getting the address and size of a variable might have some other exotic application, but we are not sure what.

Parameters

var [in]

can be any arbitrary variable.

varaddr [out]

can be any numeric type.

varsize [out]

if specified, must be a 2 byte binary. Note that if var is an array element, the size and address will be for that element, not for the entire array. You can get the starting address of the array by specifying the first element, but the only way to get the total size of the array would be to map an unformatted variable on top of the array (with the appropriate size specified in the MAP statement).

Comments

Note that iIf the address parameter specified in argument 2 is an X,8 variable, then it is assumed to be formatted as a pair of B,4 variables as in the structure above. This will allow for a transition to 64 bit mode should it ever occur, without the application having to be aware of it.

History

2012 June, A-Shell 6.1.1307: Add X,8 / B,4 relationship described in Comments above.


GETBYT

xcall GETBYT, channel, buffer, bytes

GETBYT.SBR reads a specified number of bytes from an open input file.

Parameters

channel (Num) [in]

is the channel number of the file, which must be open for input.

buffer (Raw) [out]

Receives the data.

bytes (Num) [in]

Specifies the number of bytes to read, which must be less than or equal to the size of buffer.

Comments

Use the EOF(Channel) function to test for end of file condition before each call to GETBYT.SBR.

You can get a similar effect with INPUT RAW, except that it always reads a number of bytes equal to the size of the specified variable.

Note that GET.SBR performs a similar operation but is somewhat more sophisticated.

Comments

• PUTBYT


GETDEV

(1) xcall GETDEV, devstr

(2) xcall GETDEV, unit, dev

GETDEV.SBR retrieves the current device information in one of two formats, as shown above.

Parameters

MAP1 Devstr,S,6 ! (e.g. "DSK1")

MAP1 Unit,B,2 ! (logical unit #)

MAP1 Dev,S,3 ! (e.g. "DSK")


GETJOB

(1) xcall GETJOB, jobnam {,progrm}

(2) xcall GETJOB, jobnam {,ppn, jobnum}

GETJOB.SBR retrieves the jobname, plus optionally the program name or the PPN and job number.

Parameters

jobnam (String,6)

program (String,6)

ppn (B,2)

jobnum (B, any size 1-5)

Comments

Note that ppn can be mapped either as above or as:

MAP1 PPN

MAP2 P,B,1 ! project

MAP2 PN,B,1 ! programmer number

or

MAP1 PPN

MAP2 PROJ,S,3 ! for example, "001"

MAP2 PROG,S,3 ! for example, "004"

The latter format is preferable, since A-Shell as of build 897 supports decimal PPNs up to 999,999. If you use the B,1 format, you will be limited to octal PPNs update to 377,377.


GETJTB

xcall GETJTB, job-table-variable

There are innumerable subroutines which have been written in order to return the current PPN, terminal name, job name, and so on. Although many of the more common subroutines are implemented in A-Shell, it is clearly not possible to cater to all possibilities. A-Shell therefore also contains this subroutine, GETJTB (and its counterpart SETJTB), to return into a structure, everything that is likely to be needed from the job control block, within an application.

The structure of the job-table-variable is:

MAP1 JOB'TABLE ! 130+ byte area

MAP2 JOBNAM,s,6 ! Job name

MAP2 JOBNO,f,6 ! Entry in job table

MAP2 JOBDEV,s,5 ! Current device

MAP2 JOB'FIL1,x,1

MAP2 PPN ! Current PPN

MAP3 P,b,1 ! Project number

MAP3 PN,b,1 ! Programmer number

MAP2 JOBPRV,f,6 ! Job privilege word

MAP2 JOBPRG,s,6 ! Current program name

MAP2 USRNAM,s,20,"" ! Current user name

MAP2 TRMNAM,s,6 ! Terminal name

MAP2 DRVNAM,s,6 ! Terminal driver name

MAP2 TRMBAUD,f,6 ! Terminal baud rate

MAP2 JOBDFP,x,6 ! Default file protection

MAP2 JOBLVL,f,6 ! Class of user (level)

MAP2 JOBEXP,f,6 ! Experience of user

MAP2 SYSDOS,s,14 ! Operating system name

MAP2 JOBATT,s,6 ! Parent job name

MAP2 SYSVER,s,4 ! Operating sys. version (to 9.9N)

MAP2 JOBSTS,f,6 ! Job status word

MAP2 PRJ'STR,s,3 ! Project no. string

MAP2 PRG'STR,s,3 ! Programmer no. string

MAP2 JOBTYP,f,6 ! Job type

Comments

By calling GETJTB once at the start of each program, all the information likely to be required is readily available, without the need to call a hotchpotch of routines later on.

The operating system field, sysdos, contains the name of the host operating system on which A-Shell is running, for example Windows/32 or AIX. If A-Shell is running in demonstration mode, then an asterisk is appended to the name, e.g. AIX*.

The user name field, usrnam, returns the current logon user name.

The jobnam parameter will be returned with the trailing spaces removed, but the program name (jobprg) will be padded with trailing spaces to a length of 6.

The p and pn fields, being only one byte each, are only capable of handling up to 377,377 (octal). Since A-Shell supports decimal PPNs update to 999,999, you should use the prj’str and prg’str fields instead.


GETMAC

xcall GETMAC, addr {,maxcount, adapters(1)}

GETMAC.SBR returns the hardware MAC ("Media Access Control") address of the Ethernet controller. Depending on how the addr parameter is mapped, it either returns it as a set of six decimal numbers in an array, or as a string of the format xx:xx:xx:xx:xx:xx (where each ‘xx’ is a hex octet). Under Windows, it can also return a list of all the available adapters.

Parameters

addr [out]

The returned MAC address, mapped either as:

MAP1 ADDR

MAP2 ADDRB(6),B,1

Or

MAP1 ADDR,S,18

In the first case, the MAC address is returned as a sequence of 6 decimal values, one byte each. In the second, it is returned as a string in the format "xx:xx:xx:xx:xx:xx" (where each 'xx' is a hex octet).

maxcount (optional, Windows only) [in]

This optional parameter may be used under Windows, in conjunction with the following adapters parameter, to retrieve a list of all the available Ethernet adapters on the local PC. The value of maxcount must be the same or less than the mapped size of the adapters array and serves to set a limit on the number of adapters about which information will be returned.

adapters (optional, Windows only) [out]

If specified, this array will return details about all of the available adapters, and must be mapped as follows:

map1 adapters(#) ! # must be >= value of maxcount

map2 adap'mac(8),b,1 ! MAC address (decimal bytes)

map2 adap'mac$,s,24 ! MAC address (hex format)

map2 adap'name$,s,128 ! Adapter name

map2 adap'descr$,s,128 ! Adapter description

map2 adap'ip$,s,16 ! IP address

Comments

The main purpose of this subroutine would probably be as a security mechanism to prevent unauthorized use of an application, since every Ethernet controller ever produced has a unique MAC address, and there is no practical way to duplicate them. However, before you get too excited about this as a replacement for SSD chips, be aware that there are a number of potential or real pitfalls with MAC addresses:

• A computer may have multiple Ethernet cards. Under UNIX variants, GETMAC.SBR only returns the first one. Under Windows, the addr parameter will return the one which appears to be the one currently connecting the PC to the network, but this determination can be confused, and it can obviously change over time. (For example, a laptop user might connect with a wired adapter sometimes, and with a wireless adapter other times.)

• In the PC environment, an adapter could be portable (such as a PCMCIA or USB adapter).

• With virtualization software (like VMware or Parallels), you might have virtualized adapters, in effect allowing two machines to have the same MAC address. (Such adapters would most likely have the word "Virtual" in their description, so if this is a concern, you might want to check the descriptions via the adapters list and disallow licensing to such a Virtual adapter.

• Adapters that are disabled will not show up in the list. (So, for example, if you attach your license to a particular adapter, and later the user disables it in favor of another adapter, you might have to re-license it.)

Most of the potential problems listed above apply only to PCs (since a UNIX server is unlikely to suffer from such changes to the adapter hardware list). One strategy for dealing with the variability of adapters on a PC would be to scan the list of available adapters in order to choose one (or two) that appear to be permanent (i.e. not virtual, not USB, etc.) for licensing purposes. At runtime, as long as it (or one of them) is present in the current list, you could be reasonably sure that the software hadn't been moved from the licensed machine.

Note that the first two fields of the adapters array are mapped to accommodate up to eight bytes of MAC address, which is a nod to some future possibility not currently applicable.

See CONDEV and MX_GETIP (Get IP address) for information on getting the IP address.


GETPPN

xcall GETPPN, ppn

GETPPN.SBR returns the current PPN in the two-byte format (first byte is project number, second byte is programmer number).

Note that the two-byte PPN format is largely obsolete, as of build 897, which supports decimal PPNs up to 999,999. You are better off using one of the other routines which retrieve the ppn, which retrieve the PPN in string format, such as LOG or GETJTB, or as a pair of two-byte binaries, such as XPPN.


GETPRG

XCALL GETPRG, prgnam {,sbxnam, svr'prgnam, svr'prgver, prgdir, sbxdir}

GETPRG.SBR returns the name of the currently running program in prgnam.

Parameters

Parameter | Type | I/O | Description
prgnam | String, 10 | out |
sbxnam | String, 10 | in/out | If specified, it also returns the name of the current routine (if called from within a subroutine). Otherwise, set to "".
svr'prgnam | String, 10+ | out | Applies only to subroutines running in the ATE client context (e.g. launched via AG_XFUNC); it returns the name of the program currently running on the server. Otherwise it will return a null string.
svr'prgver | String, 13+ | out | Also only applies to the ATE client context, returning the version of the program currently running on the server. Example format: 1.2A(345)
prgdir | String, 18+ | out | Returns the device:[p,pn] where the program (prgnam) was loaded from. Example format: DSK22:[123,456]. If the program was loaded directly from memory, it will return a null string.
sbxdir | String, 18+ | out | Same as prgdir, but for the last called SBX.

History

2011 October, A-Shell 5.1.1136: Add four parameters.


GETUSN

Updated July 2013

xcall GETUSN, usrnam$ {, machine$, ate'user$, ate'machine$, compname$, wts'session}

GETUSN.SBR returns the current user login name along with, optionally, the other variables listed in the syntax line and the table below. See OPTIONS=EFFUSR and CONDEV for related information.

Parameters

Parameter | Type | I/O | Notes
usrnam$ | String, 20+ | in/out | The current user login name. If the user name has been overridden (via MX_SETUSRNAM or automatically by an ATSD server when accepting an ATE connection), then usrnam$ will return the over-ridden name. To force it to return the original name (either the server login name or effective user name), set usrnam$ to "!" before calling GETUSN.SBR.
machine$ | String, 20+ | out | The console device name.
ate'usrnam$ | String, 20+ | out | The login name of the ATE client.
ate'machine$ | String, 20+ | out | The machine name of the ATE client.
compname$ | String, 20+ | out | The Windows computer name of the client machine. In many cases this will be the same as the machine$ parameter, except it will be just the computer name without any suffixes. It is mainly useful in cases where you are using the -awts command line switch (or OPTIONS=NTTS) where the machine$ parameter may have little relation to the actual client computer name.
wts'session | Num | out | The Windows Terminal Services client session ID, if applicable. Zero indicates the client is not running a WTS connection. Note, however, that internally WTS numbers client sessions from zero, so if you are using the value to reference registry or other information tied to the session #, subtract one first.

History

2013 July, A-Shell 6.1.1356: Added parameters compname and wts'session


GETVER

xcall GETVER, verstring

GETVER.SBR returns the version of the currently running program module, either RUN or LIT or SBX.

Parameters

verstring [out] (String)

should be 13+ characters to handle the longest possible version string.

Example

Given the following PROGRAM statement:

PROGRAM MYTEST,1.0A(234)

GETVER would return:

1.0A(234)

Comments

If the program is currently executing an SBX, then GETVER will return the version of the SBX rather than the version of the main program.

A module with no PROGRAM statement will return version "0.0(0)"

The version string returned by GETVER is the same as that displayed by DIR/V and also the same as the value of the dot variable .PGMVERSION.

To retrieve the version of a program module other than the one currently executing (i.e. like DIR/V does), see the SOSLIB function Fn'ProgVer$(fspec).

See Also

• VERSYS.LIT, which returns the versions of source modules embedded within a compiled program module.


GETX

xcall GETX, char

GETX.SBR inputs a single character from the keyboard, with function key translation support. The function key translation table will be any PFK loaded into user memory, or the LIB:<tdvnam>.IFX file. The routine will automatically set NOECHO mode (equivalent to XCALL NOECHO) and leave the terminal in that mode. It will not display the input character. It is exactly equivalent to XCALL ACCEPN, Char, "IFX".

char may be a floating point variable (in which case the ASCII value is returned), or else a binary or string variable (in which case the raw input character will be returned).


GRECNV

xcall GRECNV, dblock

GRECNV.SBR takes an input date and converts it to a variety of other formats (string, Gregorian, separated) with optional range and validity checking. The type of conversion is specified by the PCONC field.

MAP1 DBLOCK

MAP2 PSTR,S,12 ! MM/DD/YY or MM/DD/CCYY

MAP2 PYEAR,B,2 ! Year in Century

MAP2 PMON,B,1 ! Month

MAP2 PDAY,B,1 ! Day

MAP2 PCENT,B,2 ! Century

MAP2 PBASE,B,4 ! New – Zero for Gregorian date

MAP2 PJDAT,B,5 ! Gregorian form of the date

MAP2 PCONC,S,1 ! Conversion request code

! "D" = Start with string (PSTR)

! "G" = Start with Gregorian (PJDAT)

! "M" = Start with separated

(PYEAR,PMON,PDAY,PCENT)

! "T" = Start with today

MAP2 PVALD,S,1 ! To-Gregorian validity checking

! "N" = Do not do reverse conversion check

MAP2 PFRMT,S,1 ! Date format code

! "C" = MM-DD-YYYY (Yr+Cent*100)

! "S" = MM-DD-YY-CCCC (Sep Century)

MAP2 PCMPC,S,1 ! Completion code

! "S" = Success

! "R" = Success but out of range

! "U" = Failure

MAP2 PDOW,B,1 ! Day of week (0=Monday)

MAP2 POLD,B,5 ! Oldest date within range

MAP2 PRNGE,S,1 ! Range check code

! "B" = Date must be BC

! "A" = Date must be AD

! "R" = Date must be within old/new range

MAP2 PNEW,B,5 ! Newest date within range

MAP2 PFIL,B,5 ! Not used

GRECNV was originally written for AMOS by Bob Strunk of Software Systems Consulting in Cincinnati, Ohio, and may be still available if you are looking for a date conversion routine that is available on both AMOS and A-Shell.


GTLANG

xcall GTLANG, status, gtlang'map

GTLANG.SBR retrieves information from the currently selected language definition file, such as the names of the days of the week, affirmative and negative abbreviations, currency symbol, etc. Using these variables instead of hard coding such information can go a long way towards making your application adaptable to other languages.

Beginning in A-Shell 5.1.1136 of January 2009, the A-Shell extended form of the ASHINC:GTLANG.MAP file is supported in order to return the upper collating sequence. A sample program, GTLANG.BAS, is included in the EXLIB to illustrate.

Parameters

status (F,6) returns 0 for success or –1 for failure.

gtlang'map

The following table shows the variable names.

Variable name | Type | Description
LANG'NAME1, LANG'NAME2 | S,20 | Standard and alternate names for the language.
LANG'EXTENSION | S,4 | is the extension used for message files associated with this language. For example, the extension for the ENGLSH.LDF (Language Definition File) is USA, which is why you will find message files with names like ERRMSG.USA, SBRMSG.USA, LITMSG.USA, etc.
LANG'CURRENCY'SYM | S,4 | Currency symbol for this language.
LANG'CURRENCY'POS | F,6 | Will be set to 0 if the symbol should appear before the currency amount, or 1 if after.
LANG'CURRENCY'SPC | F,6 | Specifies the "currency spacing" (whatever that is).
LANG'CURRENCY'SIZE | F,6 | Specifies the number of digits making up the "currency amount" (whatever that means).
LANG'THOUSANDS | S,1 | Character to be used to separate thousands (i.e. to insert between every three digits). In the USA we use a comma, while in much of Europe they use the period, with the comma being used for the decimal point.
LANG'DECIMAL | S,1 | Character to be used for the decimal point.
LANG'DATE'FORMAT | F,6 | Date format: 0=month-day-year, 1=day-month-year, 2=year-month-date.
LANG'TIME'FORMAT | F,6 | Time format: 0=12 hour, 1=24 hour.
LANG'DATE'SEP | S,1 | Character used to separate the day, month, and year parts of a date, e.g. "/" for MM/DD/YY.
LANG'TIME'SEP | S,1 | Character used to separate the hours, minutes, and seconds in time (typically ":").
LANG'DATA'SEP | S,1 | Character used to separate elements of data.
LANG'PPN'LEFT, LANG'PPN'RIGHT | S,1 | Characters used to enclose PPN, (e.g. [7,6]).
LANG'CHARSET | F,6 | Character set number to be used. This is probably only relevant under AMOS.
LANG'YES'WORD, LANG'NO'WORD | S,6 | Complete name of the affirmative word ("yes", "sí", "ouí", etc.) or negative word ("no", "non", "nyet", etc.).
LANG'YES'CHAR, LANG'NO'CHAR | S,1 | Standard one-character abbreviation for yes'word and no'word.
LANG'WORD'CHARS | S,30 | Contains all of the characters that can be considered part of a word in this language. (For English, this is just A-Z and a-z, but other languages may allow for accented or other special characters.)
LANG'ULC | S,30 | May specify up to 15 pairs of upper and lower case letters that are to be considered equivalent. The idea here is to identify how to fold accented and other special characters to upper and lower case. (Not necessary for the standard ASCII A-Z.)
LANG'SPARE | S,30 | Reserved for something.
LANG'USR | S,30 | Reserved for user-defined extensions to the language definition.
LANG'COL | X,128 | May be used to specify the first 128 bytes of the collating sequence for this language. It should consist of all the characters 0-127 in ascending sort order. If you are using an 8 bit character set, then the upper 128 bytes may be placed in Col2 provided that the Extend1 and Extend2 fields are set appropriately.
LANG'JAN <through> LANG'DEC | S,20 | Full names of the twelve months of the year: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
LANG'MON <through> LANG'SUN | S,20 | Full names of the seven days of the week: Mon, Tue, Wed, Thu, Fri, Sat, Sun
LANG'EXTEND1, LANG'EXTEND2 | B,1 | Set to 1 to indicate that the corresponding collating sequence field (Col and Col2 respectively) is valid.
LANG'COL2 | X,128 | Collating sequence for the second 128 bytes (128-255) of the character set.
Definition file: GTLANG.MAP


HASH

Added October 2011

xcall HASH, hashtype, key, cbkey, hash, status

HASH.SBR generates a hash code from a string of characters.

hashtype specifies the type of hash to generate. Currently there are only two possibilities: 1=ELF, 2=DJB. ELF is one of the most commonly used hash algorithms in the UNIX world, and is tweaked for 32 bit processors. DJB (named after its creator Dan J. Bernstein) is thought to be one of the most efficient hash algorithms and is thought to work work well on very short keys, but may be considered somewhat weaker than the ELF algorithm (i.e. more likely to generate the same hash from different keys) when it comes to avalanche and permutation.

For related information and an alternative to HASH, see DIGEST.

Parameters

Parameter | Type | I/O | Description
hashtype | Num | in | 1=ELF, 2=DJB. See above
key | String or X | in | the source data from which the hash will be calculated. It can be any length.
cbkey | Num | in | optionally specifies the number of bytes to be considered in key. If 0, key is processed up to the first null byte or its physical length.
hash | String,8+ or b,4 | out | the generated hash. If string (8+ bytes), then it will be returned as 8 hex digits. If b,4, it will be returned as a 32 bit value.
status | Signed Num | out | indicates success or failure:
 |  |  | >=0 | success
 |  |  | -1 | bad key type
 |  |  | -2 | bad hash type
 |  |  | -3 | bad has data type of size

History

2011 October, A-Shell 5.1.1239: Added to A-Shell


HOST2F

xcall HOST2F, alphaflt, hostflt

HOST2F.SBR converts an IEEE 4 byte (single precision) or 8 byte (double precision) floating point to the equivalent AlphaBASIC 6 byte format. Although this is done internally by A-Shell all the time, since it uses the IEEE format for internal calculations, the subroutine may be handy when importing data from outside sources.

Parameters

alphaflt

should be mapped as F,6 and will return the converted value.

hostflt

should be mapped as X,4 or X,8 depending on the size of the IEEE floating point value to be converted.

Comments

See F2HOST for the reverse conversion. Also note that when importing data, if you have any control over the formatting of the import file, it will probably be much easier to use string CSV format. See the INPUT CSV statement for an easy way to import CSV data.


HOSTEX

Updated November 2012; see History

xcall HOSTEX, cmd {,status, stdout}

HOSTEX.SBR allows you to execute a host operating system command from within your BASIC program. It is similar to the popular AMOS.SBR known to many AMOS programmers, except that the effect of the command depends on the host operating system.

Parameters

cmd (String) [in]

valid command line for the current host operating system, with an optional suffix; see Command Modifiers and Launching A-Shell with HOSTEX.

status (F,6) [out]

is an optional return variable. If specified, it will return the exit value of the command, if any. (Zero generally means success; anything else would be considered an error, but the interpretation of the error is dependent on the command executed.)

stdout (String) [out]

an optional parameter, used only with Linux, that may be specified to receive the stdout of the specified command. For example:

MAP1 STDOUT$,S,2048

MAP1 STS,F

xcall HOSTEX,"uname -a",STS,STDOUT

This would capture the output of the "uname -a" command into the variable STDOUT.

It also works with multi-line output, e.g.:

xcall HOSTEX,"ls -l",STS,STDOUT

In this case, the individual lines of output will be delimited within the variable (STDOUT) using the standard UNIX line delimiter (ASCII 10).

Note that this technique is really only reliable with "regular commands", especially shell commands. If you execute an arbitrary executable, there is no telling whether it will generate stdout in a fashion compatible with this scheme.

Note also that dynamic (variable-length) strings are not supported for this parameter. Any output that exceeds the physical length of the parameter will be discarded.

Comments

Under UNIX, a new process is forked to execute the command as a child process to the current process, but by default the child process uses the same screen console as the parent. If you do not want the output of the child process to disturb the current screen, you can redirect its output to a file (as in the example above). You may also want to redirect the stderr channel to a file as well, as in this example which searches for the string "abcd" in all the .prt files in the current directory, writing its output and any error messages to grep.lst:

xcall HOSTEX, "grep abcd *.prt > grep.lst 2>&1"

If you want to get the output of the executed command on the current screen, then beware that A-Shell will not know what has been displayed there, and thus the cursor will be out of sync with the display. One way around this is to redirect the output to a file, then read the file back in and use PRINT statements to output it in the context of A-Shell. For example, PWD.LIT uses this technique to print the current working directory:

xcall HOSTEX, "pwd > pwd.lst"

Open #1, "pwd.lst", input

Input line #1, PLINE

Print PLINE

Close #1

Another technique which might be appropriate for some kinds of interactive commands would be to save the current screen, clear it, execute the new command, then restore the original screen, for example:

PRINT TAB(-1,202); TAB(-1,0); ! save screen & clear it

xcall HOSTEX, CMD$

PRINT TAB(-1,0);TAB(-1,203); ! clear and then restore it

For commands that generate simple teletype-style text output, the easiest and cleanest method for capturing the output is to use the stdout parameter which, when specified, automatically captures the stdout output into the specified variable. You can append the 2>&1 redirection modifier to the command to also redirect the stderr output there as well.

Under A-Shell/Windows, HOSTEX executes both Windows and certain DOS-legacy (also known as "console mode") commands (for which an EXE exists). This will create a new Windows process which will run in its own window (without disturbing the current window, other than perhaps to cover it up).

+Note that for later versions of Windows, you can use the CMD.EXE (command executor) to execute any console commands, for example:

xcall HOSTEX, "cmd.exe /c pwd > pwd.lst"

Use cmd /? from the Windows command prompt to see all of the switches and options available. See this discussion on the A-Shell forum for related information.

Note that in the ATSD environment, you cannot launch a child session on the server unless it runs only in background—i.e. you must use the "&" Command Modifier.

History

2012 November, A-Shell 6.0.1263: Remove command line length limit of 512, now unlimited.

2010 May, A-Shell 5.1.1182: HOSTEX.SBR bug fix: Passing a "-g <icon>" clause on a "$ASHELL" command line (to launch a child session of A-Shell) was not working if the parent was launched with a "-g <icon>" switch. (It was reverting to the default acorn icon.)

2008 September, A-Shell 5.1.1124: Optional third parameter (stdout) added (UNIX only).

2006 May, A-Shell 4.9.956: xcall HOSTEX,"$ASHELL..." now replicates more switches from the parent to the child:

• -o <settings file>

• -nm

• -m, -mx (provided no -m or -mx is specified in XCALL command line)

• -z, -zt, -zi (provided no -z, -zt, or -zi is specified in XCALL command line)


Command Modifiers

Modified March 2017; see History

By default, the current program is suspended while waiting for the command to finish executing. In other words, the command is executed like it was a subroutine. However, this can be modified by appending a modifier to the end of the cmd string, from the following table:

Modifier

Function

<none>

Current process is suspended while waiting for the command to complete

&

Command executes in background (or in the case of Windows, minimized) and in parallel with current job. (Current job not suspended.)

%

(Windows only) Command executes in a minimized window, but current job is suspended while waiting for it to complete. This is most useful for minimizing the screen flash which would otherwise accompany a command that executed very quickly.

$

(Windows only) Command executes in a normal window, but current job is not suspended.

#

(Windows only) Similar to "$", except that it allows the child process to inherit the handles opened by the parent. This is mainly only of interest for passing a socket opened by the parent to the child, so that the parent can close it and accept another on the same port.

^

(Windows only) Allows for a slight variation in the Windows behavior that you otherwise would get without specifying any suffix character. In both cases, the parent session waits for the child to exit, but in the case of the "^" suffix, it does not try to get the focus back when the child returns, and it doesn't notify any sibling A-Shell sessions when the user transmits keystrokes or mouse events while waiting that are ignored by the child while the parent is waiting.

This addresses an exotic situation with child processes that have no user interface support but which take long enough that it becomes likely for the user to either switch to another session in the meantime, or to try mouse or keyboard actions in the suspended parent session which then interfered with a sibling A-Shell session.

The command modifier, if present, should be separated from the end of the cmd string by a space. For example, to launch the Windows calculator without suspending the current job, you would use:

xcall HOSTEX,"CALC.EXE $"

History

2017 March, A-Shell A-Shell 6.3.1545: added ^ switch

2006 July, A-Shell A-Shell 4.9.960: added # switch


Launching A-Shell with HOSTEX

xcall HOSTEX,"$ASHELL –e run myprog &"

Since A-Shell is itself a valid host operating system command (e.g. "ashell" or "ashw32.exe"), you can use HOSTEX to launch another instance of A-Shell. To make this easier, HOSTEX replaces the symbol "$ASHELL" with a portion of the command line used to launch the current instance of A-Shell (eliminating the problem of keeping track of how A-Shell was launched, which differs among platforms and installations). Specifically, $ASHELL will expand into the full path of the A-Shell executable, plus the -i <miame.ini> switch, plus the -g <icon> switch if applicable. In addition, the following switches are replicated from the parent to the child:

-o <settings file>

-nm

-m, -mx (provided no -m or -mx is specified in XCALL command line)

-z, -zt, -zi (provided no -z, -zt, or -zi is specified in XCALL command line)

For example, this command would work under either Windows or UNIX, launching another instance of A-Shell using the same executable and miame.ini file as the current session. The new session would run in background (or minimized under Windows) and would automatically terminate when "myprog" ended:

xcall HOSTEX,"$ASHELL –e run myprog &"

Note that the -e switch is needed to cause the child session of A-Shell to terminate when the command (in this case, "run myprog") finishes executing. Otherwise the child session will remain active at the dot prompt until it is explicitly terminated with the HOST command.

Notes

Under both UNIX and Windows, spawning another copy of A-Shell will not count as another node against the node license. The license banner will be omitted from the spawned copy, but only if both the extension and the path are omitted from the command line, as in the examples. In other words, the directory C:\VM\MIAME\BIN, or /vm/miame/bin, must be in the environment PATH.

If you want to launch a child copy of A-Shell in order to run another BASIC program or LIT commands, the preferred way to do this is with XCALL AMOS, which acts as a front end to HOSTEX.

Under Windows, it is possible to execute DOS (or "console) commands with HOSTEX, but only if an EXE for the command actually exists. For example, there is no COPY.EXE (use XCOPY instead). (The console command EXE files are usually stored in the /windows/command subdirectory.) You may also want to check out the Windows START command which is useful for executing other console commands and BAT files. (Type START /? from the command prompt for help.)

History

2006 May, A-Shell A-Shell 4.9.956: Add ability to replicate switches from parent to child.


HTMLP

command = sbx:HTMLP

(Windows only) HTMLP.SBX is a print filter subroutine intended only for use in a COMMAND statement within a printer init file. It creates a temporary copy of the specified print file with an HTML prefix and suffix, and then launches your local browser to view it.

Source, samples and related functions can be found in SOSLIB:[907,29].


HTTP

Updated October 2016; see History

(Windows only) HTTP.SBR handles various kinds of HTTP requests. See the subtopics listed at the bottom of this page for in-depth comments.

xcall HTTP, opcode, status, flags, url, request, response {,properties, certpw}

Parameters

opcode (Num) [in]

1 (XHTTPOP_REQ) = general HTTP request. Opcode must be set to "1" in all cases.

status (Signed number) [out]

0 = ok (for simple functions)

>0 = response code returned from HTTP server (generally means that operation succeeded in communicating with the server; whether that represents an unqualified success will depend on the application and the body of the response.)

<0 = Operational errors (see ashinc:HTTP.DEF HTTPERR_xxx)

flags (Num) [in]

sum of options flags. These flags are listed in ashinc:HTTP.DEF.

Symbol | Value | Description
XHTTPF_SSL | &h00001 | Use a secure protocol (SSL/TLS) per preference of server. See XHTTPF_SSL_xxx below to coerce a particular variation. Note: must be set explicitly (not automatic from "https:" in url.)
XHTTPF_REQPOST | &h00002 | Tells upload routine to use POST format with Content-Type: application/x-www-form-urlencoded
XHTTPF_REQUPLOAD | &h00004 | Tells upload routine to use POST format with Content-Type: multipart/form-data. Used for uploading files only, i.e. requires XHTTPF_FILEREQ. See Customizing REQUPLOAD Headers.
XHTTPF_REQHEAD | &h00008 | Makes the request a HEAD request
XHTTPF_REQXML | &h00010 | Deprecated. Use XHTTPF_REQPOST + XHTTPF_HDRBODY instead; see Customizing POST headers. Old description: Makes the request a POST using text/xml content
XHTTPF_REQGET | &h00020 | Simple GET (text of HTML page)
XHTTPF_REQPUT | &h00040 | Simple PUT
XHTTPF_DOWNLOAD | &h00080 | Download a file
XHTTPF_FILEREQ | &h00100 | Request arg is a filespec (or list of) not a buffer
XHTTPF_FILERESP | &h00200 | Response arg is a filespec not a buffer
XHTTPF_DEBUG | &h00400 | Outputs copy of the generated request to DEBUG.REQ; transcript of the transmission and internal calls to DEBUG.LOG; appends connection summary to ASHNET.LOG.
XHTTPF_HDRBODY | &h00800 | Parse file into headers (added individually) and body. See Customizing POST headers.
XHTTPF_PARMBODY | &h01000 | Like HDRBODY but use AddParam instead of AddHeader
XHTTPF_SETFROMURL | &h02000 | Extract path and form info from URL for use in the request header. Typically not used with XHTTPF_REQPOST, since it will strip any ?<suffix> from the resulting POST header.
XHTTPF_FORCEXFR | &h04000 | File parms are server-relative; transfer to PC
XHTTPF_REQGETRAW | &h08000 | Like XHTTPF_REQGET (&h0020) but works around a limitation of XHTTPF_REQGET in which certain characters outside the range supported by Latin1/ANSI (e.g. Russian or Chinese) would just be dropped from the response. Can also be used to retrieve binary data containing embedded nulls (such as a file), although you must then use XHTTPF_FILERESP (&h0200) to write the response to a file. (Added in ASHNET.DLL 1.4.132)
HTTPF_SSL_TLS1 | &h10000 | Combine with XHTTPF_SSL to request TLS 1.0 variation
HTTPF_SSL_SSL2 | &h20000 | Combine with XHTTPF_SSL to request SSL 2.0 variation
HTTPF_SSL_SSL3 | &h40000 | Combine with XHTTPF_SSL to request SSL 3.0 variation
HTTPF_SSL_PCT1 | &h80000 | Combine with XHTTPF_SSL to request PCT 1.0 variation
HTTPF_GETSTSTXT | &h100000 | Retrieve HTTP status text from last operation (see Comments)
Definition file: HTTP.DEF

url (String) [in]

Fully qualified URL, with optional path and/or {:port}. URL maximum length is 1024. For example:

"http://www.microsabio.net/dist/51dev/temphold/junk.zip"

"https://www.paypal.com"

"http://someserver.com:10080/some/path" (see History notes below)

request (String) [in]

Contains content of the request, for operations that require it, such as uploading files, POST, etc. Depending on XHTTPF_FILEREQ flag, may be a string buffer or a filespec (native, but see Comments about ATE). For the XHTTPF_REQUPLOAD option, can be a list of filespecs with semi-colon delimiters and an optional prefix indicating the content-type of the file and the "name" attribute to associate with it (see Comments). Note that some options only work with file mode, while some may only work with string mode.

response (String) [in/out] (If S,0, must be pre-initialized to desired maximum length)

Returns the body of the response, or in the case of XHTTPF_GETSTSTXT, the HTTP status text from the prior XCALL HTTP operation. If XHTTPF_FILERESP is set, then the passed-in value of response is interpreted as a filespec (native) and the actual response is written to that file. Otherwise the response is returned in the specified parameter.

properties (String) [in]

An optional list of name=value clauses delimited by semicolons, e.g.: name1=value;name2=value2,value3;...;nameN=valueM. See the following topic HTTP Properties Parameter for a table of properties. Note: to maintain backwards compatibility with old and now deprecated certfile parameter and syntax: if there is no "=" (equals sign) character in the string, it will be intepreted as the old certfile spec.

certpw (String) [in]

Optional password for the PFX file.

Example

Simple file download: here we download a JPG file from our public server, using XHTTPF_DOWNLOAD.

++include ashinc:http.def

map1 params

map2 flags,b,4

map2 url$,s,100,"http://www.microsabio.net/dist/other/images/EditorShot.jpg"

map2 response$,s,20,"download.jpg"

map2 status,f

flags = XHTTPF_DOWNLOAD or XHTTPF_FILERESP

xcall HTTP, XHTTPOP_REQ, status, flags, url$, "", response$

? "status: ";status;

if status = 0 or status = 200 then

? "ok"

else

? "error - ";response$;" may contain details (as text)"

endif

Note:

• Prior to ashnet.dll 1.4.131, the normal return code for this operation was 0, and errors would return -12. In ashnet.dll 1.4.131 and later, it returns HTTP status codes (200 for ok, most everything else would be an error.)

• In the case of an error, the response file may contain details (in text) rather than the downloaded file.

• For ATE compatibility, use xcall ATHTTP instead of xcall HTTP. ATHTTP also works with local Windows as a pass-through to HTTP.

• The SOSLIB function Fn'HttpGet() can also download files, although it uses multiple XCALL TCPX operations to do so. The approach shown here is somewhat more efficient when running under Windows, but less efficient under ATE (due to the need to transfer files back and forth between the ATE client and the server).

• If the URL is https: (secure), simply add the XHTTPF_SSL flag.

See the EXLIB directory [908,25] for several other examples.

History

2017 February, A-Shell 6.3.1544: HTTP.SBR now exposed to Linux via libashnet.so.1.9.157. Also, filespecs passed in the request and response parameters are now folded to lower case. The documentation has always noted that they are to be native filespecs, but since case doesn't matter in the Windows world, folding them to lower avoids a common mistake when porting a working application from Windows to Linux.

2016 November, October, A-Shell 6.3.1535: Replaced old parameter certfile with new parameter properties and much expanded its usage.

2014 October, A-Shell 6.1.1391: Increased length of url from 260 to 1064.

2013 June, A-Shell 6.1.1350: (ashnet.dll 1.4.135, which works with A-Shell 6.0 and later): added support for the certfile and certpw parameters. Previously they were ignored.

2012 October/November, A-Shell 6.0.1261 and 1263: Various changes comprising ASHNET.DLL version 1.4.132/2..

2009 September, A-Shell 5.1.1159: added to A-Shell

Subtopics

HTTP Properties Parameter

ATE

Setting attributes for uploaded files

Customizing POST headers

Customizing REQUPLOAD Headers

SOAP Example

Debugging

Retrieving HTTP status text


HTTP Properties Parameter

The current list of property names and values is shown below. Note that the property names are case sensitive, but the values are not. For boolean values, anything starting with "T" or "1" is considered TRUE; everything else is considered false. Note the default values for the case where the property is not specified.

Name = Value | Default | Description
Cert=<fspec> | none | Specify cert file spec
AllowHeaderFolding | True | Disables MIME header folding
BasicAuth | False | Allows HTTP basic authentication; see Comments.
RequiresSslCertVerify | False | If true, verify server's SSL cert; if expired or invalid, abort connection.
SslAllowedCiphers | <all> | Specify comma-delimited list of allowed SSL/TLS ciphers; see Comments.
AutoAddHostHeader | False | If true, the "Host" header will be added to the request header for XHTTPF_REQGET
MimicFireFox | False | If true, headers are added to XHTTPF_REQGET calls to mimic those used by FireFox
MimicIE | False | If true, headers are added XHTTPF_REQGET to mimic those used by Internet Explorer
ReadTimeout | 75 | Time in seconds to wait while reading the response from the server before timing out.
ConnectTimeout | 30 | Time in seconds to wait for the connection to be established before timing out

Comments

BasicAuth: Basic Authentication is one of many types of HTTP authentication, but it is often considered a security risk because the name and password are transmitted in plain text. For an SSL/TSL connection, this may be ok, but in any case, the default is set to False just to err on the safe side.

SslAllowedCiphers: To limit SSL/TLS connections to a more specific set of possible ciphers, specify one or more of the following (comma-delimited). You may also use the special value "best-practices" to request "current best practices". Currently this means the following, but may evolve over time:

• Any RSA keys must be 1024 bits or more

• All renegotiations must be secure

• All ciphers using RC4, DES or 3DES are disallowed

Available ciphers

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 | TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 | TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA256 | TLS_RSA_WITH_AES_256_GCM_SHA384 | TLS_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 | TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 | TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA256 | TLS_RSA_WITH_AES_128_GCM_SHA256 | TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA | TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_RSA_WITH_RC4_128_SHA | TLS_RSA_WITH_RC4_128_SHA | TLS_RSA_WITH_RC4_128_MD5
TLS_DHE_RSA_WITH_DES_CBC_SHA | TLS_RSA_WITH_DES_CBC_SHA |

History

2016 November, October, A-Shell 1535: Replaced old parameter certfile with new parameter properties and much expanded its usage.


ATE

To access this function from a server (connected to by an ATE client), you can use the SOSLIB wrapper routine ATHTTP.SBX. It uses essentially the same calling format (limited, however, to the file mode operations), but handles the communication and data transfers between the server and the ATE client. Note that unlike the normal case (local Windows), the filenames in the request and response parameters here will be converted, if necessary, from AMOS to server-relative native format. Only one filename may be specified in the request parameter, and if using the content-type prefix, ATHTTP.SBX 1.0(102) or higher is required. See the ATHTTP.BP source code in [907,33] for further details, and the HTTP1.BP sample program in [908,25] for an example of calling it.


Setting attributes for uploaded files

When using the XHTTPF_REQUPLOAD flag to upload files, the generated request will contain a header for each file, specifying a content-type and name attribute. For example, if request = "myfile.qry", the generated header will look something like:

Content-Disposition: form-data; name="file"; filename="myfile.qry"

Content-Type: application/octet-stream

The filename attribute (set to "myfile.qry" here) may not be changed, but shouldn't be a problem as it matches the normal format used by the standard HTML form type for file uploads. The name attribute ("file" in this default case) is arbitrary; in most cases the server will ignore it, but in some cases (when more than one file or file type is being uploaded) it may be used to communicate to the server the nature or meaning of the file. The Content-Type header is automatically determined based on some simple heuristics involving the file extension. In cases where the default name and Content-Type values are not acceptable to the server, as of ashnet.dll 1.4(129) you can specify them by inserting, in front of each filename, a prefix of the form "Content-Type=<type>|<name>=" where <type> is the desired content-type, and <name> is the desired value of the 'name' attribute. For example, if:

request = "Content-Type: text/html|queryfile=myfile.qry"

the generated header would look like:

Content-Disposition: form-data; name="queryfile"; filename="myfile.qry"

Content-Type: text/html


Customizing POST headers

By itself, the XHTTPF_REQPOST flag will generate a standard set of headers to accompany the specified request, e.g.:

POST /my/web/service HTTP/1.1

Host: mydomain.com

Content-Type: text/plain; charset="ansi"

Content-Length: 84

<body of request here>

But let's suppose you don't like the auto-generated Content-Type, and want to add your own Authorization line. You can do this by modifying your request file (we're assuming XHTTPF_FILEREQ) to add the desired headers at top, separated from your request body by a blank line, and then add the XHTTPF_HDRBODY flag. (Note: this is a slightly different situation than the previous example using XHTTPF_REQUPLOAD; in that case the Content-Type and name header for the individually uploaded files could be addressed via special syntax in the request parameter. In this case we are changing the main header for the entire request.) For example:

Content-Type: application/json; charset=utf-8

Authorization: Basic YWdlYmFwaTpCN2VyQDhhYw==

<body of request here>

Submitting the above file, using XHTTPF_REQPOST + XHTTPF_HDRBODY + XHTTPF_FILEREQ would result in the auto-generated Content-Type line being changed to the one specified in our request file, and the Authorization line we specified being added, as follows:

POST /my/web/service HTTP/1.1

Host: mydomain.com

Content-Type: application/json; charset="utf-8"

Authorization: Basic YWdlYmFwaTpCN2VyQDhhYw==

Content-Length: 84

<body of request here>


Customizing REQUPLOAD Headers

Added June 2013

(The following applies beginning with A-Shell 6.0.1261 and ashnet.dll 1.4.132 of October Oct 2012)

You can modify the default Content-Type and Content-Disposition headers that would otherwise be generated when uploading files using the XHTTPF_REQUPLOAD+XHTTPF_REQFILE flags, by prepending a control sequence prefix on the front of each filepsec in the filespec list specified in the request parameter. The format of the prefix is:

Content-Type=<type>|<name>=

where <type> may be any content-type string, known or unknown, and <name> is the value of the "name" attribute to be associated with the file. For example:

request$ = "Content-Type=text/html|homepage=c:\temp\mypage.txt"

In the above case, the header associated with the file in the request would look something like:

Content-Disposition: form-data; name="homepage"; filename="mypage.txt"

Content-Type: text/html

To upload multiple files in a single request, just separate them in the request string by separating them with semicolons. Any filename which does not start with the "Content-Type" prefix will be treated as before, with the Content-Type being set according to the file extension, and the name attribute set to "file" (,"file2", etc.)


SOAP Example

Added June 2013

SOAP requests may be formed by combining an XML-format document (based on the requirements for the web service as defined in the WSDL for the service) with a set of HTTP binding headers. The technique is essentially the same as described in Customizing POST headers, except that the Content-Type may be different and typically you will be adding a SOAPAction header. The following is a an example of a real web service (as of June 2013) provided by WebserviceX.NET which returns details about airports based on the airport code. The format of the XML request document is as follows:

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<getAirportInformationByAirportCode xmlns="http://www.webserviceX.NET">

<airportCode>$AIRPORTCODE$</airportCode>

</getAirportInformationByAirportCode>

</soap:Body>

</soap:Envelope>

To generate an actual request, we copy the above into a file, replacing the $AIRPORTCODE$ with the actual code (see CGIUTL for one technique to simply such replacements). In order to specify the desired Content-Type and the SOAPAction header, we insert it at the top of our file, followed by a blank line and then the XML request:

Content-Type: text/xml; charset=utf-8

SOAPAction: "http://www.webserviceX.NET/getAirportInformationByAirportCode"

<xml doc here>

Assuming that our generated request file is called "airport.req", we can then call the web service as follows:

flags = XHTTPF_REQPOST ! POST request (typical for SOAP)

flags = flags or XHTTPF_FILEREQ or XHTTPF_FILERESP ! request and response are both filespecs

flags = flags or XHTTPF_HDRBODY ! request body contains header lines

url = "http://www.webserviceX.NET/airport.asmx"

xcall HTTP, 1, status, flags, url, "airport.req", "airport.rsp"

To examine the final headers as sent to the service, add the XHTTPF_DEBUG flag and then check the resulting DEBUG.REQ file, which should look something like:

POST /airport.asmx HTTP/1.1

Host: www.webservicex.net

Content-Type: text/xml; charset="utf-8"

SOAPAction: "http://www.webserviceX.NET/getAirportInformationByAirportCode"

Content-Length: 418

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<getAirportInformationByAirportCode xmlns="http://www.webserviceX.NET">

<airportCode>LAX</airportCode>

</getAirportInformationByAirportCode>

</soap:Body>

</soap:Envelope>

Note that the POST, Host:, and Content-Length headers are added automatically, but the Content-Type and SOAPAction headers are copied from the request file.

The complete program demonstrating this service, airport.bp, can be found in the EXLIB.


Debugging

These kinds of web service transactions can be difficult to debug, because you are usually dealing with multiple layers of separation between your app and the web server that is generating cryptic errors over unidentified minutiae. Fortunately, these web service transactions can be reduced to simple streams of text. You send it some text and, assuming you can connect at all, it sends some text back. So debugging almost always starts with obtaining copies of the details of the request and response so that you can compare them to samples provided by the web service, or send to their tech support people to ask for guidance.

To obtain this debugging information, set the XHTTPF_DEBUG flag, repeat your request, and then examine the following files:

• DEBUG.REQ - a copy of the full request, including the generated headers

• ASHNET.LOG - summary details about the connection, port, protocol, and return status will be appended here

• <response file> - assuming you get a response, and have the XHTTPF_FILERESP flag set, the response will be in the file specified by the response parameter.

• DEBUG.LE - for lower level failures (like a failure to connect at all), details possibly of interest to MicroSabio will be written here

• DEBUG.LOG - contains internal details of the operation, plus a transcript of what was sent and received over the wire.

Often you will find that there are differences between the generated headers of your request and those provided in the web service's specifications or samples, in which case you will need to determine whether they are significant, and if so, how to achieve the necessary changes. In some cases of POST transactions, you will be able to use the technique described above (Customizing POST headers). In other cases, you may want to tinker with some of the flags, such as adding XHTTPF_SETFROMURL or changing between XHTTPF_REQUPLOAD and XHTTPF_REQPOST, to see what effect it has on the generated request. If you know what the request should look like, but don't know how to generate it, please contact us with the above details.

An all-too-common scenario is that the web service has cryptic specifications, no sample request documents to model your request on, and the tech support people point you to some utility, tool or web page that works, for you to use as a model. Unless the tool provides a copy of the request text that it generates, and assuming you can run the test in plain HTTP (not HTTPS) you can use a packet sniffing tool, such as WireShark, to capture the raw message and then use it as your model. If the target service uses a secure port, that technique won't help you, but you may want to inquire whether they have a parallel non-secure sample or test version of the service which you can use to debug the basic request format.


Retrieving HTTP status text

In cases where the routine succeeds in connecting to the server, the status parameter will return the numeric HTTP status code, which is generally sufficient, along with the body of the response, to determine if the operation was a logical success. In some cases however, the HTTP status code may be ambiguous, and the server may augment it with a non-obvious text message returned on the HTTP status line (rather than something more formal/detailed returned as the body of the response). You can retrieve that status string by making a second XCALL HTTP call following the initial one. The example below illustrates a case where upon receiving status 400 (bad request), we retrieve the HTTP status string, which hopefully contains some further detail helping clarify what is bad about the request, such as "unrecognized part number format:"

xcall HTTP, 1, status, flags, url$, request$, response$

if status = 400 then

xcall HTTP, 1, status, XHTTPF_GETSTSTXT, "", "", status'text$

endif

Note that the HTTP status text may also be found at the end of the ASHNET.LOG entry if the XHTTPF_DEBUG flag is set.


IDTIM

xcall IDTIM, stringfmt, idate, itime, flags, status

IDTIM.SBR converts a string format date and/or time into so called internal format. (Internal format dates are also referred to as separated format, and is the format returned by the DATE system function. Internal format time is simply the number of seconds since midnight.) The inverse function is ODTIM, which see for converts an converting internal format date and/or time to a string format.

Parameters

stringfmt

should be set to the date and/or time be converted, with the time following the date (with a space separator) if both date and time are included. (Also see flags parameter, which indicates if date and/or time are present.) The date, if present, should be in MM-DD-{CC}YY or DD-MM-{CC}YY format, depending on your language definition file specification for date order. The separator character, however, need not be a dash or even match the language definition file; it can be any non-numeric character. The time format is HH:MM{:SS} {AM/PM}. Legal examples would be:

12/30/07 13:01

01-01-2007 10:15:33 PM

23:01:10

05.03.1915

If only two digits are specified for the year, it is assumed to be in the twentieth century (19xx) unless the SBR=CCYY:## parameter is included in the miame.ini, in which case it will determine the YY cutoff below which we assume 20xx instead of 19xx.

idate (F,6)

will return the internal format date, or zero if the date is not included in the input string. Note, however, that to access the individual separated fields within it, you need to assign the F,6 value to a B,4 which is mapped on top of the separated date structure, as in the following example:

MAP1 Sepdate

MAP2 Mon,B,1 ! Month 1-12

MAP2 Day,B,1 ! Day 1-31

MAP2 Yr,B,1 ! Year-1900

MAP2 Dow,B,1 ! Day of week (0=Mon, 6=Sun)

MAP1 Bdate,B,4,@Sepdate ! B,4 version of Sepdate, as used by

! the DATE system function

MAP1 Idate,F,6 ! F,6 version as needed by IDTIM

xcall IDTIM, StringFmt, Idate, Itime, Flags, Status

Bdate = Idate

Print "Separated date: ";Mon;Day;Yr;Dow

Bdate = DATE ! Get today's date (for comparison)

Print "Today's separated date: ";Mon;Day;Yr;Dow

itime (F,6)

will return the internal format time (i.e. seconds since midnight) or zero if the time is not present.

flags (Num)

should be set to 0 to process both the date and time; 1 if the string is expected to contain only the time, and 2 if it is expected to contain only the date.

status (F,6)

will return a code of 0 to indicate a successful conversion, or –1 to indicate an error (such as an invalid format or invalid date).

History

2011 September, A-Shell 5.1.1232: Flag +4 allows the hh value to be greater than 24. Mainly useful for verifying validity of an elapsed number of hours. The returned internal time will still be just the seconds since the last midnight.


IMAGE

xcall IMAGE, opcode, handle, status {,params...}

Aside from the difference in calling syntax, IMAGE is nearly identical to the subroutine AUI_IMAGE, which see for full documentation. It is normally preferable to use AUI_IMAGE rather than IMAGE.SBR because AUI_IMAGE supports ATE while IMAGE.SBR is only implemented under Windows.


INCOM

xcall INCOM, name, packet, opcode, stpos, length, status

INCOM.SBR is a variation of COMMON, allowing you to read and write a packet of information in memory, generally for the purpose of passing information between programs run in sequence on one job.

Parameters

name (String ,10)

name.ext of module. Note that only the first six characters will be used.

packet (Any type, 1 to 1024 bytes)

Packet to read or write. You must use the SBR=MSGSIZ:# parameter in miame.ini to set the necessary maximum packet length if your packet variable will be longer than the default 150 bytes.

opcode (Num) [in]

0 to read, 1 to write

stpos (Num) [in]

position of first byte in packet.

length (Num) [in]

number of bytes to read or write

status [out]

1 for success, otherwise 0

Comments

The AMOS version of this routine used a memory module that was loaded into system or user memory. The A-Shell version, on the other hand, actually uses COMMON.SBR (which has been enhanced in A-Shell to support many variations), and thus there does not need to be an associated file on disk or even a memory module. The name parameter, however, is needed to identify the packet within COMMON, but any extension will be ignored.

The main differences between INCOM.SBR and COMMON.SBR are that INCOM.SBR allows you to read/write an arbitrary subset of the packet (rather than the whole packet) and that the INCOM read operation is always non-destructive (whereas COMMON’s read is normally destructive but can be overridden by the SBR=COMMONNDR switch in miame.ini).


INFLD

xcall INFLD, row, col, xmax, xmin, type, entry, inxctl, parentid, opcode, exitcode, timer, cmdflg, defpt, maxpt, funmap, setdef, infclr, hlpidx, maxchrs

INFLD is a powerful and flexible field-level input and display routine, operating in both text and GUI modes. In GUI mode, it takes on the form of a edit control, combo box, date/time picker, or up/down (spinner) control, depending on the parameter options. INFLD's GUI mode is generally application-compatible with text mode, but of course requires either A-Shell/Windows or ATE. INFLD is also used internally to implement the A-Shell dot-prompt, the VUE command line, and INMEMO.

History/compatibility note: Originally developed as an upward-compatible replacement for the native AMOS subroutine INPUT.SBR, INFLD was sold as a standalone product under AMOS. The A-Shell implementation is upward compatible with the AMOS version, but adds many additional capabilities, most notably the GUI extensions.

Parameters

Parameter | Type | I/O | Description
row | Num | in | Row for input
col | Num | in | Starting column.
xmax | Num | in | Maximum size (width; see maxchrs).
xmin | Num | in | Minimum number of characters to accept. Note that if the O (optional) type code is used, the minimum is only in effect if at least one printable character is entered.
type | String | in | Codes specifying types, formats, etc.
entry | String | in/out | String field contents sent and returned in
inxctl | → | out | (String,1 or F,6) Special exit codes compatibile with INPUT.SBR
Parameters above are required; those below are optional.
parentid | → | in | (String or Num) If zero, multiplies (row) by two
opcode | Num | in | Used to specify pre-load, output, other options
exitcode | F,6 | out | Extended exit codes (how field exited)
timer | F,6 | in/out | Used to specify time-out duration
cmdflg | Num | in | Controls whether command file input allowed
defpt | Num | in | Specifies default decimal point
maxpt | Num | in | Specifies maximum digits to right of decimal
funmap | Num | in | Controls interpretation of function keys
setdef | String | in | Defines list or set of allowable inputs
infclr | → | in | (Structure or 0) Color specifications
hlpidx | String | in | Various expansion features
maxchrs | Num | in | Maximum number of characters allowed (independent of xmax)


row

row specifies the starting row of the field . Note that if the parentid is missing or is numeric and evaluates to 0, the row is multiplied by 2. (Historians differ on the exact origin of this unusual feature, but we believe it arose during the epochal moment when display terminals suddenly increased from 12 to 24 display lines.)

You can also specify row relative to the bottom of the screen (determined dynamically from the terminal driver at runtime) by using a negative number: -1 = the bottom row, -3 = third row up from the bottom, etc.

If you set both row and col to zero, INFLD will operate in position-relative mode, starting from where the cursor was when you called INFLD. (This is similar to how BASIC INPUT works.)

If row > 200, it is interpreted as Millirows , which see for more information.


col

col specifies the starting column of the field.

Right justified fields will be re-displayed so that they align in the rightmost column (as determined by col and xmax).

If col > 200, it is interpreted as Millicolumns, which see for more information.


xmax

Updated June 2012; see History

xmax specifies the editing (or display) width of the field. Unless maxchrs is set to another non-zero value, xmax is also equivalent to the maximum number of characters which can be entered. Additional GUI-related attributes may be specified via the ST_INFXMAX structure; see below.

In text mode (with a non-GUI-enabled terminal emulation), the field width will be indicated by marker characters (typically underlines, unless type |p or type i or type I is specified). In text mode with a GUI enabled emulation (i.e. PCTDVG, AM76G or AM62CG), a pseudo-Windows-style sunken panel is used. (This may be hard to see unless the background color is pastel or gray; if not, you may want to force the use of underlines with type |_ .)

In full GUI mode (GUI-enabled driver, type |G), the field size will be indicated by the size of the Windows control (edit box, combo box, checkbox, radio button, time/date, up/down) used. The overall width of the control, however, may be somewhat larger than the number of grid width units specified, in order to allow for parts of the control outside of the input area (like drop-down buttons), or, when xmax is very small, to allow for the fact that upper case GUI characters may be wider than their text equivalents. See type ||] to disable this auto-expansion feature.

ST_INFXMAX

The ST_INFXMAX structure may be used in place of the XMAX parameter to specify additional GUI-related attributes not previously available via the INFLD interface but otherwise available with AUI_CONTROL.

defstruct ST_INFXMAX

map2 erow,b,4 ! rows, millirows or pixels

map2 ecol,b,4 ! columns, millicolumns, or pixels

map2 flags,b,4 ! see IMXF_xxx below

map2 fontattr,b,4 ! same as in AUI_CONTROL

map2 fontscale,b,4 ! " " "

map2 fontface,s,32 ! " " "

endstruct

define IMXF_FNTPTSIZE = &h00000001 ! fontscale is in points*10

define IMXF_PIXCOORDS = &h00000002 ! all coordinates in pixels [101]

define IMXF_XMAXONLY = &h40000000 ! erow=xmax; all other fields ignored

A structure definition include file, ashinc:INFLD.SDF defines the ST_INFXMAX structure.

Notes

• Minus signs in numeric fields do not count against the maximum number of characters.

• The specified xmax value may be trimmed by INFLD to be no greater than the physical size of the entry parameter. One situation where this can be unexpected is when using Coded Lists.

• When using pixel coordinates, INFLD checks that MAXCHRS <> 0, since otherwise there is no way to determine the character limits on the field size. If 0, it displays a warning message and sets it to 132.

History

2012 June, A-Shell 6.1.1312: ST_INFXMAX structure added


type

BE SURE to add new codes to (a) their own table, and (b) the consolidated table at end.

type is a string containing a sensible combination of the codes listed in the following sections. Note the following:

• Case is significant.

• The codes are generally additive, and you can use as many as you want. For example, specifying both the codes for alphabetic and numeric types will result in an alphanumeric field.

• The codes many be either single-character codes, or double or even triple character codes. All of the double-character codes begin with the lead-in character | (vertical bar.) All of the triple character codes begin with a pair of vertical bars.

The codes are organized into the categories shown in the following topics. The final topic in this section, Type Codes Summary, shows all of the type codes in a single table.

Subtopics

Character Type Acceptance

Numeric Formatting Codes

Date/Time-Related Codes

LDF-Related Codes

Timer-related Codes

GUI-related Codes

Miscellaneous Codes

Exit Key Enabling Codes

Type Codes Summary


Character Type Acceptance

You must have at least one of these. Note that a blank in the first character position of type is treated like an A to maintain compatibility with an AlphaAccounting quirk.

Value | Description
# | (number sign) Numeric (0-9). If nothing entered, displays a "0" (but returns just a blank string.) Also see N.
$ | (dollar sign) Currency field.
* | (asterisk) Accept all characters. Same as A.
, | (comma) Punctuation allowed. Punctuation is anything other than a number or letter.
@ | (at sign) Control character input.
{ | (open brace) Character acceptance is limited to the set of characters specified in setdef. (Typically you would combine this with "*", else the characters may be rejected before even considering the setdef list.
a | Alphabetic characters allowed (a-z, A-Z), or as defined by the LDF (language definition file).
A | All characters allowed (subject to code b). Note that A is used for compatibility with INPUT, but to most people, "*" makes more sense. Note that A or "*" is equivalent to the combination "a#," (alphabetic, numeric, and punctuation).
C | Carriage Return only
d | Date input, today.
D | Date input.
H | Hours field. Like $ but omits the "$" from the display.
||h | Accept hexadecimal digits (A-F, a-f, 0-9).
J | Accepts alphanumeric input, and if the input is wholly numeric, right justifies and fills with leading zeroes.
N | NO/Yes field.
P | Phone number or zip code input.
t | Time field.
U | European date.
X | Specifies a Y/N field, but with no default. May be used to force the operator to make a choice, or, with xmin=0, to allow a third option (blank).
Y | YES/No field.


Control character input

[ Type code = @ ] Works as a "fast" field to return the first n characters typed (where n is the value of xmin) , whether control characters or not. The only character you cannot retrieve this way is Ctrl+C. (You can trap that with "ON ERROR GOTO" or by using the V code.) Ordinarily you should specify a minimum of 0 or 1 for this to return a single control character properly. Also note that this code over-rides all other codes (where conflicting). See codes C and <.

Note that function keys will only return the first byte of the sequence (typically ASCII 7). However, as of A-Shell 5.1.1115.4 of 6 June 08, they will also set the exitcode parameter as expected for other field types.


Currency field

[ Type code = $ ] Redisplays as "$$###,###,###.##". If "." (period) code not used, displays with last 2 digits entered to the right of the decimal point. Otherwise inserts ".00" after the number entered (if hard decimal not entered) or simply formats the cents as ".#Z" (if hard decimal entered). Default decimal position and number of digits past the decimal point are adjustable with the maxpt and defpt parameters. Currency symbol is determined by the applicable Language Definition File (LDF). Note that the symbol may be one or two characters, with or without a space between it and the number, and it may appear before or after the number, depending on the LDF parameters. Also note that by setting defpt = -2, you can eliminate the decimal point and cents (for handling currency in whole numbers).


NO/Yes field

[ Type code = N ] When following a Y code, specifies a Yes/No field with "N" default (and pre-display). Otherwise, like # but does not display a "0" if nothing entered or supplied, and does display one blank after the marker characters. This is a useful alternative to the # code when the screen may be cluttered by the display of many fields containing 0 (e.g. "0", "0.00", "$0", etc. (See "B" to display the blanking.)


Phone number or zip code input

[ Type code = P ] If xmax = 7 or 10, specifies phone number and allows alpha and numeric entry. Must be either 0, 7 or 10 characters. Redisplayed as "(###) ###-####" with the area code omitted if only 7 digits entered. If xmax = 5 or 9, specifies zip code and allows numeric entry only. Must be either 0, 5 or 9 characters. Redisplayed as "#####-####", with the dash and last 4 digits used only if more than 5 digits entered. Note that this field ignores the language definition file, since there is no guarantee that the phone # or zip being entered actually belongs to the language of the current user. One solution is to prompt for the country first, and then if it is not USA, use alternate type codes for zip and phone.


YES/No field

[ Type code = Y ] Default to (and pre-display as) "Y", unless followed by a N code, or followed exclusively by an E or T code. (This is to maintain compatibility with INPUT's YE and YT.) The keyboard character "1" is interpreted as (and converted to) "Y" and "0" as "N" in Yes/No fields. (Note that the English "Y" and "N" abbreviations may be changed by the language definition file (LDF) to more appropriate ones for the local language.)

See the GUI-related Codes topic for information on converting a Yes/No field to a checkbox.


setdef qualifier

Indicates that setdef contains a list of all the allowable characters. To be accepted, input characters must first pass the normal type code acceptance rules, and then must be listed within the setdef string. Consequently, to use setdef exclusively to specify the allowable characters, combine { and A type codes. Note that upper and lower case is significant when setdef is used this way. See the setdef topic.


Numeric Formatting Codes

Except for "-" and ".", the formatting and miscellaneous codes do not affect the characters which can be entered; rather, they only affect the way the characters are formatted. Note that unless otherwise indicated, formatting codes only affect the way a field is displayed on the screen and not how it is returned to the calling program.

Value | Description
- | (hyphen) Allow minus sign.
. | (period) Allow decimal point.
$ | (dollar sign) Currency field.
G | May be useful for aligning decimal points in column of variable precision numbers.
H | Hours field. Like $ but omits the "$" from the display.
M | Thousands separator.
R | Right justify field.
u | LDF-Related Codes.
v | Value range checking.
Z | Zero fill.


Allow decimal point

Updated and reviewed January 2011

[ Type code = . ] If used with $ or H type and the decimal point is not entered, places the decimal point to right of last digit entered. For example, if "1234" is entered, it will be redisplayed as "1,234.00". Note that this code affects the action of the opcode parameter. When decimal points are allowed, default decimal points are inserted as actual characters into the returned field. If decimal points are not allowed, default decimal points are inserted in the display but not returned.

Note: prior to 5.1.1199, INFLD always used the "." character for the decimal point, regardless of the LDF (Language Definition File). As of 5.1.1199, you can add the TYPE code "u" to force it to use the decimal point character specified in the LDF. Note that even in the latter case, it will accept a "." from the keyboard as equivalent to the defined decimal point character.

See Also

• defpt, to set the position of a default decimal point.

• maxpt, to limit the number of digits past the decimal point.


Allow minus sign

[ Type code = - ] May be typed anywhere in the field, but is always displayed (during entry) to the left of the field. On exit, it is redisplayed as a trailing minus sign (for codes $, H, M), and relocated to the beginning for the returned variable. For example, if "1234-" is entered, it will be redisplayed as "12.34-" (assuming decimal points are not allowed) and returned to the calling program as "-1234."

Force leading minus sign: Force leading minus sign display format when used with $, H or M fields. (Normally these use trailing minus sign display format.) Also note that this only affects the final display to the field; the minus sign is always displayed during field editing at the front, and always returned in the entry parameter in leading format.


Thousands separator

[ Type code = M ] Triggers a numeric thousands separator between every 3 digits to the left of the decimal point in the final redisplay of the field. The actual character used is defined in the language definition table (comma for the USA table). (This is automatic for $ and H fields.)


Right justify field

[ Type code = R ] Note that unlike most formatting codes, right justify (and zero fill) actually affect the way the field is returned as well as the way it is displayed. Additionally, whenever you preload a field using the R or Z codes, INFLD will automatically strip the leading fill characters prior to the initial display to simply editing.


Value range checking

[ Type code = v ] setdef parameter must be loaded with a string of the format ",min,max,," where min is the minimum acceptable value and max is the maximum acceptable value. See setdef for more info on proper formatting of range strings. Note that you will probably want to use code s along with v to stifle the "Choices:" message which otherwise appears on the bottom line when setdef is non null..


Zero fill

Updated January 2011

[ Type code = Z ] Enough leading zeroes will be added to fill the field to the xmax size. Note that unlike most INFLD formatting options, the leading zeroes are actually returned in the field. On preloading a Z field, the leading zeroes are removed prior to editing, except that if the field is blank, one zero is left.

History

2011 January, A-Shell 5.1.1200: INFLD refinement: When using TYPE Z (zero fill), leading zeroes are no longer stripped on entering the field for date fields or form fields. Stripping the leading zeroes in such cases may mess up the alignment of the form or the interpretation of the individual digits in the date.


Date/Time-Related Codes

Updated February 2011

The following table shows the codes related to date and time fields. Note that determination of whether a date field will return the full century (CCYY), rather than just the year (YY), is determined by the larger of maxchrs and xmax.

Value | Description
> | (greater than) Convert date format.
d | Date input, today.
D | Date input.
|D | Defaults century to 19xx. Applies for date formats which allow user to enter only the YY. If not specified, century default is determined by the SBR=CCYY:## entry in the miame.ini file.
||D | Allows a date field to be filled with zeroes.
|d | Allow date shortcuts.
|h | HexaDecade Dates (2).
H | Hours field. Like $ but omits the "$" from the display.
|H | HexaDecade Dates (1).
j | Julian date format.
t | Time field.
th | Same as "t" but allows hh > 24. Not supported in the Windows date control, i.e. not compatible with TYPE "|G" (use "|g" instead).
||t | Same as t (time) but in GUI mode returns the time in 12-hour format rather than 24 hour format.
u | LDF-Related Codes.
U | European date.
||u | May be used with the D, d, t, and YN codes to ignore the current LDF settings and just use the (American) defaults. Without this, the LDF format was used, even in the absence of the "u" code.

History

2011 January, A-Shell 5.1.1200: INFLD enhancement: date fields (except for the GUI date picker) can now use a "form" (TYPE "f", SETDEF set to something like "99/99/99"). This provides a sort of middle way between the Windows date picker control (which some people don't like), and a standard date field (in which the separators don't appear until after hitting Enter).


Date input

[ Type code = D ] Format will be determined by the combination of xmax, the u and U codes, and the language definition file. The possibilities are: xmax=6 (MMDDYY or DDMMYY); xmax=8 (MMDDYYYY or DDMMYYYY). INFLD forces the entry to be a valid date. See > code (for swapping the year up front), U (European format), u (force language definition file format) and setdef parameter description (for date range checking). See the GUI-related Codes topic for information on using a Windows-style date picker control.


Date input, today

[ Type code = d ] If neither D, U, nor u code used, assumes MMDDYY format, otherwise uses format as specified by D or U codes. See > code and setdef topic. Note that the pre-load feature only works if the entry field is empty.


European date

[ Type code = U ] Like D but forces European format (DD digits in front of the MM digits).

See Also

• Type > (Convert date format)

• setdef parameter description


Convert date format

[ Type code = > ] Converts from YYMMDD format (for internal storage) to either MMDDYY or DDMMYY (depending on use of D, U or u codes) for display and input. Note that this conversion will take place on both input and output, so if you want to preload a date field (see opcode parameter), it should be supplied in YYMMDD format, and INFLD will also return the date in that format (no matter what the input/display format was.)


Allow date shortcuts

The combination |d (vertical bar, lower case d) causes INFLD to allow the use of date shortcuts even if the xmin value has not yet been satisfied. Otherwise, you must first enter the number of digits required by xmin before any shortcuts can be used. To review, date shortcuts allow you to enter between 1 and 4 digits and when you hit Return, INFLD fills in the remaining ones based on guessing. For one or two digits, it assumes they are the day of the current month. For three or four, it assumes they are the month and day (or day and month for European format.)


HexaDecade Dates (1)

When the combination |H (vertical bar, H) is used in conjunction with any Date code, causes the editing format to be automatically expanded from 6 digits to 8 digits (to accommodate the century.) However, on return (and on pre-load) the field is converted to/from 6 digit "HexaDecade" format. In "HexaDecade" format, years past 99 are encoded using one hex digit followed by one decimal digit. For example, year 100 (e.g. 2000) would be "A0", year 105 (e.g. 2005) would be "A5", year 111 (e.g. 2011) would be "B1", etc. The advantage of this system is that it eliminates the need to expand existing date fields from 6 to 8 bytes, yet preserves sort order. It does, however, require that you deal with converting from "HexaDecade" format to "normal" format for printing and other display purposes. (Fortunately, this would typically be a matter of cosmetics rather than processing accuracy, although you may need to also watch out for any mathematical operations on dates.)

Note: Setting OPTIONS=HEXDEC may take care of most or all of the display, printing, and math issues as well. Refer to the A-Shell User’s Guide for more details.


HexaDecade Dates (2)

Using |h has the same effect as |H but does not expand the field to 8 digits for editing. Instead, it "guesses" at the century. If no other hints given, it will guess 20xx for xx < 60 and 19xx for xx > 60. If you specify |D it always assumes 19xx.

Note: You may use SBR=CCYY:## to change the YY cutoff for assuming 19xx vs. 20xx to ## (instead of 60.)


Julian date format

[ Type code = j ] Convert dates to Julian format (for internal storage). May be used in combination with the D, d, or u codes, although if used by itself it will be treated as the combination Dj. Note that the entry parameter must be a string of at least 6 bytes which will hold the string representation of the Julian date value; it may then be assigned to a 2 or 3 byte binary number for more compact storage if desired.


Time field

Updated and reviewed January 2011

[ Type code = t ] (HH:MM:SS {A/PM}). INFLD supplies the separator characters (: for the USA Language Definition File) as needed to simplify data entry, and forces a legal time format (within the limits imposed by the xmin and xmax parameters). See GUI-related Codes for information on using a Windows-style time-picker control.

In text mode, field is accepted without editing or formatting, but INFLD will require that the field be in legal time format before exiting.

In GUI mode (|G but not |g), the field becomes a time picker control. Field is returned in military (24 hour) format, unless type ||t specified. xmax will determine whether the returned format is HH:MM {A/PM} or HH:MM:SS {A/PM}.


LDF-Related Codes

Type u (LDF-Controlled Format) and ||u (ignore LDF) have varying effects on dates, times, Y/N and numeric fields whose format options may vary based on the Language Definition File (LDF). Note that unlike most type codes which act independent of the order they appear in, u and ||u must generally precede the associated type codes.

For date fields (D, d, and U), u has no effect. The D and d date fields use the LDF format by default, and the European date (U) fields always use the European format. The only LDF-related option here is to precede the D or d with ||u to force the American format even when the LDF specifies European format. (That could be a useful workaround for running a USA-developed app, which assumed American date format, in some other part of the world.) Note that a good strategy for avoiding confusion within an application related to differing date formats is to always add the > code to force {CC}YYMMDD format internally, regardless of the display and edit format. Also note that in a GUI environment where a date-specific control (such as a calendar control) is being used, the edit/display format will generally be determined by the regional settings of the client PC (making the > option even more important.)

For Y/N fields, the affirmative and negative characters are determined by the LDF, unless you precede the type Y or YN with ||u, in which case it will use "Y" and no "N". In the GUI environment, you may want to use type ||c to convert your Y/N fields to checkboxes (which avoids all language and regional confusion).

For numeric fields (#, H, $), u forces INFLD to use the decimal point and thousands separator characters specified in the LDF, rather than the USA default characters ("." and "," respectively). In this case, the u does not have to precede the numeric type code.

Note that this will only have an effect if the field would otherwise allow entry or display of decimals and thousands separators. See type codes . (period), M, $, H as well as the defpt and maxpt parameters.

See Also

The system parameter Language for establishing the LDF, and GTLANG for how to query it.


Timer-related Codes

These codes allow variations on the field time-out behavior. Note that except for the "!" code, all of the remainder have no effect unless the timer parameter is specified and is non-zero.

Value | Description
! | (exclamation point) Activate return of elapsed time during input. This is only applicable when the timer parameter is specified. Note that this can be used even if time-out is not specified (by setting timer=0).
/ | (slash) Disable the timer-related messages that normally appear on the bottom line, such as "timing out", except for the time remaining clock. Combine with "+" to eliminate all of the timer displays.
+ | (plus sign) Disable display of time remaining (on bottom line). Normally, the time remaining until time-out is displayed (and updated every second) on the bottom right corner of the screen.
Q | Disable time-out suspend feature. (Normally, the operator can suspend the time-out counter for 10 minutes by hitting Ctrl+S. Suspending the timer is useful when you have to temporarily interrupt data entry, as when answering the phone.) Note: Under A-Shell, Ctrl+B is the suspend key.
r | Time out reminder. This is similar in motivation to the w code, except that it just causes a single beep, without any message, after 10 seconds have elapsed (when the timer option is active.)
|t | Reset timer to the initial value after every keystroke.
|T | Overrides timer parameter to zero. Useful for disabling timer globally in programs that otherwise use it (by putting this in the SBR=INFDEF: string.)
w | Timer wake up warning. When added to any set of timer related codes, causes a warning beep and message when only 10 seconds remain on the timer. The message blinks TIMING OUT in the lower right corner of the screen, and any key hit during the remaining 10 seconds resets the timer to the original value. Note that w overrides / to display the warning message and suspend message as well, if invoked. See r


GUI-related Codes

These codes activate various graphic user interface features within the A-Shell/Windows (or ATE) version of INFLD. Note that all of them require GUI mode to be activated with |G or |g.

Value | Description
||] | (bar bar close bracket) Prevents field width from being automatically expanded by logic that attempts to allow for the extra space needed by various GUI enhancements. For example, combo boxes smaller than six characters wide typically get an extra three characters of width to account for the space needed for the dropdown button. Similar rules apply to date and time pickers as well.
||[ | (bar bar open bracket) causes the redisplayed field to grow as needed for the contents. (This was once part of the ||] code but has been removed in order to avoid slight differences in field display widths which give such screens a ragged look.)
||a | Activate Auto-Complete mode.
||b | For checkboxes, causes the current state of the checkbox to override the normal default state (i.e. the default based on the type codes if opcode=0, or the contents of the entry parameter if opcode=1 or 2). Useful when the checkbox statement may have been changed by clicking on it outside of the awareness of the application. Same effect as cmdflg=4.
||c | Convert Y/N field to checkbox.
||C | Causes a field which would normally appear as a combo box or a date picker while editing (see setdef, dates) to also appear as a combo box when not actively being edited. Otherwise, these kinds of fields revert to static text controls when not active. See Active Versus Inactive Behavior.
|E | Causes the field to retain the form of an edit control when not active. (Otherwise, fields normally revert to static text controls when not active.) Also see ||C and Active Versus Inactive Behavior.
|f | Reserved for internal use ATE in GUI mode to control function key settings
||f | Force fixed-pitch font.
||F | Force modified fixed-pitch font.
|g | Implies |G, but limits the GUI enhancements to just the Windows-style edit box (i.e. without some of the other automatic enhancements such as date picker controls).
|G | Activate GUI enhancements.
||g | Disable/override GUI mode. (Used to temporarily cancel a global |G or ||G or |g)
||G | Same as |G except turns Y/N fields into checkboxes.
||H | Disable horizontal scrolling within control. Note that the ability to scroll is sometimes needed in order to fit all of the allowed characters, if using proportional fonts and the field consists of wider-than-normal (e.g. CAPS) characters.
||J | Right Justify Checkbox Text.
|K | Select data entry convention.
||K | Acts just like |K but also disables the Ctrl+C abort while the field is active. This allows you to use Ctrl+C for copy-to-clipboard without first having to disable Ctrl+C abort in the application. See also Ctrl+C Behavior.
|m | Prevents the Enter key, when used to select an item from the dropdown list in a combo box, from also causing the field to exit.
|M | Multi-line edit box. xmax sets the display width of the box. maxchrs sets the maximum number of characters allowed (up to a maximum of 1024). defpt is reinterpreted as the height of the box. See ||H for disabling horizontal scrolling (to enable word wrap). Enter (along with any other enabled exit key) exits. See Multi-line Edit Control (INFLD).
||m | Causes exitcode 13 to be returned when an item is selected from the dropdown list (using Enter or click) in a combo box. This allows you to distinguish that event from merely hitting Enter to the field when the dropdown is not displayed. The same effect also applies to fast mode checkboxes, allowing you to distinguish between Enter (which returns exitcode 0) and a click or other keystroke which changes the checkbox value and then exits (with exitcode 13).
||M | Variation of multi-line edit. Allows Enter to be used to manually break lines. Also, displays a vertical scroll bar.
||r | Create a radio button.
||s | Makes setdef list matching optional. Only applies to the combo box, in which case it allows the operator to enter a value that is not in the list.
||S | Variation of combo box in which typing a character only selects the nearest matching item from the list. (Otherwise the user can type independently of the list, and use Down+Arrow to find the nearest match.) See Combo Box Control (INFLD)
||U | Create up/down ("spinner") control. See Up/Down Control (INFLD).
||v | Self Service Date Picker.

Subtopics

Activate GUI enhancements

Active Versus Inactive Behavior

Convert Y/N field to checkbox

Create a radio button

Field Markers

Force fixed-pitch font

Force modified fixed-pitch font

Right Justify Checkbox Text

Select data entry convention

Self Service Date Picker

Auto-Complete


Activate GUI enhancements

|G may be added globally to make INFLD act visually more like a typical Windows control while still maintaining API compatibility with existing applications. In most cases, this simply means that it will use a Windows-style edit box. If the setdef parameter contains a list of allowed inputs, this is converted into a combo-box containing those inputs as choices. For dates, it uses a "date picker" control. For times, it uses a "time-picker" control. See Combo Box Control (INFLD), Date Picker Control (INFLD), Time Picker Control (INFLD), and Checkbox Control for examples and more details about these control types. See ||c for checkboxes and |g.

Note that by itself, |G does not force INFLD to use the standard Windows color scheme (white edit boxes with black text). Instead, it continues to use the infclr parameter for setting the color scheme. As a convenience to allow you to quickly experiment with the standard Windows color scheme without tinkering with all of your infclr settings, you can use the option in the Misc. Settings dialog to "Force standard colors in edit boxes", which overrides infclr.


Active Versus Inactive Behavior

In nearly all cases (text and GUI), INFLD fields assume a different form when active (i.e. being edited) vs. when inactive (i.e. displayed). For example, when active, the data in the field is usually stripped of formatting characters and left justified, while the field itself may be underlined or appear in a different color.

In the GUI mode, these active-vs.-inactive differences may extend to the type of control object used to contain the field. By default, an edit control (or in some cases a date picker, checkbox, combo box, etc.) is used while the field is active, and a static text control is used when the field is not active. This makes it visually obvious which field has the focus, and may discourage users from wanting to move the cursor randomly about the form by clicking. But, it is different from the "typical" Windows form, where there is often no visual change to a field between its active and inactive state, other than the presence of the cursor.

type |E and ||C may be used to achieve an effect more like the just-described "typical" Windows form. |E causes the field to appear as an edit control when inactive. This applies even to combo boxes and date pickers. ||C is similar, but applies only to combo boxes and date pickers (and time pickers), causing them to retain their drop-down button as well. (Neither applies to checkboxes, which always have the same form regardless of whether active or inactive.)

Note that when using either |E or ||C, it is imperative that the field send a mouse-click exitcode string (see hlpidx) and that your program respond to these exit codes, so that when the user clicks on such a field, the program can detect the click and retain control. Otherwise, since these control types have their own user interface (independent of your application), the user will have the impression of being able to change the field, but the program will not realize that the change has been made. (In the default case, where the field reverts to a static text control when inactive, this is not a problem, since a static text control does not offer any way for the user to directly interact with it, other than simply clicking. You can still define mouse-click exitcode strings and respond to the click by re-activating the field, but the point is that you do not have to.)

To make it more obvious to the user which input field has the focus, you can use the Active Background Color option (on the Misc Settings dialog) to define a special background color for edit boxes that have the focus, as shown below:

To configure that option under program control, see MX_WINSETTINGS.


Convert Y/N field to checkbox

[ Type code = ||c ] The text message associated with the checkbox must be placed in the setdef parameter, and the xmax parameter should be expanded to allow for the combined width of the text message (prompt or label) and the checkbox itself. Checkboxes may be toggled with the space bar, or set using the same keystrokes as for regular Y/N fields (i.e. either 1/0 for affirmative/negative, or by using the single-character affirmative/negative keys defined in the language definition file). They also return to the program the same field contents as they would have for normal Y/N fields, thus making it quite easy to convert existing Y/N fields to checkboxes.

The color of the text label associated with the checkbox is determined by the OFCLR and OBCLR fields within the infclr parameter. In Windows themed environments, you'll need to add 64 to the OFCLR/OBCLR values to override the theme color. In most cases, you should just set all of the infclr fields to -2 for maximum compatibility with the standard Windows color logic.

By default, the text label goes on the left and the checkbox itself on the right. This can be reversed with the type R (which is normally used for right justification). But in either case, the text itself is left-justified within the space allotted to it. To right justify the text within its space, add SBR=INFLDCBRJ to the miame.ini.

Checkboxes are somewhat unusual, compared to typical INFLD uses, in that a single call combines both the text prompt and the data field. If your programming style divides the functions of displaying the text prompts and the data, you may want to modify the code that previously printed the text label to use INFLD opcode 2 to display both the label and checkbox contents at the same time. Having done this, you can leave the xmax parameter for the checkbox editing call set at 1 (as it would have been for a Y/N field); INFLD will recognize that it overlays an existing checkbox control object and use the existing one.

See also Checkbox Alignment, Justification.


Create a radio button

[ Type code = ||r ] These are similar to checkboxes, but considerably trickier to use because they are must be grouped somehow since only one within a group can be set at one time. If there is only one set of radio buttons on the screen, then these form a single group. Otherwise you must use AUI_CONTROL to create a group box to contain the radio buttons. Note that because of these complexities, it is usually much easier to use a combo box to present a choice of mutually-exclusive options. (Combo boxes are easy to implement – just specify |G and use the setdef parameter to list the choices.) See Radio button Control.


Field Markers

INFLD marks the position and size of the input field in a variety of ways. In text (non-GUI) mode, the standard marker is an underline character. If the prehistoric compatibility mode is selected (|p), then the field markers will be dots. You can make the markers invisible with type I.

When a GUI-enabled terminal emulation is used (one that ends in G, such as PCTDVG or AM62CG or AM75G), by default INFLD will use a sunken panel effect to identify the position and size of the field. This effect only works well (visually) when the screen background color is somewhere in the gray or pastel zone; otherwise it may be hard to see. You can disable the sunken panel effect and force it to use the underlines instead with type |_ (vertical bar, underline).

In full GUI mode (a GUI-enabled terminal emulation and type |G specified), the field becomes a Windows control (typically an edit control, but other possibilities are up/down controls, combo boxes, checkboxes, and radio buttons), and no other field markers are needed.


Force fixed-pitch font

Updated March 2009

||f forces INFLD to use a fixed-pitch font. The result is the same as if you selected the "Use Fixed Pitch Editing Font" option in the A-Shell/Windows Misc. Settings dialog, except that it only affects this field. Fixed pitch fonts look less Windows-like, but have the advantage of making the relationship between the width of the editing box and the number of characters that can be typed more predictable.

The actual font used will be the same as the standard text mode font (whose dimensions are based on the size of the main window "grid", i.e., the main window size divided by the number of rows and columns established by Tab(-5,x) and Tab(-6,x) or by SET WIDTH and SET TERM HEIGHT or the default values of 24 row and 80 columns). Because of this, the effect works best for INFLD GUI fields embedded into text-based (or hybrid text/GUI) main window displays. ||f should not be used with ||] (prevent automatic expansion of the field), since without expanding the field width by a couple of pixels on both edges to account for the internal margins of the edit control, the actual usable width of the control may be just short of the amount needed to display the specified maximum number of characters.

See ||F (Force modified fixed-pitch font) for a variation that may work better with dialogs, especially those using the MBF_ALTPOS grid system.


Force modified fixed-pitch font

Updated March 2009

||F, like ||f (Force fixed-pitch font), forces INFLD to use a fixed-pitch font. However, unlike ||f, which uses the standard A-Shell text-mode font (based on the main window grid), ||F selects a custom fixed-pitch font based on the actual field size (as rendered into pixels based on the resolution, grid units, scale adjustments, etc) to allow the specified maximum number of characters (according to xmax) to fit in the field. ||F is generally more suitable than ||f within dialogs, particularly those based on the MBF_ALTPOS (see AUI ctype) grid, since in that environment the grid units have no particular relationship to the main window grid units, and thus the main window text font may be too big or too small for the edit control. ||F is also compatible with ||]. The main downside to ||F vs. ||f is that depending on the currently selected fixed pitch font type, the screen resolution, and limitations on the granularity of font scaling, the actual font selected at runtime may sometimes appear smaller than "ideal" (meaning that it may give the appearance that the field could accept more characters than the actual limit as set by the xmax parameter). Although this does somewhat undermine one of the objectives in using a fixed pitch font, the discrepancy is generally small, and certainly much smaller than the discrepancy that occurs with the standard proportional edit font (where the typist may hit the xmax or maxchrs limit long before filling the physical width of the control).


Right Justify Checkbox Text

||J right justifies text within a check box control. Note that for combo boxes, type R determines whether the box is on the right or left of the text, but within the text portion of the control (whichever side of the checkbox), the text would be left justified unless |J is specified. This is equivalent to (but more flexible that) SBR=INFLDCBRJ.


Select data entry convention

|K determines whether to adopt Windows or AMOS conventions related to data entry, when the two are in conflict. For example, without |K, the initial input mode is overwrite; with |K it is insert. (You can use the Insert key to toggle insert mode on and off.) Without |K, the Home key is considered a field exit key (returning exitcode 9 if type 9 is specified); with |K, Home just moves the cursor to the start of the field. With |K, Tab acts like Enter (returns exitcode 0).

In most cases where the nature of the GUI version of the control introduces the possibility of navigating within the control using keys that might otherwise have been only used as exit keys (such as up/down arrows within a drop-down list), you can use the Ctrl key in conjunction with the navigation key (e.g. Arrows, Home, etc.) to force it to act as an exit key, assuming the exit key is allowed by the type codes.

When |K (Windows keyboard mode) is NOT used, the Shift+Arrow keys work like function keys (same as they do in text mode), and will generate exitcodes based on the <tdv>.IFX translation table. The standard exitcodes for the shifted arrows are: -36, -37, -38 and -39. See FIXTRN.LIT for details on editing translation tables.

See also Ctrl+C Behavior.


Self Service Date Picker

Added March 2011

The concept is similar to the self-service combo (where you put "..." in the setdef parameter and it returns exitcode 29 when you attempt to display the drop-down), except here you activate it by adding type ||v to the date type codes. Presumably this might be useful in cases where you like the look of the edit portion of the date picker, but want to display a more specialized calendar when the user clicks the drop-down button.

See Date Picker Control (INFLD) in AUI.SBR for related information.


Auto-Complete

Updated August 2010

Auto-complete is a mechanism to help the user enter data and to speed up the data entry process. It does this by displaying a list of choices (or "suggestions") to complete the entry whenever (a) there is a pause—currently 0.5 seconds—in the user’s typing (after a change has been made to the field), or (b) the user hits the down arrow to explicitly request a list.

See Auto-Complete Illustrations for images and explanations of how auto-complete appears to the user.

Unlike most field editing scenarios which typically involve only a single call to INFLD, the Auto-Complete scenario may involve several calls. Basically, since INFLD cannot reasonably know where to find your data, nor how you would like it displayed, it returns to the application with a special exitcode (30 or 31) whenever it thinks it would be appropriate to update the list of Auto-Complete suggestions. The application is then responsible for taking the current contents of the field (from the entry parameter), building a corresponding list, and passing it back to INFLD. For example, the application code may look something like this:

setdef = "" ! typically start with an empty setdef

do

xcall INFLD, row, col, xmax, xmin, entry, inxctl, parid, opcode, exitcode, … ,setdef,…

if exitcode = 30 or exitcode = 31 then ! INFLD requests a new or longer list

setdef = <updated list data, based on the returned entry>

else

<logic dealing with any other exitcodes>

exit ! terminate the auto-completion loop

endif

loop

To activate auto-complete mode, add the following type codes: "||a)|]"

"||a" activates auto-complete mode, but in order for the re-entry process to work as expected, the ")" (re-enter at end of field) and "|]" (don't pad or strip trailing spaces) are strongly recommended.

You may also want to add ||S if you want to prevent the user from entering anything other than one of the items you supply in the dropdown list. Otherwise, the items in the list are just suggestions and don’t prevent the user from entering other values.

On re-entry (after INFLD exits with exitcode 30/31 to request a new list),the application is responsible for formatting setdef as follows:

{[widthspec]}<coldef>~<set-list>

{[widthspec]}

is an optional specification to adjust the width of the dropdown list. If not present, the dropdown list will be the same width as the field. Otherwise, the options are as follows:

widthspec | Result
+### | increase list width by ### columns
-### | increase list width by ### columns (but start ### columns to the left of the field)
### | set width to ### columns (starting in the same column as field)

<coldef>

is an XTREE-style column definition (coldef) string defining the layout of the <set-list>. In the simplest and most typical case, it would specify just one column, using Cformat S (for string), and whose width matches the width of the items in the <set-list>. (The column title is ignored.) Theoretically you can also use any of the cformat or XTREE Advanced Coldef Options that made sense for the selection list (for example, to highlight certain items), but none are typically needed. If you define more than one column (as in the city/zip example in the illustrations), then only the first visible column is actively connected to the field; any additional columns are for display purposes only (i.e., the zip code column in the above illustration).

<set-list>

is a standard setdef List of Valid Inputs, except that each entry must be the same length. (Use space padding as needed to achieve this.) Note that unless you specify the ||S type code (see above), the length of the entries in the list doesn’t have to exactly match that of the field; they just have to all be the same length. With ||S, if the list items, (or in the case of a multi-column list, the first column of the list items) does not exactly match the field width (according to maxchars), then none of the list items will be accepted by INFLD as valid inputs.

See Also

• The EXLIB sample programs INFAC1.BP and INFAC2.BP for simple working examples.

• The INFLD-GUI Auto-complete discussion on the A-Shell forum.

History

2010 August, A-Shell 5.1.1189: Many enhancements.

2010 April, A-Shell 5.1.1181: Auto-complete feature added to A-Shell.

Subtopics

Auto-Complete Variations

Auto-Complete Illustrations

Auto-Complete Examples

Auto-Complete Comments


Auto-Complete Variations

Subroutines > INFLD > INFLD Parameters > type > GUI-related Codes > Auto-Complete

Auto-Complete Variations

Reviewed August 2010

Uncoupled Mode

In the normal mode, the list is coupled to the edit control. Even though the application is responsible for supplying the data to build the list, the application only needs to communicate with INFLD. It is INFLD’s responsibility to create the list control, update it, give it the focus, capture clicks, etc. But in the uncoupled mode, the application takes charge of the list control (typically using XTREE, but theoretically anything it likes), and INFLD is only responsible for returning the related exitcodes. No special type codes are required for this mode. Instead, when the application receives exitcode 30 or 31, instead of building the list data in the setdef parameter and returning to INFLD, it must build and display the list control itself. When returning to INFLD to allow the user to continue typing, the setdef parameter should be left blank (which will prevent INFLD from trying to create/display the list itself).

In addition to responding to exitcodes 30 and 31, the application should also respond to whatever exitcode it assigned to the list control that it builds. (For example, in the case of XTREE, via XTR'KBDSTR.) When the user clicks on the list control built and displayed by the application, the natural response would be for the application to put the focus on that list control, allowing the user to scroll among the choices with the arrow keys and select one by hitting Enter. The application must also respond to the exitcode returned from the list control (i.e. XTREE), so that it can allow the user to return to the edit field either by up-arrowing out of the list control, or clicking directly on the edit control.

Uncoupled mode allows the application maximum flexibility, but requires considerably more programming effort. The only benefit being derived from INFLD in this case is the auto-complete time-out mechanism. (In comparison, the normal field time-out is too simple-minded to work well in this situation.)

Auto-Complete with Self-Service Combo Box

In this variation, the control starts out as a combo box rather than an edit control. As in the normal case of a Self Service Combo Box, you must set setdef="…" to activate it, and clicking on the drop-down button returns exitcode 29. Although the application can do whatever it wants with that exitcode, the normal plan would be to respond to it just like you would to exitcode 30 (i.e. build a list by passing a properly formatted setdef backto INFLD.) Note that on return to INFLD, the control would then change from a combo to an edit box, and from that point would act like the normal Auto-Complete case.

Auto-Complete with Coded Lists

Auto-Complete can be combined with Coded Lists (||L) rather than standard setdef lists of complete entries, although the main effect is only felt on the final exit from the field. In the interim exits (with exitcode 30/31), the raw field contents will be returned to the application (since that’s what the auto-complete list would be based on), and the application can return either the coded or raw field contents on re-entry. (INFLD will first try to convert the entry string as if it were a coded value, but if that fails, uses it as is.) In almost all cases, you would want to also specify the||s (list matching optional), unless you planned to fill your list with all of the valid possibilities. (In that case, it isn’t clear how Auto-Complete would really be of any advantage, vs. just using a regular combo box.)


Auto-Complete Illustrations

Subroutines > INFLD > INFLD Parameters > type > GUI-related Codes > Auto-Complete

Auto-Complete Illustrations

Updated August 2010

For illustration, in the example below, the user has entered "Wood" into a field expecting a city name, but then paused, resulting in the auto-completion list containing cities whose names start with those characters:

The above example illustrates the possibility of the dropdown list containing additional information-only columns, in this case the zip codes. It also illustrates the possibility of making the dropdown list a different width than the field. (See the discussion of coldef for details.)

Once the list is displayed, the user can either select one of the choices from the list, either with the mouse or by using the DownArrow / UpArrow and Enter, or just continue typing, as in the example below (adding an "s" and then pausing again):

To complete our example, let’s assume that the user spotted the intended city, "Woods Hole", in the list and decides that it is easier to arrow down to it than to type the remaining characters:

Hitting Enter at that point closes the list and puts the selected item into the field:


Auto-Complete Examples

Subroutines > INFLD > INFLD Parameters > type > GUI-related Codes > Auto-Complete

Auto-Complete Examples

Updated and Reviewed August 2010

The following two examples illustrate valid setdef formats which sent back to INFLD in response to exitcode 30 or 31. Note that for the initial call to INFLD, you would normally set setdef to ""(unless you wanted the list displayed immediately).

Simple example:

SETDEF = "1~7~x~S~~~,ACME ,Adams ,Affleck,Azure ,,"

The above setdef string does not contain an optional [widthspec] and instead starts with a simple column definition (Coldef) string defining a single column of seven characters. The coldef string is normally (in standard XTREE usage) terminated by two tildes (~~), but in the context of INFLD auto-complete, a third tilde (~~~) is required to act as a delimiter between the coldef and the actual list items. Also note the trailing spaces on the list elements to give them each 7 characters. Finally, following the coldef string and the three tildes, we show four entries in the list, each delimited by a comma and space-padded to seven characters. Note that as with a standard setdef List of Valid Inputs, the first character of the list specifies the list item delimiter (comma in this example), and two delimiters mark the end of the list.

More complex example:

SETDEF = "[+3]0~0~x~H~RGBbg=220,230,240,A~~1~10~x~S~~11~1~x~bH~~~" &

+ ",Apples A,Bananas ,Peaches A,Watermelon ,,"

In the above list, we started with a [widthspec] of "[+3]" so that the dropdown list would be 3 grid-columns wider than the field. Then we used a more complex Coldef string to define an RGBbg value associated with a pseudo-column, plus 2 real columns - the first ten characters long (the primary column) and the last one character to contain the color code. The list then specifies the color code "A" for Apples and Peaches, so those two items would appear in the auto-complete list with the specified background color. Note that each item in the list (as measured by the space between the delimiters) must match the total length of all the real columns (11 in this example):

See the sample programs INFAC1 and INFAC2 in [908,41] of the EXLIB for more complete examples.


Auto-Complete Comments

Subroutines > INFLD > INFLD Parameters > type > GUI-related Codes > Auto-Complete

Auto-Complete Comments

Updated and reviewed August 2010

• Auto-complete can only be used with "simple" text fields (no radio buttons, checkboxes, date pickers, spinners, multi-line or forms).

• The visible space occupied by the list will be the equivalent of about 5 "grid rows" below the INFLD control, unless the control is too close to the bottom of the parent window, in which case the list will display above the field. Note that even when the list displays above the field, you still use the Down+Arrow to move from the field to the list, the Up+Arrow to move back to the field from the list, and the Down+Arrow (or Ctrl+ Down+Arrow) from the last item of the list to request more items.

• Internally, the list control is assigned exitcode -63 (VK_xF63). You should not have any controls in that range (-33 to -99 is generally reserved for A-Shell.)

• When INFLD exits with exitcode 30 (asking the app to refresh the list data) or exitcode 31 (requesting more data), you must re-enter with a proper setdef string (as described above), or manually remove the existing list control. (To make it easy to remove, list controls created by INFLD have the name "xtrInfldAutoComplete", and thus can be deleted using:

xcall AUI, AUI_CONTROL, CTLOP_DEL, "xtrInfldAutoComplete"

• Obviously, you want to minimize the time the application takes to respond to exitcode 30. Characters typed during that interval should be queued up but won't appear until the application returns to INFLD.

• There is no particular limit to how many items can be in the list, but as a matter of practicality or efficiency, you should keep it reasonably short. (For example, if the user enters "A" and pauses, you may not necessary want to generate a list with all of the items that start with "A".) The user can effectively request more items by pressing Ctrl+DownArrow from the bottom of the list.

• Requesting more items: If the user wants to see more items in the list, she can either type some more characters (effectively refreshing and narrowing the choices), or she can press Ctrl+DownArrow from the last item in the list, which generates exitcode 31. Applications can respond to exitcode 31 by either building a longer list, or by replacing the current list with the next several items in sequence. Note that if you don't want to require the Control key for this purpose, add the advanced coldef option ScrollMode=Tree.


Miscellaneous Codes
Value | Description
& | (ampersand) Enable protected fields.
|& | (bar ampersand) Works like a "smart" version of "&", re-enabling protected mode on exit only if it was previously enabled. The "&" feature always re-enables protected mode, which was the way it worked historically under AMOS. Beginning with A-Shell 6.3.1540: when specified in the INFDEF string, now affects BASIC INPUT fields. (Normally, the INFDEF options only apply to XCALL INPUT, XCALL INFLD, etc.) This can be handy in an application that uses protected fields along with BASIC INPUT, assuming that the BASIC INPUT does not deactivate the protection (which INFLD would otherwise do).
( | (open parenthesis) Strip leading blanks from entry before pre-load.
) | (close parenthesis) Start cursor at end.
|/ | (bar slash) Disables the display of the INFLD "about" box (normally triggered by Ctrl+Slash). This is mainly a workaround for a problem where the about box is being triggered unexpectedly.
: | (colon) Disable bright and dim.
; | (semicolon) Turn cursor on while waiting for input; turn it off again on exit from field.
[ | (open bracket) Force cursor to blink during input.
\ | (backslash) Clear bottom line.
] | (close bracket) Strip trailing blanks. Otherwise entry field is filled up with trailing blanks, like in the original AlphaAccounting version of INPUT.SBR. The stripped blanks are not counted toward xmin. (See ].)
|] | (bar close bracket) Defeats both the padding and stripping of trailing blanks, so that you get back exactly what you typed. (See ].)
^ | (carat) Convert to upper case (1).
_ | (underscore) Use clear-to-end-of-line function (-1,9) to clear field.
|_ | (bar underscore) Use underline to mark designated field (instead of default auto-beveling). See Field Markers.
` | (grave accent) Force destructive Enter.
|. | (bar period) Forces INFLD to use periods rather than underlines for the field marker in text mode. Previously you had to use prehistoric compatibility mode, or allow decimal points, to achieve this.
} | (close brace) Activates "INMEMO" mode. This is a special INFLD mode used internally by the A-Shell implementation of INMEMO.
|} | (bar close brace) Activates horizontal scrolling mode. Set automatically when maxchrs > xmax.
||} | (bar bar close brace) Activates "command-line" mode. This is a special INFLD mode used internally by the A-Shell implementation of the dot prompt and for BASIC INPUT statements.
< | (less than) Echo a carriage return on exit from the field. This is useful especially with the F and @ codes to let the operator know immediately that the input is being processed.
= | (equals) Do not reformat the field on exit. Also see |R (do not redisplay on exit).
|A | Activates simulation of AMBTOA.SBR
b | Disallow blanks.
B | Disable character blanking.
c | Capitalize first letter of each word.
e | Force non-destructive CarriageReturn (or Enter). This is the default for most field types except numeric. See code "`" (grave accent) above.
E | Abort allowed.
f | Form Field.
F | Fast input.
|F | |F is similar to F (fast) except that it affects the preload operation, rather than interactive typing. When specified, if the preloaded characters satisfy the minimum field size, then the field will exit immediately (without waiting for input).
||F | Forces the current field to use the fixed pitch font, regardless of the setting of the "Use Fixed Pitch In Edit Boxes" option in the Misc. Settings menu. This can be useful when specific fields do not work well in a proportional font.
g | Return updated field contents.
h | Disables the help message display "Hit ? for Help". This may be desirable when you have help on virtually every field, or when you need to use that area for some other message.
i | (lower case I) Completely invisible field. Similar to S except that nothing is echoed (so you cannot even see how many characters are allowed, or how many were typed.) type i silences the beveling so that the field remains totally invisible (no cursor, no indication of field position or size, no echoing of characters).
I | (upper case letter "eye".) Use invisible field markers. See also Field Markers.
|I | (bar upper case letter "eye") Forces INFLD to start in insert mode, rather than the default (which may be either insert or replace mode, depending on several factors).
||I | (bar bar upper case letter "eye") Forces INSERT mode off / REPLACE mode on). This overrides the remembered state for the current field, but does not change the remembered state for subsequent fields.
||k | Disables internal too-fast input filter, which may otherwise cause characters fed via a burst to be dropped.
|l | (bar lower case letter "el") Forces lower case.
||l | (bar bar lower case letter "el") Same as ||L except that entry will return a complete <code>,<description> pair (e.g. "01,North") instead of just the code item. See Coded Lists.
||L | (bar bar upper case letter "el") List substitution. setdef consists of <code>,<descr> pairs, e.g.: ,01,North,02,South,03,Middle Earth,, Application uses the code items (01, 02, ...) while the operator sees and uses the description items. See Coded Lists.
m | Disable the INFLD.DEF option.
n | Return null.
O | (Upper case letter "O") Optional field. Allows operator to skip the field, even if the xmin specified is non-zero. However, if 1 or more characters are entered, then the minimum goes back into effect.
p | Overrides cmdflg parameter, setting it to 1 (i.e. forces command file input to be active.)
|p | Prehistoric Compatibility Mode. See Field Markers.
|P* | This three-character type combination (vertical bar, P, followed by any character A-Z, [, ], ^, _) enables Ctrl+ (whatever the third character of the sequence is) to launch the pop-up utility ASHPOP.RUN.
||P | This may be used with the security type field (S) to automatically decrypt/encrypt a password, using A-Shell's standard password encryption scheme. See MX_PWCRYPT.
q | Causes field to be edited in reverse video.
|r | Read only.
|R | Do not redisplay field.
s | Disable display of setdef options, which are otherwise displayed along the bottom line of the screen. Not applicable in GUI mode, where the setdef options are loaded into a combo box.
S | Security field: echo all characters as "*". Also see i above.
|s | Provides support for regular expressions in SETDEF. When |s is specified, SETDEF is interpreted as a single regular expression, which the data field must match. Note that to invoke regular expression flags such as PCRE_CASELESS, you'll need to use the Perl-style internal option settings, e.g. "(?i)[AP]M" will match AM, PM, am, pm, etc. Also note that in this mode, setdef should contain only the regex pattern, with no leading or trailing delimiters.
|S | Causes an automatic screen capture to be appended to the capture file on exit from the field. See MX_SCRNPIC for more info on screen captures.
|u | Convert to upper case (2).
W | Disallow record abort key.
|X* | Program Ctrl+X.
0 | (zero) Strip away all characters typed ahead into the input buffer before inputting the field. Useful when you want to make sure that the operator reads a message or prompt before answering it.


Force destructive Enter

[ Type code = ` ] This forces a destructive Enter key (e.g. make it always truncate field at position of the cursor.) When using this code, the field is automatically cleared as soon as you enter the first character (except an exit key). Except for numeric fields, Enter usually exits a field without truncating or erasing any characters. See e code (force non-destructive) for information on how INFLD determines whether to use destructive or non-destructive carriage returns.


Disable bright and dim

[ Type code = : ] This disables the output of bright and dim codes. Normally INFLD displays the field markers in dim, with the field contents in bright. On some terminals, use of these intensity commands may cause an inordinate delay, slowing down output. The ":" type code will speed up display in this situation by leaving the terminal in the same intensity.


Enable protected fields

[ Type code = & ] Use this code when you have the screen protected. This is necessary since INFLD is forced to disable protected fields in order to display reduced intensity field markers. When it exits, it will enable protected fields if you use this code. (Also note that disabling protection during input is not a problem since it is impossible to move the cursor out of the field, unlike Alpha's INPUT.SBR.) Before using this code you may want to reconsider your use of protected fields. If you are only using them to allow you to clear the data from the screen quickly, then you only need protection enabled when you perform the screen clear function (e.g. print tab(-1,13); tab(-1,10);tab(-1,14))


Start cursor at end

[ Type code = ) ] This starts the cursor at end of field instead of the beginning of the field. This is only effective when opcode=1 and may be useful in sophisticated applications where a single field is input in parts using multiple INFLD calls. See the parameter description of opcode for notes on preloading trailing blanks.


Clear bottom line

[ Type code = \ ] This clears the bottom line on exit from the field. This is useful when the program prints error messages on the bottom line. The only time that this would be harmful is when you have a message on the bottom line that should remain there for multiple fields.


Disable character blanking

[ Type code = B ] This disables blanking of characters to right or left of field. INFLD normally displays a few blanks to the right of expanding fields like $, D, H (or to left of field if right justified), in order to completely erase the previous field display. It does not do this for fields which are not re-displayed with extra formatting characters, and you can disable it in all cases with this code.


Disallow blanks

[ Type code = b ] This prevents blanks from being entered into the field. This code also alters the way the Rubout (or Backspace on most PCs) key works. Normally it erases the character to the left of the cursor, leaving a blank if it was in the middle of the field. Since we do not want to allow blanks here, it just acts like a left arrow when in the middle of the field.


Abort allowed

[ Type code = E ] Operator may use the Backspace key (when in first position of field) or Escape key to signal abort. Either key displays and returns the field as "END", and sets both inxctl and exitcode to 2. Note that the Left Arrow key takes on a different function when used without the E code; see exitcode. Also note that typing "END" is not supported as an alternative to using Backspace or Escape.


Fast input

[ Type code = F ] Exits as soon as the maximum (xmax) number of characters entered, or an enabled exit code is used; no CarriageReturn or Enter needed. See code <. To alert the operator, INFLD will make the cursor blink while editing fast fields.

F generally has the same effect in a GUI field as in a text input field—i.e., causing the field to exit automatically when the maximum number of characters are entered. There are some special GUI situations, however, where it takes on additional meaning. One occurs with drop-down controls (combo boxes or date pickers), where it causes a single-click on an entry in the drop-down list to cause the item to be selected the field to exit. Otherwise, single-click in this case would normally just close up the drop-down list and return to the edit field.


Return updated field contents

[ Type code = g ] Causes INFLD to return the updated field contents when an enabled function key is used to exit the field. Normally the field contents are not returned on a function key exit. (As a mnemonic, you may associate "g" with "GO" commands, where a single key not only exits and updates a field but also causes some other action, dependent on the actual function key used.)


Use invisible field markers

[ Type code = I ] (Usually the maximum size of the field is indicated with underline or period markers.) With this code, there is no visual indication of the field size (although the maximum is still in effect and the bell will sound if you try to go past it. This may be desirable for passwords (in conjunction with S code), or for satisfying special aesthetic requirements.


Disable the INFLD.DEF option

[ Type code = m ] The INFLD.DEF option is described more fully in its own topic, but briefly, it allows a method of automatically adding a series of type codes to every INFLD call. m will disable this ability, and even disable the search for the INFLD.DEF module, which may shave a few CPU ticks off each call.

Note that INFLD.DEF is replaced by SBR=INFDEF: in the miame.ini file, but the m code still serves the same purpose..


Return null

[ Type code = n ] This returns entry as a null string if the field was exited with some sort of abort condition, such as time out, Ctrl+C, Escape, Left Arrow with the E code, or Ctrl+E. Otherwise, the pre-existing contents of the field would be returned. This may simplify your abort handling.


Disallow record abort key

[ Type code = W ] Note that with Alpha's INPUT, the record abort key is Ctrl+W (hence the W code). However, with INFLD, Ctrl+W is used as an editing function (next word), and Ctrl+E is used as the record abort key. This code W should be used whenever you do not plan to check for the inxctl=1 (or exitcode=1) returned code.


Prehistoric Compatibility Mode

The combination |p (vertical bar, lower case p) causes INFLD to revert to behavior as similar as possible to the old INPUT.SBR. Some of the differences include: use of dots instead of underlines; always blank 3 spaces to right of field; use Ctrl+W for record abort instead of Ctrl+E; throw away characters above ‘z’ ("{", "|", "}", "~"); and allow months 1-13 and days 1-31 in all dates. This capability was added for users converting from INPUT.SBR that wanted to preserve those idiosyncrasies while taking advantage of field editing and other enhancements of INFLD.


Do not redisplay field

[ Type code = |R ] This prevents the redisplay of the field on exit from editing mode. This can be useful to eliminate display thrashing when you are going to reformat and redisplay the field yourself manually. In the case of GUI mode, this causes the field control to be deleted on exit (making it easier to redisplay the field using a simple text PRINT statement, but also mandatory that you redisplay it.)


Read only

The combination |r (vertical bar, lower case r) prevents the operator from making editing changes to the field. This might be useful in a situation where you wanted to allow the operator to use certain exit codes in the context of a field but not actually change the contents.

History

2013 August, A-Shell 1359: Now applies to date and time pickers, up/down controls, and combo boxes. Previously it only worked for normal edit controls.


Program Ctrl+X

[ Type code = |X* ] This three-character type combination (vertical bar, X, followed by any third character A-Z) is one of the more obscure features available. It programs Ctrl+X to act as if you entered Ctrl+*, where "*" is the third character of the three-character type code. For example, the sequence |X[ would cause Ctrl+X to act like Ctrl+[ (Escape). Perhaps this would be useful if your terminal did not allow certain control sequences to be input from the keyboard.


Convert to upper case (1)

[ Type code = ^ ] Has no effect on non-alphabetic characters. You do not have to specify this for Y/N fields, since they already force upper case. When ^ is used in combination with one of ($,H,M), it takes on a new meaning: forcing the minus signs to be displayed in leading rather than trailing format. (Note that for numeric codes # and N, this is unnecessary since leading minus display format is the default.) Also see |u.


Convert to upper case (2)

The combination |u (vertical bar, lower case u) provides an alternate way to force the field contents to upper case. The other method, type "^" (caret) causes problems with d/VUE which sometimes wants to treat the caret as a literal control character lead-in character in your program source code. (This would not only fail to give you the upper case flag, but would also combine with the next type code in your list of type codes to produce a control character which would be, at best, ignored by INFLD.)


Exit Key Enabling Codes

These codes are used to selectively enable individual exit keys (and corresponding return codes) you wish to process. For example, if you want to process a Ctrl+R by returning the cursor to home or previous screen, then you will have to enable use of the Ctrl+R. Where possible, the codes are equal to the exitcode value returned to make them easier to remember. An attempt at exiting a field with a disabled exit key produces a beep.

Note that not all of the available exit keys are enabled in this manner. The Enter key is always enabled (any field may be exited with Enter). The abort key Ctrl+E is always enabled unless disabled with the W code. The time-out abort is activated by specifying a non-zero value for the timer parameter.

The following table, like the others, is organized by the alphabetical order of the type code characters. See the exitcode parameter for a table ordered by exitcode values.

Value | Description
? | Help key allowed. Displays message on bottom line "Hit `?' for Help", and returns exitcode = 8 if help key entered. Leaves the value of entry as it was before calling INFLD. Note that the help key, message, and message location may be customized.
||< | Type ||< may be used with ||S (selection-only combo boxes) to force an exit with EXITCODE 32 whenever the selection changes due to the user typing a keyboard character. The concept is the same as for ||5 and ||3 as described below.
|a | Enable Ctrl+A (when cursor already at start of field) to return exitcode=19. (Ctrl+A normally moves cursor tostart of previous word.)
|B | Enable Ctrl+B to return exitcode=16, and Ctrl+O to return exitcode=17.
|C | Enable Ctrl+S to return exitcode=26.
||E | Causes Enter to return exitcode 23 instead of the normal 0. This can be useful in certain dialog situations (particularly involving AUI_EVENTWAIT) where either the correct response to Enter, or the meaning of a response of exitcode 0, might otherwise be ambiguous.
k | Enable Ctrl+E to return exitcode=15 (rather than its normal use as the record abort key, which sets inxctl=1.)
L | Enable Ctrl+L (RightArrow). Returns exitcode=12 if right arrow hit when cursor already at right end of field.
|L | The combination |L (vertical bar, L) is the same as type L (without the vertical bar) in that it triggers exitcode 12. The difference is that with L by itself, you can only exit from the far right side of the field. (If there are characters to the right of the cursor, then the right arrow key will simply move the cursor to the right.) With |L, you can exit the field from any position, provided you have not already used other editing or cursor motion keys first. This mode is useful for Right+Arrow to skip from one field to the next.
|N | Enable Ctrl+N to return exitcode=22 (instead of just moving the cursor to the end of the field).
|Q | Enable Ctrl+P to return exitcode=25 (instead of initiating a screen snapshot).
T | Allow Tab key as a terminator. Sets inxctl to 3 and exitcode to 7.
||T | Causes Enter to act like Tab (returning exitcode 7). This might help simplify dialog logic, particularly when using EVENTWAIT with the EVW_EXCDFOCUS option, by eliminating the need for special treatment of the exitcode 0 case.
|U | Enable Ctrl+U to return exitcode=21 (instead of just moving the cursor to the start of the field).
V | Trap Ctrl+C and return exitcode=10 (instead of the normal mode which aborts to the BASIC error trapping routine). Note that you must specify the exitcode parameter for this to work. See also Ctrl+C Behavior.
|w | Enable Ctrl+W to return exitcode=20 (when at the start of an empty field)
|W | Enable Ctrl+W to return exitcode=1 and inxctl=1, instead of moving the cursor to the start of the next word.
|XX | Enable Ctrl+X to return exitcode=27. Note that this is a special case of the general three-character type sequence |X* which causes Ctrl+X to be interpreted as Ctrl+* (where * is any character compatible with the Ctrl key).
|Z | Enable Ctrl+Z to return exitcode=18 (instead of clearing the field).
1 | Enable Escape, returns exitcode=1. Note that this is only effective when used without the E code (see above). This differs from Escape with the E code in that the contents of the field are not overwritten with "END". Also note that the Ctrl+E abort key also returns exitcode=1.
2 | Enable LeftArrow (Backspace on most PCs), returns exitcode=2. This is only effective without the E code, and is intended to be processed as a move to previous field.
|2 | (vertical bar followed by 2) (Windows/ATE) (GUI mode only) Forces Shift+Tab to return exitcode 2 (like left arrow would if type 2 was specified). Otherwise Shift+Tab acts exactly like UpArrow, meaning it will exit with exitcode set to 3 if type 3 specified. Unlike left arrow, Shift+Tab does not require that the cursor be in the home position in order to be treated as an exit key. Note that type |2 neither requires type 2 nor implies it. In other words, type |2 by itself will enable Shift+Tab exits (setting exitcode 2) but will not enable the Left Arrow exit. Use type 2|2 or |22 to allow both methods of exiting.
3 | Enable UpArrow, returns exitcode=3. Should be processed as either a return to previous field, or to next field above cursor in same column.
|3 | Types |3 and |5 are equivalent to the existing Types 3 and 5, respectively, except that if used with a combo box, they also cause the up/down arrows to exit immediately (with the corresponding exitcode), rather than scroll among the choices in the combo box, PROVIDED THAT the combo box is not already in the dropdown position. (This is directly analogous to the XTREE coldef option ScrollMode=Tree.) An additional side-effect of |3 and |5 (versus 3 and 5) is that Shift+UpArrow and Shift+DownArrow will now act as they do in text mode (i.e. get translated via the function key translation system), even if |K (Windows keyboard mode) is in effect.
||3 | Types ||5 and ||3 act just like |5 and |3 respectively, except that the exit occurs AFTER updating the display (with the next or previous item in the list), instead of BEFORE. Thus they work similarly to the SelChgExit feature of XTREE, allowing you to update some other display element to correspond with the currently displayed item in the combo box.
4 | Enable Ctrl+R, returns exitcode=4. Should be processed as a return to first field in screen, or to previous screen (in multi-screen applications).
5 | Enable Ctrl+J (down arrow), returns exitcode=5. Should be processed as an advance to next field or next line (skipping fields on current line).
|5 | See |3.
||5 | See ||3.
6 | Enable Ctrl+T, returns exitcode=6 and should be processed as an exit out of screen (usually to the ANY CHANGE? prompt). This is particularly useful to terminate change mode when the cursor is allowed to be moved about freely between fields (with the above codes).
7 | Enable Spacebar, returns exitcode=13.
8 | Enable Rubout or Delete, returns exitcode=14 if cursor is in the first position of the field.
9 | Enable Ctrl+^ (Home). Returns exitcode=9 if Ctrl+^ (Home) key hit, and should be processed as a return to first field of screen


Type Codes Summary

The following table shows all of the type codes and is intended as a kind of "quick reference" for the codes.

Type | Value | Description
Numeric | - | (hyphen) Allow minus sign.
Timer | ! | (exclamation point) Activate return of elapsed time during input. This is only applicable when the timer parameter is specified. Note that this can be used even if time-out is not specified (by setting timer=0).
Character | # | (number sign) Numeric (0-9). If nothing entered, displays a "0" (but returns just a blank string.) Also see N.
Character | $ | (dollar sign) Currency field.
Misc | & | (ampersand) Enable protected fields.
Misc | |& | (bar ampersand) Works like a "smart" version of "&", re-enabling protected mode on exit only if it was previously enabled. The "&" feature always re-enables protected mode, which was the way it worked historically under AMOS.
Misc | ( | (open parenthesis) Strip leading blanks from entry before pre-load.
Misc | ) | (close parenthesis) Start cursor at end.
Character | * | (asterisk) Accept all characters. Same as A.
Character | , | (comma) Punctuation allowed. Punctuation is anything other than a number or letter.
Numeric | . | (period) Allow decimal point.
Misc | |. | (bar period) Forces INFLD to use periods rather than underlines for the field marker in text mode. Previously you had to use prehistoric compatibility mode, or allow decimal points, to achieve this.
Timer | / | (slash) Disable all timer displays. This differs from the "+" code in that the "+" code leaves the message "timing out" on the bottom line (but does not show the time)
Misc | |/ | (bar slash) Disables the display of the INFLD "about" box (normally triggered by Ctrl+\). This is mainly a workaround for a problem where the about box is being triggered unexpectedly.
Misc | : | (colon) Disable bright and dim.
Misc | ; | (semicolon) Turn cursor on while waiting for input; turn it off again on exit from field.
Exit | ? | Help key allowed. Displays message on bottom line "Hit `?' for Help", and returns exitcode = 8 if help key entered. Leaves the value of entry as it was before calling INFLD. Note that the help key, message, and message location may be customized.
Character | @ | (at sign) Control character input.
Misc | [ | (open bracket) Force cursor to blink during input.
Misc | \ | (backslash) Clear bottom line.
Misc | ] | (close bracket) Strip trailing blanks. Otherwise entry field is filled up with trailing blanks, like in INPUT. The stripped blanks are not counted toward xmin.
Misc | |] | (bar close bracket) Defeats both the padding and stripping of trailing blanks, so that you get back exactly what you typed. (See ].)
GUI | ||] | (bar bar close bracket) Prevents field width from being automatically expanded by logic that attempts to allow for the extra space needed by various GUI enhancements. For example, combo boxes smaller than six characters wide typically get an extra three characters of width to account for the space needed for the dropdown button. Similar rules apply to date and time pickers as well.
GUI | ||[ | (bar bar open bracket) causes the redisplayed field to grow as needed for the contents. (This was once part of the ||] code but has been removed in order to avoid slight differences in field display widths which give such screens a ragged look.)
Misc | ^ | (carat) Convert to upper case (1).
Misc | _ | (underscore) Use clear-to-end-of-line function (-1,9) to clear field.
Misc | |_ | (bar underscore) Use underline to mark designated field (instead of default auto-beveling). See Field Markers.
Misc | ` | (grave accent) Force destructive Enter.
Character | { | (open brace) Character acceptance is limited to the set of characters specified in setdef. (Typically you would combine this with "*", else the characters may be rejected before even considering the setdef list.
Misc | } | (close brace) Activates "INMEMO" mode. This is a special INFLD mode used internally by the A-Shell implementation of INMEMO.
Misc | |} | (bar close brace) Activates horizontal scrolling mode. Set automatically when maxchrs > xmax.
Misc | ||} | (bar bar close brace) Activates "command-line" mode. This is a special INFLD mode used internally by the A-Shell implementation of the dot prompt and for BASIC INPUT statements.
Timer | + | Disable display of time remaining (on bottom line). Normally, the time remaining until time-out is displayed (and updated every second) on the bottom right corner of the screen.
Misc | < | (less than) Echo a carriage return on exit from the field. This is useful especially with the F and @ codes to let the operator know immediately that the input is being processed.
Exit | ||< | Type ||< may be used with ||S (selection-only combo boxes) to force an exit with EXITCODE 32 whenever the selection changes due to the user typing a keyboard character. The concept is the same as for ||5 and ||3 as described below.
Misc | = | (equals) Do not reformat the field on exit. Also see |R (do not redisplay on exit).
Date/Time | > | (greater than) Convert date format.
Character | a | Alphabetic characters allowed (a-z, A-Z), or as defined by the LDF (language definition file).
Character | A | All characters allowed (subject to code b). Note that A is used for compatibility with INPUT, but to most people, "*" makes more sense. Note that A or "*" is equivalent to the combination "a#," (alphabetic, numeric, and punctuation).
Exit | |a | Enable Ctrl+A (when cursor already at start of field) to return exitcode=19. (Ctrl+A normally moves cursor to start of previous word.)
GUI | ||a | Activate Auto-Complete mode.
Misc | |A | Activates simulation of AMBTOA.SBR.
Misc | b | Disallow blanks.
Misc | B | Disable character blanking.
Exit | |B | Enable Ctrl+B to return exitcode=16, and Ctrl+O to return exitcode=17.
GUI | ||b | For checkboxes, causes the current state of the checkbox to override the normal default state (i.e. the default based on the type codes if opcode=0, or the contents of the entry parameter if opcode=1 or 2). Useful when the checkbox statement may have been changed by clicking on it outside of the awareness of the application. Same effect as cmdflg=4.
Misc | c | Capitalize first letter of each word.
Character | C | Carriage Return only
Exit | |C | Enable Ctrl+S to return exitcode=26.
GUI | ||c | Convert Y/N field to checkbox.
GUI | ||C | Causes a field which would normally appear as a combo box or a date picker while editing (see setdef, dates) to also appear as a combo box when not actively being edited. Otherwise, these kinds of fields revert to static text controls when not active. See Active Versus Inactive Behavior.
Character | d | Date input, today.
Character | D | Date input.
Date/Time | |D | Defaults century to 19xx. Applies for date formats which allow user to enter only the YY. If not specified, century default is determined by the SBR=CCYY:## entry in the miame.ini file.
Date/Time | ||D | Allows a date field to be filled with zeroes.
Date/Time | |d | Allow date shortcuts.
Misc | e | Force non-destructive Return (or Enter). This is the default for most field types except numeric. See code "`" (grave accent) above.
Misc | E | Abort allowed.
GUI | |E | Causes the field to retain the form of an edit control when not active. (Otherwise, fields normally revert to static text controls when not active.) Also see ||C and Active Versus Inactive Behavior.
Exit | ||E | Causes Enter to return exitcode 23 instead of the normal 0. This can be useful in certain dialog situations (particularly involving AUI_EVENTWAIT) where either the correct response to Enter, or the meaning of a response of exitcode 0, might otherwise be ambiguous.
Misc | f | Form Field.
Misc | F | Fast input.
Misc | |F | |F is similar to F (fast) except that it affects the preload operation, rather than interactive typing. When specified, if the preloaded characters satisfy the minimum field size, then the field will exit immediately (without waiting for input).
GUI | |f | Reserved for internal use ATE in GUI mode to control function key settings
GUI | ||f | Force fixed-pitch font.
GUI | ||F | Force modified fixed-pitch font..
Misc | g | Return updated field contents.
Numeric | G | May be useful for aligning decimal points in column of variable precision numbers.
GUI | |g | Implies |G, but limits the GUI enhancements to just the Windows-style edit box (i.e. without some of the other automatic enhancements such as date picker controls).
GUI | |G | Activate GUI enhancements.
GUI | ||g | Disable/override GUI mode. (Used to temporarily cancel a global |G or ||G or |g)
GUI | ||G | Same as |G except turns Y/N fields into checkboxes.
Misc | h | Disables the help message display "Hit ? for Help". This may be desirable when you have help on virtually every field, or when you need to use that area for some other message.
Character | H | Hours field. Like $ but omits the "$" from the display.
Date/Time | |h | HexaDecade Dates (2).
Character | ||h | Accept hexadecimal digits (A-F, a-f, 0-9).
Date/Time | |H | HexaDecade Dates (1).
GUI | ||H | Disable horizontal scrolling within control. Note that the ability to scroll is sometimes needed in order to fit all of the allowed characters, if using proportional fonts and the field consists of wider-than-normal (e.g. CAPS) characters.
Misc | i | (lower case I) Completely invisible field. Similar to S except that nothing is echoed (so you cannot even see how many characters are allowed, or how many were typed.) type i silences the beveling so that the field remains totally invisible (no cursor, no indication of field position or size, no echoing of characters).
Misc | I | (upper case letter "eye".) Use invisible field markers. See also Field Markers.
Misc | |I | (bar upper case letter "eye") Forces INFLD to start in insert mode, rather than the default (which may be either insert or replace mode, depending on several factors).
Misc | ||I | (bar bar upper case letter "eye") Forces INSERT mode off / REPLACE mode on). This overrides the remembered state for the current field, but does not change the remembered state for subsequent fields.
Date/Time | j | Julian date format.
Character | J | Accepts alphanumeric input, and if the input is wholly numeric, right justifies and fills with leading zeroes.
GUI | ||J | Right Justify Checkbox Text.
Exit | k | Enable Ctrl+E to return exitcode=15 (rather than its normal use as the record abort key, which sets inxctl=1.)
Misc | ||k | Disables internal too-fast input filter, which may otherwise cause characters fed via a burst to be dropped.
GUI | |K | Select data entry convention.
GUI | ||K | Acts just like |K but also disables the Ctrl+C abort while the field is active. This allows you to use Ctrl+C for copy-to-clipboard without first having to disable Ctrl+C abort in the application. See also Ctrl+C Behavior.
Misc | |l | (bar lower case letter "el") Forces lower case.
Misc | ||l | (bar bar lower case letter "el") Same as ||L except that entry will return a complete <code>,<description> pair (e.g. "01,North") instead of just the code item. See Coded Lists.
Exit | L | Enable Ctrl+L Right Arrow. Returns exitcode=12 if right arrow hit when cursor already at right end of field.
Exit | |L | The combination |L (vertical bar, L) is the same as type L (without the vertical bar) in that it triggers exitcode 12. The difference is that with L by itself, you can only exit from the far right side of the field. (If there are characters to the right of the cursor, then the right arrow key will simply move the cursor to the right.) With |L, you can exit the field from any position, provided you have not already used other editing or cursor motion keys first. This mode is useful for Right+Arrow to skip from one field to the next.
Misc | ||L | (bar bar upper case letter "el") List substitution. setdef consists of <code>,<descr> pairs, e.g.: ,01,North,02,South,03,Middle Earth,, Application uses the code items (01, 02, ...) while the operator sees and uses the description items. See Coded Lists.
Misc | m | Disable the INFLD.DEF option.
Numeric | M | Thousands separator.
GUI | |m | Prevents the Enter key, when used to select an item from the dropdown list in a combo box, from also causing the field to exit.
GUI | |M | Multi-line edit box. xmax sets the display width of the box. maxchrs sets the maximum number of characters allowed (up to a maximum of 1024). defpt is reinterpreted as the height of the box. See ||H for disabling horizontal scrolling (to enable word wrap). Enter (along with any other enabled exit key) exits. See Multi-line Edit Control (INFLD).
GUI | ||m | Causes exitcode 13 to be returned when an item is selected from the dropdown list (using Enter or click) in a combo box. This allows you to distinguish that event from merely hitting Enter to the field when the dropdown is not displayed. The same effect also applies to fast mode checkboxes, allowing you to distinguish between Enter (which returns exitcode 0) and a click or other keystroke which changes the checkbox value and then exits (with exitcode 13).
GUI | ||M | Variation of multi-line edit. Allows Enter to be used to manually break lines. Also, displays a vertical scroll bar.
Misc | n | Return null.
Character | N | NO/Yes field.
Exit | |N | Enable Ctrl+N to return exitcode=22 (instead of just moving the cursor to the end of the field).
Misc | O | (Upper case letter "O") Optional field. Allows operator to skip the field, even if the xmin specified is non-zero. However, if 1 or more characters are entered, then the minimum goes back into effect.
Misc | p | Overrides cmdflg parameter, setting it to 1 (i.e. forces command file input to be active.)
Character | P | Phone number or zip code input.
Misc | |p | Prehistoric Compatibility Mode. See Field Markers.
Misc | |P* | This three-character type combination (vertical bar, P, followed by any character A-Z, [, ], ^, _) enables Ctrl + (whatever the third character of the sequence is) to launch the pop-up utility ASHPOP.RUN.
Misc | ||P | This may be used with the security type field (S) to automatically decrypt/encrypt a password, using A-Shell's standard password encryption scheme. See MX_PWCRYPT.
Misc | q | Causes field to be edited in reverse video.
Timer | Q | Disable time-out suspend feature. (Normally, the operator can suspend the time-out counter for 10 minutes by hitting Ctrl+S. Suspending the timer is useful when you have to temporarily interrupt data entry, as when answering the phone.) A-Shell Note: Under A-Shell, Ctrl+B is the suspend key.
Exit | |Q | Enable Ctrl+P to return exitcode=25 (instead of initiating a screen snapshot).
Timer | r | Time out reminder. This is similar in motivation to the w code, except that it just causes a single beep, without any message, after 10 seconds have elapsed (when the timer option is active.)
Numeric | R | Right justify field.
Misc | |r | Read only.
Misc | |R | Do not redisplay field.
GUI | ||r | Create a radio button.
Misc | s | Disable display of setdef options, which are otherwise displayed along the bottom line of the screen. Not applicable in GUI mode, where the setdef options are loaded into a combo box.
Misc | S | Security field: echo all characters as "*". Also see i above.
Misc | |s | Provides support for regular expressions in SETDEF. When |s is specified, SETDEF is interpreted as a single regular expression, which the data field must match. Note that to invoke regular expression flags such as PCRE_CASELESS, you'll need to use the Perl-style internal option settings, e.g. "(?i)[AP]M" will match AM, PM, am, pm, etc. Also note that in this mode, setdef should contain only the regex pattern, with no leading or trailing delimiters.
Misc | |S | Causes an automatic screen capture to be appended to the capture file on exit from the field. See MX_SCRNPIC for more info on screen captures.
GUI | ||s | Makes setdef list matching optional. Only applies to the combo box, in which case it allows the operator to enter a value that is not in the list.
GUI | ||S | Variation of combo box in which typing a character only selects the nearest matching item from the list. (Otherwise the user can type independently of the list, and use Down+Arrow to find the nearest match.) See Combo Box Control (INFLD)
Date/Time | t | Time field.
Date/Time | th | Same as "t" but allows hh > 24. Not supported in the Windows date control, i.e. not compatible with TYPE "|G" (use "|g" instead).
Exit | T | Allow Tab key as a terminator. Sets inxctl to 3 and exitcode to 7.
Timer | |t | Reset timer to the initial value after every keystroke.
Timer | |T | Overrides timer parameter to zero. Useful for disabling timer globally in programs that otherwise use it (by putting this in the SBR=INFDEF: string.)
Date/Time | ||t | Same as t (time) but in GUI mode returns the time in 12-hour format rather than 24 hour format.
Exit | ||T | Causes Enter to act like Tab (returning exitcode 7). This might help simplify dialog logic, particularly when using EVENTWAIT with the EVW_EXCDFOCUS option, by eliminating the need for special treatment of the exitcode 0 case.
LDF | u | Observe LDF rules. See LDF-Related Codes.
Character | U | European date.
Misc | |u | Convert to upper case (2).
Exit | |U | Enable Ctrl+U to return exitcode=21 (instead of just moving the cursor to the start of the field).
GUI | ||U | Create up/down ("spinner") control. See Up/Down Control (INFLD).
LDF | ||u | Ignore LDF; see LDF-Related Codes.
Numeric | v | Value range checking.
GUI | ||v | Self Service Date Picker.
Exit | V | Trap Ctrl+C and return exitcode=10 (instead of the normal mode which aborts to the BASIC error trapping routine). Note that you must specify the exitcode parameter for this to work. See also Ctrl+C Behavior.
Timer | w | Timer wake up warning. When added to any set of timer related codes, causes a warning beep and message when only 10 seconds remain on the timer. The message blinks TIMING OUT in the lower right corner of the screen, and any key hit during the remaining 10 seconds resets the timer to the original value. Note that w overrides / to display the warning message and suspend message as well, if invoked. See r
Misc | W | Disallow record abort key.
Exit | |w | Enable Ctrl+W to return exitcode=20 (when at the start of an empty field)
Exit | |W | Enable Ctrl+W to return exitcode=1 and inxctl=1, instead of moving the cursor to the start of the next word.
Character | X | Specifies a Y/N field, but with no default. May be used to force the operator to make a choice, or, with xmin=0, to allow a third option (blank).
Misc | |X* | Program Ctrl+X.
Exit | |XX | Enable Ctrl+X to return exitcode=27. Note that this is a special case of the general three-character type sequence |X* which causes Ctrl+X to be interpreted as Ctrl+* (where * is any character compatible with the control key).
Character | Y | YES/No field.
Numeric | Z | Zero fill.
Exit | |Z | Enable Ctrl+Z to return exitcode=18 (instead of clearing the field).
Misc | 0 | (zero) Strip away all characters typed ahead into the input buffer before inputting the field. Useful when you want to make sure that the operator reads a message or prompt before answering it.
Exit | 1 | Enable Escape, returns exitcode=1. Note that this is only effective when used without the E code (see above). This differs from Escape with the E code in that the contents of the field are not overwritten with "END". Also note that the Ctrl+E abort key also returns exitcode=1.
Exit | 2 | Enable LeftArrow (Backspace on most PCs), returns exitcode=2. This is only effective without the E code, and is intended to be processed as a move to previous field.
Exit | |2 | (vertical bar followed by 2) (Windows/ATE) (GUI mode only) Forces Shift+Tab to return exitcode 2 (like left arrow would if type 2 was specified). Otherwise Shift+Tab acts exactly like UpArrow, meaning it will exit with exitcode set to 3 if type 3 specified. Unlike left arrow, Shift+Tab does not require that the cursor be in the home position in order to be treated as an exit key. Note that type |2 neither requires type 2 nor implies it. In other words, type |2 by itself will enable Shift+Tab exits (setting exitcode 2) but will not enable the Left+Arrow exit. Use type 2|2 or |22 to allow both methods of exiting.
Exit | 3 | Enable UpArrow, returns exitcode=3. Should be processed as either a return to previous field, or to next field above cursor in same column.
Exit | |3 | Types |3 and |5 are equivalent to the existing Types 3 and 5, respectively, except that if used with a combo box, they also cause the up/down arrows to exit immediately (with the corresponding exitcode), rather than scroll among the choices in the combo box, PROVIDED THAT the combo box is not already in the dropdown position. (This is directly analogous to the XTREE coldef option ScrollMode=Tree.) An additional side-effect of |3 and |5 (versus 3 and 5) is that Shift+UpArrow and Shift+DownArrow will now act as they do in text mode (i.e. get translated via the function key translation system), even if |K (Windows keyboard mode) is in effect.
Exit | ||3 | Types ||5 and ||3 act just like |5 and |3 respectively, except that the exit occurs AFTER updating the display (with the next or previous item in the list), instead of BEFORE. Thus they work similarly to the SelChgExit feature of XTREE, allowing you to update some other display element to correspond with the currently displayed item in the combo box.
Exit | 4 | Enable Ctrl+R, returns exitcode=4. Should be processed as a return to first field in screen, or to previous screen (in multi-screen applications).
Exit | 5 | Enable Ctrl+J (down arrow), returns exitcode=5. Should be processed as an advance to next field or next line (skipping fields on current line).
Exit | |5 | See |3.
Exit | ||5 | See ||3.
Exit | 6 | Enable Ctrl+T, returns exitcode=6 and should be processed as an exit out of screen (usually to the ANY CHANGE? prompt). This is particularly useful to terminate change mode when the cursor is allowed to be moved about freely between fields (with the above codes).
Exit | 7 | Enable Spacebar, returns exitcode=13.
Exit | 8 | Enable Rubout or Delete, returns exitcode=14 if cursor is in the first position of the field.
Exit | 9 | Enable Ctrl+^ (Home). Returns exitcode=9 if Ctrl+^ (Home) key hit, and should be processed as a return to first field of screen


entry

Reviewed September 2011

entry is a string parameter in which the response is returned. Depending on the value of the opcode parameter, it may also be used to preload the contents of the field.

Note that when preloading the field, trailing blanks are stripped (unless type |] is specified). When returning the field, trailing blanks are added (up to the length specified by xmax), unless type ] is specified, in which case they are stripped, or type |] is specified, in which case they are neither added nor removed.

Comments

The mapped length of entry should be at least as large as the larger of xmax and maxchrs. If less than xmax, xmax will be reduced accordingly. If less than maxchrs, the returned contents may be truncated. Be aware of cases where entry may need to be larger than xmax, such as in list substitution (type ||L) where data returned may be longer than the data as entered or displayed. As of edit 1159, the entry parameter may also be mapped as a dynamic string (e.g. map1 entry,s,0) in which case it will grow as needed.


inxctl

inxctl is traditionally a numeric variable (F,6 or B,2) to accept a return code (as in Alpha's INPUT):

Value | Description
0 | Input OK, no message.
1 | "Y" answer to YES/NO type field, or Ctrl+E entered to abort record.
2 | "N" answer to YES/NO type field, or abort key used (either =left arrow or Escape) when enabled with the E code)
3 | Tab key used to terminate input.

inxctl is largely superseded by exitcode, which offers a much wider variety of return code information. Because of this, under A-Shell, you may put inxctl to a different use by mapping it as a one byte string (String,1). In that case, it will return the actual character that caused the field to exit. (Virtual function key sequences will be indicated by a chr(250).)


parentid

If parentid is not specified, or contains a numeric 0, the value of row is multiplied by two. This code is believed to be a holdover from the days when the first 24 line terminals appeared, replacing the 12 line models. (This parameter was previously called "v," apparently a reference to the original VT-xxx terminals that made the transition from 12 to 24 lines.) Note that despite the "parent" in the parameter name, it is also possible to use it to name the current control, but that "parent" was chosen because in the vast majority of cases, that will be the main significance of the parameter.

(GUI) If parentid is numeric and greater than 1, it is interpreted as referencing the parent control whose ID is parentid-1. The current field is treated as a child of that control, which among other things means that its coordinates are taken as relative to the parent, allowing them to be relocated simply by relocated the parent, e.g. dialog, groupbox, tab control, etc.

(GUI) If parentid is a string, it can identify the name of the parent control rather than its ID number. It can also assign a name to the current control by preceding it with the character ">". If specifying both, start with the parent control name, then the ">", then the current (edit) control name. For example:

MAP1 PARENTID,S,50

parentid = "dlgCustomer"

parentid = "dlgCustomer>editName"

parentid = ">editfName"

Note that if parentid contains the name to be assigned to the current INFLD control, it must be preceded by a ">", and it must follow the parent control name, if present (as in the examples above). The maximum length of a control name is 24 characters. See Control names for more details on the concept of identifying controls with names.


opcode

Updated November 2013

opcode, formerly DEFLT, specifies operational options such as pre-load, output vs. input, or format conversion:

Symbol | Value | Description
INFOP_EDIT | 0 | Normal operation (input). Field is cleared first.
INFOP_PRELOAD | 1 | Like 0 except contents of entry are preloaded into the field and displayed before input. Note that for codes d, Y, and N (Y/N), entry overrides the standard default only when entry is non-null. Also note that leading fill characters in R and Z fields, and trailing blanks in all field types will be stripped to simplify editing. You can, however, force it to keep one or more trailing blanks by supplying them as chr$(160) (which is a blank with the 8th bit set).This can be useful in conjunction with the ")" code
INFOP_DISPLAY | 2 | Format and output contents of entry. (No input)
INFOP_SIMPLE | 4 | Speed and cursor motion optimized version of opcode 2; assumes screen already clear. Relevant only for text mode.
INFOP_FORMATTED | 8 | Like opcode 0 except returns entry formatted.
INFOP_PRELOAD + INFOP_FORMATTED | 9 | Like opcode 1 except returns entry formatted. Note that you must de-format the field (somehow) between successive opcode=9 calls to the same field.
INFOP_PRELOAD + INFOP_DISPLAY | 10 | Like opcode 2, except returns entry formatted.
INFOP_FMTONLY | 28 | Format conversion only. Takes entry unformatted and returns it formatted.
INFOP_READONLY | 33 | Read-only input mode. Field loaded with entry, but cannot be changed. EXITCODEs however are still possible. This might be useful in a case were you want to allow a user to review previous entry fields, but only change them by first hitting some kind of special exitcode and then entering a password. This has the same effect as type |r (vertical bar, r).


exitcode

exitcode, if specified, receives a value to indicate how the field was exited. Note that for a specific value (except 0) to be returned, it must be activated by a corresponding type code (for the positive EXITCODEs), or by the funmap parameter controlling function key usage (for the negative exitcodes).

The number of command or function keys is limited by your terminal and function key translation module, subject to a maximum of 127 for direct function keys, and 999 for "virtual" function keys using the chr(7)+chr(250)+###. sequence.. Note that we use the terminology Command Keys (Cmdx) in place of Function Keys (Fxx) to underscore the idea that they can be mapped on to the physical function keys any way you like.

When |K (Windows keyboard mode) is NOT used, the Shift+Arrow keys work like function keys (same as they do in text mode), and will generate exitcodes based on the <tdv>.IFX translation table. The standard exitcodes for the shifted arrows are: -36, -37, -38 and -39. See FIXTRN.LIT for details on editing translation tables.

Value | Symbol | Description
0 |  | Return (Enter), or Tab when |K code used.
1 | EXC_ESC | Escape (if neither E nor W codes used), or Ctrl+W if the |W code used.
2 | EXC_LEFT | LeftArrow (^H) or Escape (when E code used), or Shift+Tab when |2 used.
3 | EXC_UP | UpArrow (^K) when enabled with 3 code, , or Shift+Tab when in GUI mode (|G)
4 | EXC_PGUP | PageUp (^R) when enabled with 4 code
5 | EXC_DOWN | DownArrow (^J) when enabled with 5 code
6 | EXC_PGDN | PageDown (^T) when enabled with 6 code
7 | EXC_TAB | Tab (when enabled with T code)
8 | EXC_HELP | Help (?) when enabled with ? code
9 | EXC_HOME | Home (Control ^) when enabled with 9 code
10 | EXC_CTRLC | Ctrl+C Trap (when enabled with V code). See also Ctrl+C Behavior.
11 | EXC_TIME | Field timed out
12 | EXC_RIGHT | RightArrow (^L) when enabled with L code
13 |  | Spacebar (when enabled with 7 code) or user selected an item in the dropdown area of combo box using Enter or Click (when enabled with ||m code).
14 |  | Rubout or Delete (when enable with 8 code)
15 |  | Ctrl+E (when enabled with the k code)
16 |  | Ctrl+B (when enabled with the |B code)
17 |  | Ctrl+O (when enabled with the |O code)
18 |  | Ctrl+Z (when enabled with the |Z code)
19 |  | Ctrl+A (when enabled with the |a code)
20 |  | Ctrl+W (when enabled with the |w code)
21 |  | Ctrl+U (when enabled with the |U code)
22 |  | Ctrl+N (when enabled with the |N code)
25 |  | Ctrl+P (when enabled with the |Q code)
26 |  | Ctrl+S (when enabled with the |S code)
27 |  | Ctrl+X (when enabled with the |XX three-character code)
29 |  | User clicked on dropdown button in Self Service Combo Box
30 |  | (Auto-Complete) User has modified the field and then paused or hit Down+Arrow; INFLD requests an updated setdef parameter containing the drop-down list configuration and contents.
31 |  | (Auto-Complete) User has hit Ctrl+Down+Arrow from bottom item of auto-complete list request additional items. Application may replace list with new data, or just add to the existing list, at its option.
-1 |  | (Cmd1) (When enabled via translation table and/or (funmap))
-2 |  | (Cmd2) etc.
-35 |  | Shift+Tab; note 1
-65 |  | Ctrl+PageDown; note1
-66 |  | Ctrl+PageUp; note1
-67 |  | Ctrl+Home; note 1
-68 |  | Ctrl+End; note 1
-69 |  | Click on close-tab "x" button in TabX control
-### |  | (Virtual function key) Triggered by a function key or a mouse-click on a field which was programmed to send the sequence chr(7)+chr(250)+"###." where ### is any number. See hlpidx.

Notes

1: The upper bit of the funmap parameter must be set in order to enable the specified exitcode. This can be accomplished by setting funmap = -1, enabling all function key exits as well, or by adding 2^31 to any other funmap value.


timer

timer, when specified and non-zero, causes the field to time-out (returning exitcode=11) after the number of seconds specified (in timer). If type "!" is not specified, then timer is not modified on exit from INFLD. (This allows you to use a fixed time-out value on every field without having to reset it each time.)

However, if type "!" code is specified, then the elapsed time (in seconds) is returned in timer. Stand advised that although the elapsed time is quite accurate, the time-out period may become elongated by up to 15% due to heavy system activity. This should not cause any inconvenience, as long as you check for time-out by seeing if exitcode=11 and not by comparing the elapsed time (returned in timer) to the original timer value. For example, if you set timer to 30, and the field times out, the elapsed time (returned in timer) may actually be 29-32 seconds. So check the exitcode to see if time-out occurred, and if you want to know the precise elapsed time, use the returned value of timer.

You can override the timer parameter (force it off) with the type code |T Also see type code |t which causes the timeout counter to be reset to the initial value after each keystroke.

Comments

• You can override the timer parameter (force it off) with the type code |T.

• Also see type code |t which causes the timeout counter to be reset to the initial value after each keystroke.

• If you only care about the elapsed time (and don't want to time out), then you need to set the initial timer value to something suitably large. The elapsed time feature doesn't work if the initial timer value is 0. You would also probably want to disable the timer displays with the /+ type codes.


cmdflg

cmdflg may be set to one or more of the flags listed below, which are discussed in the following sections:

Symbol | Value | Description
INFCF_CMDFIL | 1 | Enable command file input
INFCF_DROPDOWN | 2 | (GUI only) Force drop-down display
INFCF_EXISTING | 4 | (GUI only) Set initial value based on existing control
INFCF_DISABLE | 8 | Disable the control


INFCF_CMDFIL

This flag causes INFLD to attempt to read from a command file. If no characters are available, it will then accept input from the keyboard. Command file input can be turned on and off on a field-by-field basis. Note that you can override cmdflg (force it on) using the type code p.


INFCF_DROPDOWN

This flag applies only when INFLD is used in GUI mode (see type |G) and the field is implemented using a control type that has a drop-down option (e.g. date picker, combo box). In such a case, the drop-down display will be triggered automatically at the start of the field editing operation (as if the user had clicked on the drop-down button).

Note that this usage is often appropriate when the field is being called in response to a mouse click. One way to detect that within a centralized INFLD wrapper routine would be to check if the incoming value of exitcode matches the value associated with the current field (as defined in the hlpidx parameter).


INFCF_EXISTING

This flag applies only to checkboxes, in which case it causes the initial field value to be loaded from the current state of the existing checkbox (assuming there is an existing checkbox control at the specified coordinates) rather than the entry parameter. This helps deal with the fact that clicking on a checkbox (even when it is not currently under the control of INFLD) may toggle the value of the checkbox (in addition to sending the keyboard string associated with the field). If your app responded to the resulting exitcode by calling INFLD to edit the clicked-on checkbox, the app's copy of the checkbox's value (stored from the previous time it was edited with INFLD) may be out of sync with the new actual state of the checkbox, in which case it would appear to the user that it sometimes takes two clicks to get the checkbox to change value.

This is equivalent to setting type ||b.


INFCF_DISABLE

Use of this flag causes the field to be set to the disabled state. This is mainly useful in GUI mode with opcode 2 (display) to display a field value but indicate to the user (by the fact that it is in dim gray) that it is not presently applicable (and cannot be edited). Since you cannot edit a disabled field, attempting to use this flag with opcode 0 or 1 will cause it to act just like opcode 2, except that any incoming positive exitcode value is preserved (instead of being reset to 0 as would normally be the case with a display operation). This should help your existing field navigation logic to jump over disabled when moving backwards through them.

Note that a normal field display operation (i.e. opcode 2 and cmdflg not containing INFCF_DISABLE) will cause a previously disabled field to be re-enabled. Thus it might be necessary for your program to maintain a separate copy of the cmdflg parameter for every field that might be disabled, in order to preserve its state.

History

2006 February, A-Shell 4.9.951: Function added to A-Shell


defpt

defpt may be used to specify the default decimal point position relative to the right of the field. A value of zero indicates a default just following the last digit entered. If this parameter is omitted, there will be no default. (If this parameter is passed but you do not want a default, set it to -1.)

The action of defpt depends on whether the "." (allow decimal point) type code is used. If it is, then any default decimal points will actually be inserted into (and returned in) the field. If the "." code is not specified, any default decimal points will be inserted for display purposes only.

Note that the type codes $ and H will automatically set defpt to 2 if "." not specified, and 0 if it is specified. However, you can over-ride this by setting defpt to anything you want. Also note that you can set defpt to -2 to edit currency in whole numbers without a decimal point.

Note also that in multi-line mode (i.e. when type |M or ||M is specified), defpt is re-interpreted as the display height of the control in rows.


maxpt

maxpt may be used to specify the number of digits after a decimal point If the "." code is used, then INFLD will prohibit the operator from entering any more than <maxpt> digits past a hard decimal point. In any case, the display will be padded with enough zeroes or blanks (depending on the G code) to have <maxpt> digits after the decimal point.

If the parameter is omitted, no such checking will take place. However, if you specify the parameter and the value is zero, it will not allow any digits past the decimal point. (If you need to specify the parameter but do not want any such checking, set it to -1.)

Note that the $ and H codes automatically set maxpt to 2 (unless you set it otherwise), and it will always be set to the same as defpt, if defpt is specified and maxpt is not specified


funmap

funmap is interpreted as a bitmap controlling the function key translation. If funmap is not specified, all function keys will be translated exactly as in the function key translation module. Depending on which of the four function key translation architectures you decide to use (FIXTRN, SET PFK, the INFLD/AMOS proprietary one, or the A-Shell "virtual" method), funmap may be used to override editing translations to return an exitcode (F#=-#) or select which functions keys are enabled.

A-Shell Note: The only function key translation method which is strictly binary compatible between AMOS and A-Shell is the FIXTRN method. Tables created by FIXTRN.LIT under AMOS and FIXTRN.LIT under A-Shell are binary compatible, assuming equivalent terminal drivers. (The PCTDV and PCTDVG drivers used by A-Shell/Windows are function-key compatible with the AMOS AM65 driver.) SET PFK style translations are operationally compatible between A-Shell and AMOS but the tables themselves are not binary compatible.

When using the FIXTRN or SET PFK function key translation architectures, it is not possible for a single key to have both editing and command translations, so to get command EXITCODEs, you have to set the translation table up to do that directly. The procedure is to translate the function key to Ctrl+G (ASCII value 7) followed by the ASCII character whose value is the exitcode (negative) you want. For example, you might translate F5 to Ctrl+G Ctrl+E. Since the ASCII value of Ctrl+E is 5, INFLD will translate this sequence to exitcode -5. (Ctrl+G was chosen as the lead-in since it is generally reserved for some non-editing auxiliary function in other editing utilities. Prior to version 6.1 however, INFLD used Ctrl+B for this function.)

Since you have to translate all function keys directly to EXITCODEs in the translation table when using FIXTRN or SET PFK to make your tables, the funmap parameter only controls which function keys will have command translations enabled. The standard plan would be to set up the .IFX module to translate all the F keys (that could ever be used for command EXITCODEs) as discussed in the preceding paragraph. Then the funmap parameter is set at runtime to enable selected function keys, according to the table above. For example, to enable F1, F3, and F5, you would set funmap = 1 + 4 + 16. The main difference here between using the proprietary translation architecture module and either of the SET PFK or FIXTRN architectures is that with the proprietary format, merely setting the appropriate bit in the (funmap) parameter will enable the function key, while with the SET PFK/FIXTRN formats, you have to both set the appropriate bit in funmap and define the appropriate translation within the .IFX module.

Since funmap contains only 32 bits, it can only enable/disable F1 through F32 directly. Any function key value beyond F32 is enabled by the high bit of funmap (2**31).

There are two other possibilities for command function key EXITCODEs. One is to key them in directly from the keyboard at run time. From a programming standpoint, the funmap parameter is used exactly the same with the alternate keyboard sequences as with the SET PFK or FIXTRN translations.

The other is to use the new A-Shell "virtual" function key codes, which are typically associated with clicking the mouse on a field or button. These are defined using the sequence chr(7) + chr(250) + "###." where ### may be any number, 1 through 99999. This method allows you associate a (negative) exitcode value with just about every object or command in your entire application. See the hlpidx parameter for associating such sequences with inactive INFLD objects, and AUI_CONTROL for associating them with other kinds of control objects (buttons, static text fields, etc.)


setdef

Updated and reviewed April 2013

setdef is a string specifying any of the following:

List of Valid Inputs

Dummy List of Inputs

List of Paired Inputs

Date or Value Range Checking

Form Field

Character Acceptance List

Regular Expression

Note that since the typical length requirement for the setdef string can vary widely, it is particularly convenient to map it as a dynamic string; see Dynamically-Sized S and X Variables|topic=Dynamically-Sized Variables.

See Also

• Invalid Input Message

• Setdef Limits


List of Valid Inputs

If the field is not a date, and the type { is not specified, then setdef is interpreted as a list of possible complete entries. When specified, the choices will display on the bottom line of the terminal (as many as will fit) to assist the operator (unless disabled with the s code). A null string disables the feature (accepts all inputs)

The format of the string is:

/x1/x2/x3/x4/..../xn//)

Where:

/ Represents the element delimiter. It may be any non-numeric character except the minus sign. We suggest slash or comma. Note that the delimiter character must appear once in the first position, once between each element in the list (all blanks are significant), and twice at the end of the list

xn - The elements x1, x2, etc., represent the allowable inputs. They may be any length (up to the length of the field) and may differ in length. All characters are significant, as is upper/lower case.

The list elements may contain any of the following wildcards:

Wildcard | Result
* | Matches anything. Used only at the end of an element.
? | Matches any one character.
# | Matches any numeric digit.
@ | Matches any alphabetic digit.

A-Shell (Only): In GUI mode (see GUI-related Codes code |G), a field with this type of setdef list will be converted to a drop-down combo box. The user can select an item from the list using the mouse, or type freely as before (provided the results match one of the entries in the list). Note that in this mode, the length of the items in the list may be longer than xmax, in which case the entry only has to match the first xmax characters of an item in the list (and only the first xmax characters are returned to the calling program). An example of a situation where this would be useful is a list of states, where you are only interested in the 2 character code, but to be helpful to the operator, the dropdown list could also contain the full name of each state (e.g. "CA California, WV West Virginia," etc.)

See Also

• type ||C for forcing the field to be displayed as a combo box even when inactive. Without ||C, after exiting from the combo box editing mode, the field will be redisplayed as a normal sunken, static text field.

• ||S and ||s for variations on the combo box matching logic.

• cmdflg INFCF_DROPDOWN flag to force drop-down to open automatically

• Auto-Complete


Dummy List of Inputs

In GUI mode, if setdef is set to three dots ("..."), then INFLD appears as combo box, but any action that would cause the drop-down box to appear (clicking on the drop down button or hitting Alt+Down) instead causes INFLD to exit with exitcode 29. The idea is to allow the application to then build its own list of choices based on the partial data entered in the field. See Self Service Combo Box.


List of Paired Inputs

If type ||L or ||l specified, then setdef is interpreted as list of pairs, where the first item in each pair is the abbreviated form and the second member is the descriptive form, i.e.:

/01/South/02/North/03/Middle Earth/04/Purgatory//

In the list above, 01,02,03 and 04 are the abbreviated forms what will be used by the application internally, whereas "South", "North", etc. are the descriptive forms that the user will user and type (or select from the combo box.) See the type code definitions for more details.


Date or Value Range Checking

For numeric fields, when the type v is specified, the setdef parameter must contain a two-element list consisting of the minimum allowed value and the maximum allowed value. For example, ",23,99,," would allow a range from 23 to 99. Note that the delimiter used to separate the two values must be a valid AMOS numeric delimiter, such as space, comma, or backslash.

For date fields, type v is not specified, and the setdef parameter may be used to specify the first and last allowable dates. To use this feature, specify a standard format setdef list with only two elements: the beginning and ending dates. The dates must be in YYMMDD (xmax=6) or YYYYMMDD (xmax=8) format (regardless of the input format).

Examples:

setdef string | Result
/M/F// | Matches only `M' or `F'
,TALL,SHORT,PORTLY,PETITE,, | Matches `TALL', `SHORT', `PORTLY', or `PETITE'.
|##-*|@@#|| | Matches anything starting with 2 numeric digits followed by a dash, or any 3 character field in which the first two are alphabetic and the third numeric.
\M@*\\ | least two alphabetic characters, with the first one `M'. (MR., MRS., MS., etc.)
\850101\851231\\ | When used with a date type code (D, d, or U), will match any date between 1-Jan-85 and 31-Dec-85, inclusive.
,-40,49,, | When used with type v in a numeric field, will match only values ranging from negative 40 to positive 49.


Character Acceptance List

The third way of using setdef is to specify a list of acceptable characters (rather than complete field entries). To use this method, specify the "{" code and then load setdef with a string of the characters you want to accept. Note that any input characters must first pass the normal type code test and then must be in the setdef string, so you may wish to specify the A type code as well. For example:

setdef = " 123ABCabc+-"

This would limit input to the numbers 1, 2, and 3; the letters A, B, C, a, b, and c; the plus sign, minus sign, and space. Note that upper and lower case must be listed independently.


Regular Expression

When the |s type code is specified, setdef is treated as a regular expression which the field contents must match.

Note that unlike most or all of the other setdef cases, in this case, no leading or trailing delimiters are used, just the regular expression itself.

Also note that in general, regular expressions can match anywhere in the field, which means that the field could contain additional leading or trailing characters which don't have any connection with the pattern. Typically this is not what you intended. To force the expression to match at the start and/or end of the field, you may want to include the regular expression anchor characters ^ (start of field) and $ (end of field). For example, let's say you want to only accept fields starting with an optional numeric digit and ending with a mandatory character in the range of a-z. Now consider the following two regular expressions:

setdef = "\d?[a-z]"

setdef = "^\d?[a-z]$"

The first expression is close, but would match a field containing "a!", since the first part of the pattern (the numeric digit) is optional, the "a" matches the second part of the pattern, and there is nothing preventing additional characters after that. The second version closes that loophole by forcing the start of the pattern to match at the start of the field, and the end of the pattern to match at the end of the field, eliminating the possibility of extra characters not envisioned by the pattern.


Invalid Input Message

(GUI mode only) When setdef is used to enforce a pattern or range or other limitation on the field, if the input does not pass muster, INFLD will display an error message saying "Invalid Input". The actual text of the message comes from SYS:SBRMSG.xxx message number 011,010. Since this can be frustrating for the user if the pattern or range is not obvious, INFLD will display the pattern string from setdef if you add a trailing "%s" to the message definition as shown here:

011,010,Invalid Input %s


Form Field

Updated January 2011; added February 2009

[ Type code = f ] Defines a "form" (also known as a "masked input"), the details of which are specified using the following special characters:

9 matches any digit

A matches any alphabetic character

X matches any character

Anything else is a "form background" character, which magically appear in the field when the field gets to the required size, and the cursor jumps over them as you type.

Examples

(999) 999-9999 (North American telephone number)

99-XXX-99 (e.g. 05-Feb-09)

Comments

• The form characters will appear automatically within the field as needed, and cannot be moved by the user, thus both simplifying and enforcing data entry rules. However, they are not returned with the field data (unless you add +8 to the opcode).

• In text mode, the form characters will appear even in an empty field, but in GUI mode, they do not appear until required by the number of characters entered. (This is because GUI mode usually involves proportional text, and since proportional spaces are so narrow, the form characters would probably initially confuse users.) If you want the entire form to be apparent at the start of entering a field, you may want to pre-fill it with (non-space) filler characters, such as "0" or "X".

• Any characters entered must satisfy both the form characters and the type codes, so generally you would use type * (all characters accepted) and rely on the form characters to further limit it.

• If xmin is shorter than the form length, the user will not be required to enter the remaining characters. For example, an extended zip form of "99999-9999" would allow an entry of "12345" if xmin <= 5.

• As of 5.1.1200, forms may be used with date fields, although the form must contain only two separator characters and they must be in the 3rd and 6th position of the form, which must otherwise contain all 9's. (For example, "99/99/99" and "99-99-9999" are acceptable, but " 99 - 99 - 99" would not be, because of the extra spaces.)


Setdef Limits

Note that under ATE, by default, the maximum length of setdef is 3072 bytes. Beyond that, you will arguably be better off using a control such as XTREE. But if you can expand that limit by executing the following command:

PRINT TAB(-10,42);BUFSIZ;chr(127);

where BUFSIZ is the new maximum length of the ATE command buffer. The buffer must be large enough to handle all of the arguments of INFLD, which for the purposes of combo boxes, mainly just means the maximum size of setdef, plus perhaps another 1K to handle the rest of the parameters.

The maximum size of a setdef match is 300 characters. Prior to A-Shell 5.1.1111 of May 08, it was 50 characters.


infclr

Updated June 2011; see History

infclr allows the specification of various color palettes which are then automatically invoked for the corresponding situations. If specified, it must be mapped as in the file INFPAR.BSI. See the following topic for an alternative.

The effect of any of these colors can be disabled by setting it to -1, which causes INFLD to use the color setting which was in effect when INFLD was called. The standard AM72 color selections range from 0-15, where 0 is usually black, so if your field seems to disappear, you should check if you accidentally left any of the color palettes 0 on 0 (black on black).

Color | Codes | Description
Display | DFCLR, DBCLR | Used when INFLD is called to display a field (OPCODES 2, 4, 10 and 12). The editing colors (EFCLR and EBCLR) are used while you are editing a field (unless it is a negative number). Setting DFCLR and/or DBCLR to a palette index value +64 overrides the theme color (provided you don't have the Settings > Misc option to "Force standard colors in edit boxes" set).
Negative | NFCLR, NBCLR | Override the editing palette whenever the field contains a negative number. The color change occurs instantly whenever you enter the minus sign or plus sign keys to change a number's sign.
Negative foreground | NFCLR | Also overrides the display and update foreground colors (DFCLR and UFCLR) whenever the field is negative. Typically, NFCLR will be red (#4 on the standard AM72 palette).
Update | UFCLR, UBCLR | Used to redisplay the field after editing, regardless of whether the field was changed. The intent of this feature is to indicate which fields have been edited on a "CHANGE" screen; we recommend a color very similar to the display color.
Message | MFCLR, MBCLR | Used for displaying any auxiliary messages, like time out, invalid entry, help available, etc.
Original | OFCLR, OBCLR | Used when clearing any messages. You should set them to match the normal color scheme of the area where messages will be displayed. These are also used to specify the color scheme for the text portion of a checkbox or radio box. See TYPEs "||c" and ""||r" in the GUI-related Codes section.
Forms | FFCLR, FBCLR | Used to display the literal characters embedded in a form string (see type f.)

INFLD will automatically return to the pre-existing color scheme on exiting from a field, so you do not need to worry about it changing your ambient colors.

INFLD does not check whether your terminal supports color, relying instead on your terminal driver to discard unsupported commands. You should program as if color was supported, since in most cases, color will have no effect on monochrome screens (unlike the PC where color commands may be interpreted as other video effects on monochrome monitors). However, by passing all color commands to the terminal driver, we leave you the option of modifying the driver to substitute color commands for some other attribute. (Should you attempt this, note that the color commands should not occupy a space, and operate as mode attributes.)

Note: In GUI mode, there is a convenient option in the Misc. Settings dialog which overrides infclr to force INFLD to use the standard Windows color scheme (typically black text within a white edit box). See History, below.

The infclr parameters will be ignored in both of the following situations: 1) When the "Force standard Windows colors in edit boxes" option is checked (in the Misc. Settings Dialog); 2) When XP Themes are active.

As a convenience to those not interested in infclr but who want to use a subsequent parameter, the infclr parameter (normally a mapped structure) may be reduced to numeric zero. Thus, for example, you can call INFLD to input an alphanumeric scrolling field with an editing window width of 60 characters and a maximum width of 150 characters as follows:

xcall INFLD, row, col, 60, 0, "a", entry, inxctl, 1, 0, exitcode, timer, 0, -1, -1, 0, "", 0, "", 150

History

2013 August, 6.1.1360: Added topic ST_INFCLRX, which see for details.

2013 July, 6.1.1355: When the "Force standard colors in edit boxes" option is set in the Misc. Settings dialog, INFLD will now display negative values (for fields with the "-" TYPE code) in red, regardless of the INFCLR settings. INFCLR is largely ignored when the "Force standard colors" option is set.

2011 June, 5.1.1220: Checkboxes and radiobuttons now automatically use the transparent background feature, UNLESS the OBCLR field of the INFCLR parameter is greater than zero.

2010 June, 5.1.1184: Setting the DFCLR and/or DBCLR fields of the INFCLR structure to a palette index value +64 now overrides the theme color (provided you don't have the Settings > Misc option to "Force standard colors in edit boxes" set).

Subtopics

ST_INFCLRX


ST_INFCLRX

Added August 2013

INFLD enhancement: new structure ST_INFCLRX (defined in INFLD.SDF) may be used in place of the INFCLR parameter to define arbitrary foreground and background (RGB) colors that will be used by INFLD when displaying and optionally when editing the field. The structure format is as follows:

defstruct ST_INFCLRX

map2 sig,s,2 ! must be set to "x1" to activate

map2 flags,b,2 ! INFCLRXF_EDTCLR (=1) to use d?rgb for edit also

map2 dfrgb,b,4 ! display foreground

map2 dbrgb,b,4 ! display background

endstruct

Notes

• The sig member must be set to "x1" or the structure will be ignored. It allows A-Shell to distinguish between the ST_INFCLRX structure and the old INFCLR structure, which is still supported. You may set it to "" if you are passing the new structure but want to continue to use the default color logic.

• The d?rgb colors are used when INFLD displays the field, either after or instead of editing, and also when "editing" read-only fields. In addition, they will be used for editing other field types if the flags member is set to INFCLRXF_EDTCLR (1).

• To override only the background or only the foreground color, set the other color field to -2.

• In the ATE environment, both server and client sides must be updated to 6.1.1360.2+ for this to work. Otherwise it will revert to the old behavior of using default colors.

• The new structure is intended for the GUI environment; for text mode programs, you should stick with the old INFCLR structure.


hlpidx

hlpidx is ignored under AMOS, and may be used for any combination of Tool tips, Mouse Click Strings, Help Keys, Context Menu Handling, and Placeholders. Note that since the typical length requirement for the hlpidx string can vary widely, it is particularly convenient to map it as a dynamic string; see Dynamically-Sized S and X Variables|topic=Dynamically-Sized Variables.

Subtopics

Tool tips

Mouse Click Strings

Help Keys

Context Menu Handling

Placeholders


Tool tips

In GUI mode, you may specify a "tool tip" (a short text message which appears automatically when the mouse idles over the field position for a second or two). These are handy for giving the user additional prompt information that would otherwise clutter up the screen. The format is simply a ">" followed by the text you want to appear.

Example

hlpidx = ">This is a tool tip"


Mouse Click Strings

Revised and reviewed May 2012

In order to implement the effect of allowing a user to be able to click on a field in order to edit it (as is typical in Windows forms), you need some way of telling your application that the click event has happened. The recommended way to do this is to encode unique high-numbered pseudo-function-key exit codes with each field. The format for this is:

"~" + chr(7) + chr(250) + "###."

or

"~VK_xF###"

In the above examples, note that each starts with a tilde, i.e. "~" or chr(126) which signals the end of any prior clause and the start of the click string definition. The two variations are equivalent, with the second one being the newer (easier to type and to read as text) format. Note that the trailing decimal point is mandatory in the first format, and not used in the second format. The ### characters (which can be as few as 1 digit and as many as 6) indicate the number of the pseudo-function key. For example, the number 231 would indicate the pseudo-function key 231, and would cause the current event-sensitive operation (INFLD, XTEXT, XTREE, AUI_EVENTWAIT, etc.) to return with exitcode -231.

To further clarify with an example, let's say you have a screen with 20 fields, each using the above technique to associate itself with a pseudo-function key 201 thru 220. If the user is currently editing field 1 and then clicks on field 15, the INFLD call to edit field 1 will return with exitcode -215, allowing the program to do any post-field processing on field 1 and then proceed to edit field 15. Obviously this requires more programming effort than a purely sequential input scheme, but is amenable to various systematic approaches, including AUI Eventwait.

If hlpidx contains both a tool tip and a mouse click string, the tool tip must be in the first position, followed by the chr(126) (or tilde), and then the mouse click string, e.g.:

hlpidx = ">Tool tip first" + "~VK_xF231"

Comments

The click string syntax and behavior is common to most other GUI-enabled controls / subroutines, including AUI_CONTROL, XTREE and XTEXT, with the only difference being INFLD's requirement of the leading tilde—which is required because hlpidx is used for multiple things.

INFLD also supports a more primitive (now deprecated) mouse click response mechanism termed Mouse Cursor Reporting. When active, INFLD treats a click outside of the field as an exit condition, returning exitcode -47. You can then retrieve further information about the last click by calling MX_MCRS.


Help Keys

The original intended use for hlpidx was to store a string to be used as key to link to some information in a help database. Sadly, this has yet to implemented as originally envisioned (i.e. as something INFLD would respond to without the application being aware of it), but the possibility remains. And until then, many applications may find it useful to use the parameter as envisioned in order to implement their own help logic in a routine which serves as a wrapper to INFLD.SBR.

If HLPDIX contains a traditional help key in addition to a tool tip and/or mouse click string, then the help key string must be first, e.g.:

hlpidx="Traditional help key>Tool tip next" + chr(126) + Chr(7) + chr(250) + "213."


Context Menu Handling

Added February 2010

(Beginning with A-Shell 5.1.1175 of 12 February 2010) You may replace the standard context menu for normal INFLD edit controls and also INFLD combo box controls by adding the desired context menu definition string to the tooltip string (which is itself part of the hlpidx parameter). The syntax is:

>tooltip\menudef

The backslash marks the end of the tooltip definition and the beginning of the menudef string. The menudef syntax is the same as that for XTREE PopupMenu definitions, i.e.:

text,command;text,command; ... ;text,command

The command fields may be either virtual keycode strings (e.g. VK_xF101), or arbitrary text (optionally containing control sequences using ^ as the lead-in), or $CUT, $COPY, or $PASTE (for the standard clipboard operations).

The text fields will be displayed in the context menu as-is, with the exception of "--------" which displays a separator line. For example:

>tip\Cancel,VK_ESCAPE;All,*^m;--------,;Cut,$CUT;Copy,$COPY;Paste,$PASTE

The above tooltip string defines a tooltip "tip" and a context menu with the following options:

"Cancel" sends an escape (VK_ESC). "All" enters the character "*" into the field followed by a carriage return (*^m). "Cut", "Copy", and "Paste" act like the standard operations.

Note that the hlpidx parameter may contain a help key, a tooltip, a context menu definition, and/or a click command, but they must be in the following order:

help key >tooltip \menudef ~clickcmd

Furthermore, if you have a menudef but not a tooltip, you must specify the ">" anyway, e.g.:

help key >\menudef ~clickcmd

This latter condition avoids compatibility issues with help keys that might contain "\", although any existing tooltips which contain "\" will be effectively truncated at that point, with a probably non-functional context menu replacing the standard one. While this could be annoying, it seems remote enough and not critical enough to go to additional lengths with cumbersome syntax to avoid.


Placeholders

Added October 2015

Placeholders, also called cues, are short messages that appear inside an INFLD/EDIT control when the control is otherwise empty. They are useful for giving the user tips as to what the field would or should contain, without requiring additional screen real estate for labels/prompts or user action to display a tooltip.

To specify a placeholder, embed it at the start of the tooltip string, enclosed in [brackets]. Note that INFLD tooltips are defined within the hlpidx parameter, starting with ">", for example:

hlpidx$ = ">[tax id]For businesses use the employer id~VK_xF123"

Compatibility: No dependency on the server version. Requires client 6.1.1419 to recognize the placeholder; older clients will treat it as part of the tooltip, which should be harmless.

History

2015 October, A-Shell 6.1.1419: Added feature to A-Shell


maxchrs

May be used to separate the display width of the field from the maximum number of characters that can be entered. Normally the objective here is to allow a longer string to be input than screen real estate would otherwise allow. This is accomplished by scrolling the field horizontally within the display width defined by xmax. A secondary motivation presents itself in the GUI proportional font environment, where you might want to make xmax larger than maxchrs in order to allow for the possibility that all the characters entered are wider than average, and thus would not fit within the display box size based on xmax.

For example, a two-character state field is likely to have this problem. The field display width is calculated based on the fixed pitch font size times the xmax value. In most cases, this is more than wide enough for proportional fonts, which "on average" are more compact than fixed pitch fonts of the same point size. But capital letters, particularly in a combination like "WY", are likely to require more space. In this case, setting maxchrs to 2 and xmax to 3 might be a good idea.

If maxchrs is omitted or equals zero, it is treated as being equal to xmax.

Horizontal scrolling: The parameter maxchrs, which is only supported in the A-Shell version of INFLD, may be used to specify a maximum horizontal scrolling width. If specified, and if larger than xmax (the field editing width) then the field will support up to maxchrs characters, scrolling horizontally as required within the display window defined by row, col and xmax.

As a convenience, especially to those interested in using the horizontal scrolling feature but who do not care about color, the infclr parameter (normally a mapped structure) may be reduced to numeric zero. Thus, for example, you can call INFLD to input an alphanumeric scrolling field with an editing window width of 60 characters and a maximum width of 150 characters as follows:

xcall INFLD, row, col, 60, 0, "a", entry, inxctl, 1, 0, exitcode, timer, 0, -1, -1, 0, "", 0, "", 150


INFLD External Parameters

In addition to the calling parameters, there are several external parameters which affect the operation of INFLD.

Parameter | Description
Language Definition File | INFLD gets a number of format and character symbol options from the Language Definition File (LDF) for your job. If no LDF file is in effect (on older versions of AMOS), the USA defaults are used.
Set type code | AMOS only. See INFLD Definition File.
Set type code | This is the A-Shell equivalent to INFLD.DEF. The command SBR=INFDEF:<type code string> is placed in the A-Shell configuration file (miame.ini) and processed when A-Shell starts up. After that, the specified type code string is added to the end of the type parameter each time INFLD is called. (except when the m code is used.)
Century Definition | The miame.ini parameter SBR=CCYY:## may be used to change the cutoff for which years are assumed to be part of the current 19xx century. Any year greater than ## will be assumed to be 19##, while any year equal or less than ## will be assumed to be 20## (unless overridden by some other parameters). Note that this applies to ODTIM and IDTIM as well as INFLD.
SBR= | Because many dealers have modified their version of INFLD and want their modifications to be standard in A-Shell, we have added a number of other option switches that can be installed into A-Shell using the SBR= parameter in the miame.ini file.


INFLD Definition File

INFLD looks for INFLD.DEF in system or user memory at runtime. If found, it reads the first line of characters from the file and interprets them as additional type codes. This is a handy way of experimenting with many of the miscellaneous and timer-related type codes which you could safely add to any category of field.

To create the INFLD.DEF file, just use VUE or another editor to create an ordinary text file whose top line is a string of valid type characters. Save the file to disk and use the LOAD or SYSTEM commands to load it into user or system memory.

Searching for the INFLD.DEF file adds another few jiffies of execution time to INFLD. You can reduce this by loading INFLD.DEF into memory immediately after the INFLD.SBR. (INFLD checks there first before doing a general search.) If you are not using the INFLD.DEF facility, you can disable the search for it in memory by using the "m" type code.


Keyboard Commands

Added March 2011

Key | Description
Ctrl+A | If |K, select field, else if |a, exitcode 19. Else previous word.
Ctrl+B | If |B, exitcode 16, else ignored
Ctrl+C | See Ctrl+C Behavior.
Ctrl+D | Same as Delete
Ctrl+E | Same as End
Ctrl+F | Insert space
Ctrl+G | If SBR=TTI_PGRW, exitcode 8, else ignored
Ctrl+H | Same as LeftArrow
Ctrl+I | Same as Tab
Ctrl+E | Same as End
Ctrl+F | Insert space
Ctrl+G | If SBR=TTI_PGRW, exitcode 8, else ignored
Ctrl+H | Same as LeftArrow
Ctrl+I | Same as Tab
Ctrl+J | Same as DownArrow
Ctrl+K | Same as UpArrow
Ctrl+L | Same as RightArrow
Ctrl+M | Same as Enter
Ctrl+N | Move cursor to end of field
Ctrl+O | If |B, exitcode 17, else ignore
Ctrl+P | If |Q, exitcode 25, else launch Screen Pictures utility
Ctrl+Q | Toggle insert/replace mode (see INS)
Ctrl+R | Same as PageUp
Ctrl+S | If |C, exitcode 26, else ignore
Ctrl+T | Same as PageDown
Ctrl+U | If |U, exitcode 21, else move cursor to start of field
Ctrl+V | If |K paste contents of clipboard, else delete word
Ctrl+W | If |W, display "Not Processed" message and set exitcode 1
Ctrl+X | If |X*, treat like Ctrl+*; else fold the field contents. See note 1 below.
Ctrl+Y | Delete to end of field
Ctrl+Z | If |Z, exitcode 18, else if |K undo last delete, else delete entire field
Ctrl+[ | Same as Escape
Ctrl+\ | Display information dialog showing current INFLD parameters
Ctrl+^ | Same as Home
Enter | If ||T, exitcode 7 (as if Tab); else exitcode 0. See Force destructive enter
Esc (Escape) | If E, exitcode 2, else if 1, exitcode 1
Del (Delete) | Delete character (or all selected characters) (Same as Ctrl+D)
Ins (Insert) | If GUI mode (|G) or |K, toggles insert/replace mode (same as Ctrl+Q); else inserts a space (same as Ctrl+F)
Home | If 9, exitcode 9, else if |K or |M treat like Ctrl+U (move to beginning of field or line) (Same as ^^)
End | If k, exitcode 15, else if |K, end of field, else if neither W nor C, exitcode 1 (Same as Ctrl+E)
Tab | If T, exitcode 7, else if |K tret like Enter
Shift+Tab | If |G (GUI mode), then if |2, exitcode 2, else if treat like UpArrow. Ignored in non-GUI (text) mode.
PageUp | If 4, exitcode 4, else ignore (same as Ctrl+R)
PageDown | If 6, exitcode 6, else ignore (same as Ctrl+T)
LeftArrow | If cursor not in first position, move cursor to left, else if E or 2, exitcode 2, else if |p treat like Enter. See note 1 below.
UpArrow | If 2, exitcode 2, else if 3 or |3 exitcode 3, else ignore. See note 1 below.
RightArrow | If |L exitcode 12, else if L and cursor at right end of field, exitcode 12, else move cursor right. See note 1 below.
DownArrow | If ||a jump into drop-down (auto-complete) box, else if 5 or |5 exitcode 5. See note 2 below.
Alt+Backspace | If |K, undo last delete
Alt+<any character> | If a control in the current window context uses the specified character as an accelerator, acts like the control had been clicked (typically this will generate the exitcode associated with the control) See the AUI_CONTROL cmd parameter for more information on defining the click action for a control.

Note 1: In Ctrl+*, the * (asterisk) may be any character A through Z plus [,],\,^,_). The fold operation is a three-way toggle between all upper case, all lower case, title case.

Note 2: In some contexts, like within special-purpose GUI controls such as the date picker or up/down control, the arrow keys may only work within the control. In such cases, to get the exitcode behavior described in the table above, you can use Ctrl+Arrow.


Screen snapshots

Most of the differences between the AMOS and A-Shell versions are only relevant to system-level programs, but there are some differences that may affect ordinary users. One is that the Ctrl+P command, under the A-Shell version of INFLD, brings up a screen snapshot utility. The utility gives you the option of printing a copy of the screen, and/or just saving it in the file <jobname>.BUF. If saved, subsequent pictures will be appended to this file, creating a snapshot log which could be useful in a variety of situations (documentation, error reporting, etc).

The name of the screen snapshot capture file can be changed using the –b and –ba A-Shell command line switches.


Pop-up Utilities

Another unusual feature implemented only in the A-Shell version of INFLD is the pop-up utility command. This command will launch a new session directly on top of the existing one and start it running BAS:ASHPOP.RUN, which is intended to be a small pop-up utility (or menu of utilities). The command itself is defined and activated by means of the type code string |Px (where x is the command letter to be combined with the Control key). For example, if type contained |P] then Ctrl+] would launch the ASHPOP utility. A-Shell is released with a sample ASHPOP that displays a simple menu of two choices, one of which then refers to another utility, ASHCAL, a simple calculator. The source for both can be found in DSK0:[7,376] As an added convenience, the calculator will write the accumulated result to a file MEM0:<jobnam>.CLP[1,1] if you exit with Tab, and INFLD will pick up the results from that file and load it into the current field. This of course requires that the disk device MEM0: be defined and that a ppn [1,1] exists. If you want this feature available all the time, then add the type code to the default string in miame.ini (e.g. SBR=INFDEF:|P]. You may want define a control key other than Ctrl+] though, since Ctrl+] is the terminator key for some telnet utilities.

A number of differences between the two versions can be .adjusted by means of SBR statements in the miame.ini file|topic=SBR.

If your application was previously using INPUT.SBR, and you want to preserve all of the idiosyncrasies of INPUT.SBR, then use SBR=INFDEF:|p in the miame.ini file to invoke "prehistoric compatibility mode."


Telnet Keepalive

(A-Shell/UNIX only) Adding SBR=INFLD_KEEPALIVE to the miame.ini causes a harmless byte sequence to be sent every 15 seconds while waiting for input within INFLD (which includes the dot prompt and BASIC INPUT statements). This serves two purposes. First, it will prevent connections from being dropped due to lack of activity while they are actually in a program waiting for input. Second (and perhaps more important), it provides a mechanism for UNIX/Linux servers to detect connections that have been dropped (without having to wait for the standard keep alive timers to expire, which by default may run to 2 hours). This way, within 15 seconds of the connection being dropped, the server will send a packet, which cannot be delivered. This should trigger a retry timer which will try to resend the packet some number of times before concluding that the connection is dead. This process is generally much quicker than the keep alive detections process.

The inxctl parameter to INFLD may now be specified as a one byte string or binary, in which case it returns the actual character used to exit the field. This is more useful to many people than the rather limited information provided by the traditional inxctl.


Ctrl+C Behavior

The following chart summarizes the behavior of ^C in various situations:

Ctrl+C Status | Type V | Type ||K | Type |K | Result of Pressing Ctrl+C
* | V | * | * | Exitcode 10
* |  | ||K | * | Copy to clipboard
disabled |  |  | |K | Copy to clipboard
disabled |  |  |  | Nothing
enabled |  |  | * | BASIC error 1

* Indicates that the setting doesn't matter, given the other settings on the line. Blank indicates that the specified TYPE code is NOT set.


INFLD Font Size Calculation

Added October 2012

When using scaled fonts in the main window, the INFLD font size is no longer reduced to agree with the combo box font unless the "Force edit box height to match combo" option is selected (in the Settings > Misc dialog). To clarify the effect of the "Force edit box height to match combo" option:

When checked, then both the combo box and edit box will have the same height, which will be just slightly less than the row height (subject to the "allow edit boxes to use leading" option). They will also use the same font. Because the combo box has more internal margin than the edit box, the resulting edit font size will be somewhat smaller than it otherwise could be, given the height of the edit box.

When not checked, the edit box will still be the same size as before, but the scaled font size will not be constrained by the combo box metrics. Instead, the combo box height will adjust to the font. The result will usually be a larger font, but at the possible cost of the combo box being taller than a row. This may be ok if you rarely use combo boxes or allow extra space below them.

History

2012 November, A-Shell 6.0.1262: Feature added


Update Notes

901 - 19 Sep 04

(Windows/ATE) When INFLD displays a message box (typically to report an editing format error), the title of the message box is now taken from the 000,001 entry of the SYS:APPMSG.xxx file (where xxx is your language definition, e.g. "USA", "CDN", etc.) If the file or entry is not defined, then it continues to use "INFLD".

897 - 10 Aug 04

(INFLD GUI) The handling of fixed pitch fonts in the GUI version of INFLD has been improved somewhat. Unlike proportional fonts (which we only scale vertically and let the horizontal size default based on the display aspect ratio and judgment of the font mapper), fixed pitch fonts can be scaled both vertically and horizontally. We use this to ability to try to generate a font that fits within an INFLD edit box in such a way that the box gets filled up when you get to the maximum number of allowed characters for that field. (With proportional fonts, this is out of the question.) Note that because fixed pitch fonts are currently scaled to an integer width in pixels, as a practical matter, the maximum number of characters is not going to exactly fill the box. But it should be reasonably close. If you cannot stand that imperfection, you might have to just give up on the GUI version of INFLD and continue to use the text version.

Note that along with the scaling improvements, we've reduced the degree of automatic expansion of small field lengths. Previously, 1 and 2 character fields were expanded by one character (to allow for font size irregularities.) When the fixed pitch option is set, we now only expand single character fields to 2 column (mainly because the edit window border reduces the available size of the field by so much that a single character field is just too skinny to look good.)

896 - 20 July 2004

(WINDOWS/ATE) The INFLD combo box (activated when you have a "normal" setdef list and |G) can now accommodate about 1200 bytes of options in the setdef parameter (up from 512 previously). For choosing from lists longer than that, you might as well just use PCKLST or XTREE.

895 - 20 July 2004

(WINDOWS/ATE) GUI version of INFLD now obeys the infclr settings. Previously, while editing, it always used the standard Windows colors. If you want to keep that behavior, set EFCLR and EBCLR to -2, either in the infclr parameter passed to INFLD, or in the INI.CLR file.

(WINDOWS/ATE) A new option to "use fixed pitch font in edit boxes" has been added to the Misc Settings dialog. When set, INFLD uses the currently defined fixed pitch font (see Settings...Fonts) and attempts to scale it slightly down to fit in the edit window better. It does not completely eliminate the complaint that the size of the edit window does not perfectly match the number of characters which are allowed, but now the edit windows will more or less uniformly appear to have room for one more character than is allowed. (This is necessary, otherwise Windows will not display that last character without scrolling the field.) Note that when you edit the field it will be redisplayed using the defined "proportional" font. If you do not like the drastic change between the fixed pitch (in edit mode) and the proportional pitch (upon display), then you can always set the "proportional font" to the same as the fixed pitch font, in which case all of the GUI controls will use it.

Update: Build 881 - 14 Apr 2004

INFLD supports a new mechanism for encoding pseudo-function keys which works better in heterogeneous environments involving ATE or the Windows control implementation of INFLD. The new scheme also allows for an unlimited range of virtual function keys (whereas the previous scheme only really supported F1 through F127.) The new encoding format is:

CHR(7) + CHR(250) + FNUM$ + "."

where FNUM$ is the string representation of the function key number (e.g. "1" for F1, "793" for F793). Since the number has a variable length, a terminator character is required. In the above example we use a period, but any non-numeric character will work.

As an example, if you want to set up an INFLD field so that when you click on it, it acts like a virtual F122 (i.e. returning exitcode -122), then you could set the hlpidx string as follows:

hlpidx = chr(127) + chr(7) + chr(250) + "122."

As of Build 883, this syntax as been changed to:

hlpidx = chr(126) + chr(7) + chr(250) + "122."

Note that this takes advantage of an INFLD feature relating to hlpidx. The leading CHR(127) is needed to tell INFLD that what follows is a mouse click string.

Update: Build 882 - 18 Apr 2004

In INFLD, when inxctl is a one byte string and the use transmits the new pseudo function key sequence, inxctl will return 250. (This allows these sequences to be distinguished from the normal IFX function sequences, which set inxctl to 7.) This distinction is useful when the new pseudo-function key sequences are used to encode mouse clicks, thus avoiding the need to start the mouse pseudo-function key codes at some offset to avoid confusion over F-key generated function codes.

The INFLD edit control (|G) now uses the type sequence |K to determine whether to adopt Windows-style or AMOS-style conventions whenever the two are in conflict. For example, without |K, the initial input mode is overwrite; with |K it is insert. (You can now use the Insert key to toggle between insert and overwrite mode.) Without |K, the Home key is considered a field exit key (returning exitcode 9 if type 9 is specified); with |K, Home just moves the cursor to the start of the field (but you can use Ctrl+Home to get the exitcode effect.

Update: Build 885 - 03 May 2004

INFLD now uses a date-time "picker" control for date (type D) and time (type t) fields when in GUI (type |G) mode. Note the following idiosyncrasies of this control:

• The date picker takes up more space than the traditional MMDDYY (or DDMMYY) format of date entry, so the control is automatically elongated by a few extra columns. Although this might possibly overwrite something to the right of the control, the effect is only temporary, since as soon as you exit from the control, it is redisplayed using the normal size and format.

• If you set xmin to 0, the date picker control will include a checkbox which the user can uncheck to indicate no date. Otherwise there is no way to enter a blank (or invalid) date.

• The left and right arrow keys will move between the sub-fields of the date or time. If you want to pass these arrow keys to INFLD (to be treated as possible field exit keys), you will have to hold down the Shift or Ctrl buttons while hitting the left/right arrows.

• To edit each sub-field, you can use the number keys, or the numpad +/- key. In the case of the time control, you can also increment/decrement it using the up/down buttons which will be appended to right edge of the field.

Update: Build 885.2 - 06 May 2004

INFLD/GUI keyboard handling refinements:

• Alt+Down+Arrow may now be used as a keyboard shortcut to display the calendar in the date picker.

• Up/Down+Arrow may now be used, in addition to the numeric keypad Plus and Minus keys to increment/decrement the currently selected sub-field (in the date picker).

• Shift+Tab now acts like UpArrow when type 3 is specified (returning exitcode 3).

Update: Build 892 - 10 Jun 2004

(Windows/ATE) Checkboxes and radio buttons can now be created and accessed by INFLD similarly to other field types. (In particular, checkboxes correspond well to Y/N fields.) The type code for checkboxes is "|c" and for radio buttons is "|b" (vertical bar followed by a lower case "c" or "b"). If combined with type Y, the field will treat a checked box as equivalent to the single character affirmative (Y, S, O, etc.) for the current language definition, and an empty box as the single character negative (N). Otherwise, a checked box will correspond to a "1" and an unchecked box to a "0".

Note the following idiosyncrasies of checkboxes and radio buttons as INFLD field types:

• Checkboxes and radio buttons combine a text field with a square or round box. Although other fields may also associate an edit control with a text prompt, in all other cases, INFLD does not concern itself with the text prompt (which much be displayed via a separate operation). When a particular checkbox or radio button is being edited by INFLD, the corresponding text will be highlighted via a dotted line, giving the operator a visual indication of what field they are on. (There is no cursor for checkboxes and radio buttons.)

• Because of this association between the text and the box or button, if you want to use INFLD to create the control, you must supply the text string (label or prompt) in the setdef parameter. setdef does not otherwise apply to these two field types. This is not to be taken as a recommendation that you use INFLD to CREATE checkboxes and radio buttons.

• In contrast to the case with other field types, in which the field becomes an editable control when it has the focus and is converted back to a static/sunken text control when not being edited, checkboxes and radio buttons remain the same whether they have the focus or not. The only visible difference when they have the focus is the dotted outline described above.

• Because of the above, it is typical for checkbox and radio button fields to be created at the same time that your program normally creates the data entry form background. You can create them for display purposes either using AUI_CONTROL, or AG_CONTROL|topic=Edit GUI Control), or INFLD. Once created, when you want to edit the field, INFLD will locate the existing control, if it exists, by looking at the row, col, and V parameters. (If V is < 0, it is taken as the actual control ID number of a control previously created with AUI_CONTROL, and row and col are ignored. If V > 1, then it is treated as the control ID number of a group box to which the checkbox or radio button belongs, and the row and col parameters are offset within the group box.) Unless V identifies the control directly, the existing controls are scanned to find one which has the same starting row/col, or the same ending row/col. The point of comparing just the starting or just the ending position is that after having created the checkbox/radio button control, you may want to treat it like Y/N field, in which case you would probably be specifying a field of size 1 (even though the full control will be several columns wide due to the text component.)

• When INFLD is operating on a checkbox (and the corresponding text is highlighted), you can toggle the check status with the space bar, or by clicking with the mouse. You can use Enter to exit, or any of the other field exit keys which you've enabled according to the normal INFLD rules.

• When INFLD is operating on a radio button, the button that has the focus will automatically be selected (as if you had clicked it with the mouse.) You cannot toggle the button with the Spacebar (partly because it would not then be clear which other button in the group should be toggled on.) (Because it is a radio button and not a checkbox, only one button in the group, at most will be checked at one time.) Considering this idiosyncrasy of radio buttons, they do not work that well as INFLD fields unless your users are prepared to use the mouse to jump to the next non-radio button field. (Otherwise, unless you enable a specific exitcode to jump from the current button to the next group of controls, there would be no way for the operator to keyboard through a group of radio buttons without leaving the last one selected.) Thus, it may make more sense to treat radio buttons more like pushbuttons, i.e., as controls that are not operated on directly by INFLD but instead are available for the user to click on at will, with the program querying them before processing the screen data.

When treating checkboxes and radio buttons like normal INFLD fields, there may be some confusion over the following similar situations:

• While within an INFLD call targeting a specific checkbox or radio button, the field will visibly maintain the focus and all keyboard will be filtered through the control. (The result is that other than space bar and defined exit keys, any other keys will probably be ignored.) Clicking on another field may or may not cause the current field to lose focus, depending on various factors.

• If you click on a checkbox or radio button while another INFLD field is active, unless the clicked-on control is set up to transmit an exitcode which will cause the currently active field to exit and the program to jump to the just-clicked field, although the click operation will change the checked status of the checkbox or radio button, the clicked-on control will not retain the focus. Instead, the focus will revert back to whatever field was previously doing input. The point of this is that if you choose not to use INFLD to individually edit your checkboxes, you can use a single generic input routine which just waits for you to exit the current screen (presumably by clicking on a button or entering a special code or key). Clicking on individual boxes in this case will change the status of the checkboxes, but not interrupt the current input operation. (You can query the checkboxes or their control variables all at once when you decide to leave or update the screen.)

Update: Build 892.4 - 17 Jun 2004

INFLD now implements fields which have a "normal" setdef parameter (containing a list of allowed entries, e.g. ",red,blue,green,purple,,") as combo boxes. User can type or select choice from drop-down box. As before, to allow an empty field, add type O (for optional).

Update: Build 893 - 24 Jun 2004

(Windows/ATE) Checkboxes created with INFLD now have the MBF_UNPROTECTED flag set so they can be deleted with Tab(-1,10) (more like static text than like regular buttons).

Update: Build 894 - 28 June 2004

(Windows/ATE) Several improvements have been made to checkboxes (now type ||c), allowing them to be handled nearly like Y/N fields. Contrary to the recommendations set out under edit 892, our latest recommendation is to either use INFLD for all aspects of checkbox implementation (creation, display, editing), or use AUI_CONTROL for all aspects. You can mix the two (i.e. create the checkbox using AUI_CONTROL and edit it with INFLD, but this is likely to cause confusion.) If you use the AUI_CONTROL method, then your program does not need to monitor the user while editing the checkboxes; you only need to query the checkboxes at some later time to see which ones are checked. In contrast, if you use the INFLD method, then you should implement an exitcode sequence allowing the user to go directly to a checkbox field by clicking on it, and treat it almost just like a normal Y/N field.

The main differences between Y/N fields and checkboxes are:

• The text label of the checkbox is an integral part of the control. You must pass the label in the setdef parameter, and set the xmax value large enough to accommodate the label (instead of just 1 which would be typical for Y/N fields.)

• The user toggles the checkmark with the mouse or the space bar.

• The OFCLR/OBCLR fields in infclr are now used to set the color of the checkbox label text when displaying or redisplaying the checkbox.

Note that, at this time, we are only encouraging the use of INFLD for checkboxes, and not radio buttons. In most cases, a single combo box (see 892) is much cleaner to simpler than a series of radio buttons. If you insist on radio buttons, it is probably best to just implement them using the AUI_CONTROL method.


INIX

Documentation added May 2016

xcall INIX, inifile, opcode, section, item {, value, dftvalue}

INIX.SBX reads/writes from standard "INI" files, which are ordinary text files, typically with a .INI or .CFG extension, which are made up of one or more groups (sections) of item=value pairs as follows:

[section]

item1=value

item2=value

etc.

Because these files can be edited in a standard text editor, and because comment lines beginning with a semicolon may be inserted anywhere, the format is both easy to use and self-documenting. There is no particular limit to the number of items or sections, but each item name within a section must be unique.

Source, samples and related functions can be found in SOSLIB:[907,26].

Parameters

inifile (String) [in]

File spec of the INI file.

opcode (Num) [in]

Operation to perform:

Value | Meaning
0 | Read single item=value pair
1 | Write single item=value pair
2 | Delete single item=value pair
3 | Delete complete section

In addition, you may add either or both of the following options in the ATE environment:

Value | Meaning
+16 | redirect the operation to the ATE client
+32 | first sync INIX.SBX from the server to the ATE client

section (String) [in]

Name of section; without the brackets, case sensitive

item (String) [in]

Name of item to read or write; case sensitive

value (String) [in/out]

For the read operation, the value is returned here. Note that if the item is not found within the specified section, the default value will be returned here, assuming the dftvalue parameter was specified. For the write operation, this will be the value to write.

dftvalue (String) [in]

For the read operation, supplies the default value of the item if the item is not defined

Comments

When writing, if the file does not exist, it will be created, and if the specified section does not exist, the section and item will be added to the end of the file. For example:

xcall INIX, "foo.ini", 1, "Favorites", "Beatle", "Ringo"

If the foo.ini file didn't previously exist, then after the above call, it would exist and contain:

[Favorites]

Beatle=Ringo

If we then wrote another item using ...

xcall INIX, "foo.ini", 1, "Favorites", "Position", "On Top"

... the file would be updated to contain:

[Favorites]

Beatle=Ringo

Position=On Top

Note that neither the order of the sections nor the order of the items is significant.

If we then retrieve three values from the file with the following ...

xcall INIX, "foo.ini", 0, "Favorites", "Beatle", fabguy$, "Paul"

xcall INIX, "foo.ini", 0, "preferences", "Position", pos$, "upside down"

xcall INIX, "foo.ini", 0, "Favorites", "Musician", player$, "Leadbelly"

The results would be:

? fabguy$ ! "Ringo"; (default "Paul" ignored)

? pos$ ! "upside down" (no such section "preferences"; use default)

? player$ ! "Leadbelly" (no such item "Musician"; use default)

Attempting to read from a non-existent INI file is equivalent to attempting to retrieve non-existent items; you get back the default value specified in each read operation, or "" if no default specified.

Despite the lack of order or indexing, INIX is quite efficient, particularly at reading, since the file gets cached in memory on the first access. Updates to the file do require the entire file to be rewritten, but this is still reasonably efficient, particularly if the total file size is "reasonable" (say, under 32K or so), and if read operations outnumber writes, as they usually do with these kinds of configuration files.

INIX.SBX was initially created and contributed to the SOSLIB by Steve Evans. It has since been adopted as a standard A-Shell routine, and is used extensively by many A-Shell modules. The source is available in [907,26] of the SOSLIB repository.


INMEMO

Updated February 2013; see History

xcall INMEMO, opcode, text, channel, strow, stcol, endrow, endcol, link, xpos, vspec, mmoclr, extctl

INMEMO was originally developed in the 1980s for use under AMOS. Its purpose is to provide an easy way for programmers to store and manipulate variable-length text structures. Although these structures may include light-bar menus, help screens and lookup tables, the most common and traditional use is to include free form, expandable memo pads within file maintenance programs. A-Shell contains a runtime implementation of INMEMO.SBR (and XFRMMO) which is about 95% compatible with the AMOS version.

Full documentation for INMEMO is provided in a separate document called the INMEMO Reference, which see for detailed information (available on the main A-Shell documentation page). The abbreviated notes provided here are intended for programmers who are familiar with the routine but just need a quick reference to the parameter list.

Note that XTEXT offers similar basic functionality with a GUI interface.

Comments

PCKLST acts as a front-end to INMEMO to create pop-up pick-list boxes.

The A-Shell version of INMEMO is slightly more advanced than the AMOS version in the implementation of free-form menus, in that it supports hidden text associated with an option (following a backslash as with regular vertical menus). For example, assuming the menu item delimiters were brackets, the text "[Mystery Option\secret]" would display as "Mystery Option", but if selected, would return the full "Mystery Option\secret".

Parameters

opcode (Num)

specifies a combination of flags from the following table.

Symbol | Description | Symbol | Description
MMO_AAH | Auto adjust (shrink) height to fit data | MMO_LIN | Return one line of memo text
MMO_APS | Alternate prompt style | MMO_MNU | Menu mode
MMO_BDR | Border | MMO_NAF | No auto formatting (wrapping)
MMO_CLS | Close memo file | MMO_NBR | Do not redraw border
MMO_CXY | Start at position EXTROW,EXTCOL | MMO_NMR | Do not redraw border or text
MMO_DBM | Start display at bottom | MMO_NOA | Do not display navigation arrows
MMO_DEL | Delete | MMO_OPN | Open memo file
MMO_DPG | Display with paging control | MMO_OPT | Disk optimized mode (n/a under A-Shell)
MMO_DSP | Display | MMO_OTX | Output memo to TEXT
MMO_EDT | Edit | MMO_RET | Return key exits memo
MMO_EWU | Edit without update | MMO_RAW | Save/retrieve raw text
MMO_FFM | Free form menu or dialog box mode | MMO_RSA | Restore screen area on exit
MMO_FST | Fast menu mode | MMO_SCH | Search
MMO_HDR | Output invisible headers with chr$(26) delimiters | MMO_SIL | Silent operations (no display)
MMO_IPG | Intelligent paging mode | MMO_SVA | Save screen area
MMO_ISL | Insert into sorted list | MMO_TBL | Table lookup
MMO_LID | Smart line insert and delete | MMO_UWE | Update without edit
Definition file: MMOSYM.DEF

text (String)

has various uses, from titles to preloaded key sequences, retrieved lines, menu selections, and even entire memo or menu contents.

channel (Num)

is generally the file channel that the memo file is open on. If the CHANNEL parameter is a string, it will be interpreted as the name of the memo file, in which case the memo file will be automatically opened, closed, and even created, if necessary.

strow, stcol, endrow, endcol (Num) [in]

specify the dimensions of the memo box, around which the border, if applicable, will be drawn.

link (B,2 or B,4)

is the link to the memo record.

xpos

is a control variable, which should be mapped as follows

MAP1 XPOS

MAP2 POS,B,4

MAP2 POS2,B,2

vspec

controls the maximum scrollable width and height of the memo, and must be mapped as:

MAP1 VSPEC

MAP2 VWIDTH,B,2

MAP2 VROW,B,2

mmoclr (B,1)

if specified, controls the colors for various parts of the memo display, and must be mapped as follows:

Symbol | Description | Symbol | Description
BFCLR | border foreground | PBCLR | prompt (title) bg
BBCLR | border background | WFCLR | warning mssg fg
TFCLR | text foreground | WBCLR | warning mssg bg
TBCLR | text background | SFCLR | status line fg
AFCLR | arrows foreground | SBCLR | status line bg
ABCLR | arrows background | RFCLR | ruler/reserved fg
PFCLR | prompt (title) fg |  |

extctl

may optionally be specified for extended control parameters, mapped as follows:

MAP1 EXTCTL |  |
 | MAP2 EXTCOD,B,2 | ! exit code
 | MAP2 EXTERR,B,2 | ! exit error status
 | MAP2 EXTMAP,B,4 | ! exit code enable bitmap
 | MAP2 EXTROW,B,2 | ! cursor row
 | MAP2 EXTCOL,B,2 | ! cursor column
 | MAP2 EXTBYT,B,4 | ! # bytes in memo
 | MAP2 EXTHIT,B,2 | ! # rows
 | MAP2 EXTWID,B,2 | ! longest row length
 | MAP2 EXTPRW,B,2 | ! # protected rows
 | MAP2 EXTSMI,S,1 | ! start menu item char
 | MAP2 EXTEMI,S,1 | ! end menu item char
 | MAP2 EXTMRW,B,2 | ! error message row
 | MAP2 EXTTOP,B,2 | ! top window offset
 | MAP2 EXTLFT,B,2 | ! left window offset
 | MAP2 EXTPCL,B,2 | ! # protected columns
 | MAP2 EXTTIM,B,2 | ! max inter-character timeout
 | MAP2 EXTOTH,B,2 | ! other menu exit keys:
 |  | ! 02 = left arrow (EXITCODE -40)
 |  | ! 04 = right arrow (EXITCODE -41)
 |  | ! 08 = up arrow (EXITCODE -42
 |  | ! 16 = down arrow (EXITCODE -43)
 |  | ! 32 = tab key (EXITCODE -44)
 | MAP2 EXTJNK,X,14 | ! for expansion

Of the above parameters, perhaps the most important are extcod and exterr, whose values are shown in the tables below. The former is similar to the exitcode parameter in INFLD, receiving a code indicating how the memo was exited. The latter indicates various other error conditions. The variable/symbol names in the first column of the tables below are defined in MMOSYM.BSI.

Symbol | Description
MMX_OK | Normal Updated exit
MMX_QUI | Non-Updated exit (Ctrl+C)
MMX_VTS | Non-Updated exit (VSPEC too small)
MMX_TIM | Updated exit (time out)
MMX_TAB | Tab used to select menu item
MMX_SPC | Spacebar used to select menu item
 | Command function exits are returned as negative numbers F1 = -1, etc.

Symbol | Description
MME_ERR | abnormal exit (see POS)
MME_SAF | failure to save or restore area
MME_OK | normal exit

History

2013 February, A-Shell 6.1.1335: Add opcode MMO_RAW to save and retrieve raw text.

2009 October, A-Shell 5.1.1164: For applications still using INMEMO in an otherwise GUI environment, to make it slightly more Windows-friendly, putting "|K" in your INFDEF string (via SBR=INFDEF:|K, or SET INFDEF, or MIAMEX,MX_INFDEF), will now cause the following changes:

· Ctrl+A selects the entire memo.

· Del (immediately after Ctrl+A) will clear the memo. Any other keyboard operation except Ctrl+C just unselects the memo and then responds as it would otherwise.

· Ctrl+C copies the selected text to the clipboard. This works for both the entire memo selected by Ctrl+A, and also for any other text selected with the mouse.

· Ctrl+V pastes the clipboard text into the memo.

· Escape will prompt whether to save changes, discard or cancel. Since the normal abort key, Ctrl+C, has a different meaning in |K mode, Escape has to serve for both updating and aborting. The text of the messagebox that appears is the same as that used by XTEXT and is defined in SBRMSG.xxx as message 023,001.


MMO_RAW

The flag MMO_RAW (&h80000000) may be combined with MMO_UWE (update without edit) to save the string contents of the TEXT parameter in a raw state, and with MMO_OTX (output to text) to retrieve the raw data into the TEXT parameter. In this mode, there is no formatting: no line breaking, no special interpretation of space compression, invisible headers, etc. Nor does it pay any attention to the coordinates or VSPEC specification.

The new raw mode is mainly intended to allow applications to tap into the variable-length storage capabilities of INMEMO, independent of the memo display and editing capabilities. In particular, it could be useful as a storage system for XTEXT.

Examples

! save TEXT$ (any length) raw to file TEST.MMO, return LINK

xcall INMEMO, MMO_UWE+MMO_RAW+MMO_SIL, TEXT$, "TEST.MMO", 0, 0, 0, 0, link, XPOS, VSPEC, MMOCLR, EXTCTL

! retrieve memo from LINK into TEXT$

xcall INMEMO, MMO_OTX+MMO_RAW+MMO_SIL, TEXT$, "TEST.MMO", 0, 0, 0, 0, LINK, XPOS, VSPEC, MMOCLR, EXTCTL

Note that the string retrieved from the file will be truncated to fit the TEXT$ destination variable. If using a dynamic string (S,0), you must pre-initialize it to a suitable max size, e.g. TEXT$ = FILL$(" ",MAX_MEMO).

See MMOSYM.DEF and MMOSYM.BSI for the flag definition. Also see sample program XTXMMO2 in [908,40] which demostrates the feature in conjunction with XTEXT.


ISMBLD

Updated April 2013

xcall ISMBLD, opflags, status, fspec, keysiz, keypos, recsiz, reccnt {, idadev, infile, maxrecs, idxblksiz, idxlvls, extrablks, exprecs}

This subroutine (.SBX) version of ISMBLD.LIT may be more convenient for building files than having to first generate a CMD file. The file is actually identical to ISMBLD.LIT which is why it has the same version (and hash, for that matter). It determines whether to act as a subroutine or LIT command based on how it is called. It was introduced in A-Shell 5.1.1122 of August 2008 as part of the ISAM overhaul that vastly improved ISAM performance, which see for an in-depth discussion of performance issues.

Parameters

opflags (Num) [in]

Operation flags (see IBF_xxx in ISMDEF.BSI)

Symbol | Value | Description
IBF_SECONDARY | &h0002 | build secondary index
IBF_AUTOBLKLVL | &h0004 | auto compute block size
IBF_EXISTING | &h0008 | process existing file (
IBF_PROGRESS1 | &h0100 | progress style 1 (% at cursor location)

status (F,6) [out]

Return status:

Value | Description
0 | success
-1 | param error
-2 | load terminated in mid-record
-3 | file doesn't exist (IBF_EXISTING)
-4 | file already exists
-5 | load file doesn't exist
-6 | expanded version/blocks size requires newer A
-7 | main idx doesn't exist (for secondary load)
30+ | erf values (during load)

fspec (String) [in]

File to create (no extension)

keysiz (Num) [in]

size of key

keypos (Num) [in]

key position

recsiz (Num) [in]

record size

reccnt (Num) [in]

# recs (initial allocation)

idadev (String) [in]

IDA device (e.g. "DSK7:") if not same as IDX

infile (String) [in]

Seq file to load from, or name of main IDX if creating a secondary IDX

maxrecs (Num) [in]

Expected max # recs (for auto-determination of optimum idxblksiz and idxlvls; 0 to ignore)

idxblksiz (Num) [in]

IDX block size (default 512)

idxlvls (Num) [in]

IDX levels (default 3)

extrablks (Num) [in]

Extra IDX blocks (if omitted, use 50%). 0.05 - 1.00 = % x 100, e.g. 0.5 = add 50%)

exprecs (Num) [in]

Expected / eventual number of records, to improve the IBF_AUTOBLKLVL (auto configure index) calculations.

Note that although ISMBLD.SBX shares much of the same code as ISMBLD.LIT, it offers the option of allowing ISMBLD to auto-determing appropriate values for the IDX block size and levels, based on the key size and expected maximum records (while only allocating the file for the desired initial size). Use ISMDMP XXX /V afterwards to confirm the configuration.

See Also

• ISMBLD.LIT

• ISMDMP.LIT

• ISMROK.SBR.

History

2013 April, A-Shell 6.1.1348, ISMBLD.SBX 2.1(134): Add new parameter exprecs (see above)


ISMROK

Updated February 2012

ISMROK.SBR reads the "rock" of the traditional ISAM file open under channel ch and returns the requested parameters, all of which are optional and can be specified using any numeric data types. It will be left as an exercise to the reader to determine the usage of the parameters (hint: check out ISMUTL.LIT). The three parameters added to ISMROK in A-Shell 5.1.1122 (see History) are described below.

xcall ISMROK, ch, idaalc, idaavl{, recsiz, keysiz, keypos, devdrv, idxalc, idxavl, idanxt, idxnxt, idx'lvls, idx'blk'siz, idx'type}

idx'lvls (Num) [out]

returns the number of levels in the IDX

idx'blk'siz (Num) [out]

returns the IDX block size

idx'type (Num) [out]

returns a bitmap field indicating the index type:

Value | Description
&h0002 | secondary index
&h0800 | A-Shell extensions; requires A-Shell version 5.1.1122 or later

See Also

• ISMBLD.LIT

• ISMDMP.LIT

ISMBLD.SBX

History

2008 August, A-Shell 5.1.1122: A-Shell's ISAM underwent some major surgery for improved ISAM performance, which see for an in-depth discussion of performance issues. As part of that project, ISMROK.SBR was given three new optional parameters, as described above. The old syntax was:

xcall ISMROK, ch, ida'alc, ida'avl, recsiz, keysiz, keypos, devdrv, idx'alc, idx'avl, ida'nxt, idx'nxt


ITC

xcall ITC, func, type, mesg, retv

(Unix/Linux only) ITC.SBR allows programs to send and receive messages between jobs.

Parameters

MAP1 FUNC,<any numeric type> ! opcode

MAP1 TYPE,<any numeric type> ! message type or process ID

MAP1 RETV,B,1 ! return code (0=ok)

MAP1 MESG ! message

MAP2 MTYPE,B,4 ! internal code

MAP2 MESGX,X,<any size> ! message contents

func

indicates the operation to perform, as described in the following table.

Value | Meaning
0 | Send message to cooperating receiver
1 | Receive message (do not wait if not available)
2 | Receive message (wait until available)
3 | Send message and signal receiver
 | Write exactly count characters (or up to null if count=0)

type

identifies the type of message, or the process ID of the target job to signal. In the case of func 3, it must be the process ID of the target job to signal. (In this operation, the contents of the message may not be important; since the signal itself could be used to notify the target job to look for subsequent messages.) For the other operations, it must be a value that both sender and receiver agree on, because the receive operation will ignore messages not sent with the specified type. (The idea here is to allow multiple message formats or priorities to be used simultaneously.) The exception is that the receiver may set type=0 to receive the first message in the queue, regardless of its type. To avoid confusion between types that are process IDs and types that are message types, it is recommended that you adopt a standard of using message type values higher than the range of process IDs (which might extend as high as 2**24 on very large systems. Type should also be below 2**31 to avoid confusing them with negative type numbers, which are used to request to read any message whose mtype is less than or equal to the absolute value of the specified type.

mesg

contains the message to send or receive. Obviously, the communicating programs need to agree in advance on the layout corresponding to each message type. It must begin, as shown above, with a 4 byte field which is reserved for internal use by the subroutine. (Actually, it plugs the type value into mtype for outgoing messages, and ignores any incoming messages whose mtype does not match the type specified.)

retv

returns a 0 or 1 indicating the success of the operation (0 = success).

Comments

UNIX/Linux systems do not allow one user to signal another unless they are both share the same effective user ID or if the sender is root. For this reason, some sites set the "setuid" flag on the ashell executable to make all A-Shell users effectively the same user, or else they rely on the system administrator being able to switch to root in order to use operations which require signaling other users. Such operations include ITC.SBR FUNC=3, KILL.LIT, CHAT.LIT, SEND.LIT, FORCE.LIT, and JSTAT.LIT.


JOBCMD

xcall JOBCMD, command

A-Shell emulates the AMOS feature of being able to specify a command string which is automatically executed whenever the job returns to the AMOS command (or dot) prompt. Setting the command to a null string disables the feature, which effectively makes it possible again for the user to interactively type commands when at the AMOS prompt. This feature is often used to force users back into some kind of a menu in case they somehow manage to drop out of a program. You have to be careful with this facility, since once you set it, there is no way to exit except by making another call to JOBCMD.SBR with a null string as the argument.

The maximum length of the Command string is 29 characters plus a trailing null byte.


JOBDAT

xcall JOBDAT, job'info

JOBDAT.SBR is yet another example of a subroutine which returns a variety of information about the current job. This one seems to have been connected with the inSight juggernaut.

Parameters

MAP1 JOB'INFO |  |
 | MAP2 JD'SYSNAM ,S,16 | ! OS name, e.g. "Windows/32"
 | MAP2 JD'JOBNAM ,S,6 | ! Job name
 | MAP2 JD'JOBNUM ,F,6 | ! Job number
 | MAP2 JD'JOBLOG ,S,20 | ! e.g. "DSK0:[150,277]"
 | MAP2 JD'USRNAM ,S,20 | ! User login name
 | MAP2 JD'PRGNAM ,S,6 | ! Program name
 | MAP2 JD'PRGVER ,S,16 | ! Program version
 | MAP2 JD'TRMROW ,F,6 | ! Current # display rows
 | MAP2 JD'TRMCOL ,F,6 | ! Current # display cols
 | MAP2 JD'TRMFGC ,F,6 | ! Foreground color #
 | MAP2 JD'TRMBGC ,F,6 | ! Background color #
 | MAP2 JD'TRMFLG(32),B,1 | ! Terminal flags (see below)

Each entry in the JD’TRMFLG() array corresponds to a terminal feature from the following table. The array item is set to 1 if the feature is supported by the current display device, else 0.

Item | Meaning | Item | Meaning
1 | Alternate page | 16 | Line insert
2 | Block fill | 17 | Auxiliary printer port
3 | Column insert | 18 | 80/132 column
4 | Color | 19 | Smooth scroll
5 | Multi-byte* translations | 20 | Box commands
6 | Alpha terminal | 21 | Mode attributes
7 | Addressable status lines | 22 | AM70-style color commands
8 | Split screen | 23 | No-space attributes
9 | Erase to end of line | 24 | "True" graphics
10 | Erase to end of screen | 25 | Gray scale
11 | Underscore | 26 | Proportional space fonts
12 | Blink | 27 | Variable rows
13 | Dim | 28 | 8 bit support
14 | Reverse video | 29 | Insight Support
15 | Character insert |  |

* (function key)


JOBNUM

xcall JOBNUM, jobnumber

JOBNUM.SBR returns the current job number (in any numeric parameter format).

Note that the job number is established when the session is launched, as the position within the job table, and remains fixed for the duration of a session.


JOBTRM

xcall JOBTRM, jobnam, trmnam, tdvnam {,ctljob, ctltrm, ctltdv}

JOBTRM.SBR returns the job name, terminal name, and terminal driver name of the current job. (All parameters should be mapped as strings of six or more characters.) Optionally, it can also return the same set of information for the "controlling job". The idea of the "controlling job" is mainly applicable in AMOS multitasking environments (such as MULTI and PolyTrack) where the program wants to know the identify of the "controlling" (or "real") job in order to associate some resources with the user or terminal. In the A-Shell environment, the "controlling job" will, for the purposes of this subroutine, always be the same as the current job, except in the case of PolyShell, in which case the controlling job name will be the same as the current job, minus the last character. (For example, the PolyShell control job PSHAA will spawn user jobs PSHAA1, PSHAA2, etc.)

The terminal name under A-Shell is virtually always the same as the job name.


JULCVT

xcall JULCVT, sepdat, juldat, flag

JULCVT.SBR converts between a separated date format and Julian date format.

Parameters

sepdate (B,4) [in/out]

is the date to convert to Julian (if flag = 0), or the return date (if flag = 1). It is in AMOS "separated" format, which is as follows:

MAP1 Sepdat,B,4

MAP1 SepdatX,@Sepdat

MAP2 Mon,B,1 ! Month (1-12)

MAP2 Day,B,1 ! Day of month (1-31)

MAP2 Yr,B,1 ! Offset from 1900 (2003=103)

MAP2 Dow,B,1 ! Day of week (Mon=0, Sun=6)

juldat (Num)

is the Julian date equivalent of sepdate (if flag = 0) or the date to convert to separated format (if flag = 1). This is the number of days since "The Beginning" (about 4716 BC).

flag (Num) [in]

should be set to 0 to convert from sepdate to juldat, else 1 to convert the other way.

Comments

The AlphaBASIC system variable DATE can be used to set sepdat to the current date (i.e. sepdat = DATE).

See Also

GRECNV and DATES for other date conversion routines.


LOKOUT

xcall LOKOUT, flags {,wait, lokmsg}

LOKOUT.SBX provides an application-friendly interface to the lock-out feature in which the file %MIAME%/ashell.lok is used to prevent users from logging into to A-Shell. This routine does nothing about users that are already in, but if you first manage to get them out, this will make sure that they stay out.

Tools you may use in your strategy to deal with the existing users include SEND.SBR, FORCE.SBR, KILJOB.SBX and MX_KILL. See Locking Users Out for additional details.

Source, samples and related functions can be found in SOSLIB:[907,32].

Parameters

flags (Num) [in/out]

On input:

0: clear the existing lockout

1: set a lockout (requires wait and lokmsg parameters)

Returns <0 on error:

-1 = too few parameters

-n = basic error n

wait (Num) [in]

0: users logging in can wait as long as they want for lock to clear

#: maximum seconds they can wait

lokmsg (String) [in]

Message to display to users trying to log into A-Shell. Should be consistent with the wait flag, and possibly mention that they can use Escape to abort the wait. Use an embedded "\n" to indicate line breaks as needed.

History

2006 March, A-Shell 4.9.952: Routine added to A-Shell


LOG

Updated June 2016; see History

xcall LOG, logstr {,qflag, ,status}

xcall LOG, dev, p, pn

LOG.SBR allows you to log to a new disk and PPN, using an ersatz or traditional specification, with an option to silence the normal output (start message) that you would otherwise see with an AMOS LOG command. It may also be used to return your current device, project, and programmer number.

Parameters

logstr (String) [in]

A string specifying the desired device and/or PPN to log to. Any of the formats accepted by LOG.LIT are accepted here. See examples below.

qflag (Numor String) [in]

If specified and non-zero (if numeric) or non-null (if string), silences the normal confirmation message that you would see when logging into a new location.

status (Num) [in/out]

If specified and set to a non-zero value on input, the routine will validate the target device and ppn, and return 0 for success, or a system error number for failure. Note that you must initialize the variable to a non-zero value for this validation to occur. Otherwise, it will still return -1 if the target device is invalid, but it will not validate the PPN, and thus it would appear to allow you to log into a non-existent PPN. See History.

dev (String) [out]

Returns current logged-in device, in upper case, with no trailing spaces or punctuation, e.g. "DSK0".

p (String) [out]

Returns decimal string representation of current "project"(1st part of PPN), e.g. "1" or "200"

pn (String) [out]

Returns decimal string representation of current "programmer number" (2nd part of PPN), e.g. "4" or "921"

Examples

xcall LOG,"SYS:" (log to SYS:)

xcall LOG,"LOG DSK0:[1,4]) ('LOG' is optional)

xcall LOG,"SYS:","Q" (silence output)

xcall LOG,DEV$,P$,PN$ (return current login)

Comments

The routine determines which operation to perform—log to a new location or return the current location—based on the number and type of parameters passed. If three string parameters are passed, it returns the current location; in all other cases it treats the operation as a request to log to a new location.

Note that by returning the PPN as a pair of decimal-formatted strings, this routine avoids the issues related to octal vs. decimal representation and single-byte overflow that may affect routines that manipulate the PPN as a pair of binary values.

History

2016 June, A-Shell 6.3.1515: Status now returns numeric error codes on failure rather than just -1.

2009 September, A-Shell 5.1.1159: The routine was modified to support returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized.


LSTLIN

xcall LSTLIN, cmdline

LSTLIN.SBR may be used within a BASIC program to retrieve the command line from which the program was launched. This is useful for allowing command line parameters to be passed to BASIC programs, and nearly essential for allowing BASIC programs to emulate AMOS LIT commands. It is similar to the BASIC Plus CMDLIN (or CMDLIN$) system variable, except for the following: 1) LSTLIN does not fold the command line to upper case, like CMDLIN does; and 2) LSTLIN includes the name of the current program, whereas CMDLIN only includes the part of the command line after the program name. The following example will make this distinction clear:

Program LSTLIN,1.0(100)

MAP1 A$,S,100

? "CMDLIN$ = [";CMDLIN$;"] (BASIC Plus only)"

? "CMDLIN = [";CMDLIN;"] (same as CMDLIN$)"

xcall LSTLIN,A$

? "XCALL LSTLIN = [";A$;"]"

If the program above is compiled with COMPLP (or COMPIL /X:1), the command line below will produce the following output:

.run lstlin hello world

CMDLIN$ = [HELLO WORLD] (BASIC Plus only)

CMDLIN = [HELLO WORLD] (same as CMDLIN$)

xcall LSTLIN = [lstlin hello world]

Note that LSTLIN.SBR works in all versions of BASIC, while use of the CMDLIN or CMDLIN$ system variable requires BASIC Plus (complp or compil /x:1).

See also: LSTLINSTRIP.


MATCH

xcall MATCH, rtncod, value, range

MATCH.SBR is useful in building flexible record selection logic. With it, you can easily allow the users to specify a list of acceptable values, or ranges of values, for a particular field. Then for each candidate record, just pass the value and range specification to the subroutine and let it worry about numeric, string, and date comparisons.

Parameters

rtncod (Num)

returns the results:

Value | Meaning
0 | No match; value is not within the specified list or range
1 | Match; value is within range
-1 | Parameter error
-2 | Value type not supported
-3 | Range string too long
-4 | Syntax error in range

value (F,6, String, or B#)

is the value which you want to check against the range.

range

is the range specification in the form:

r1,r2,r3,...,rn

Each of the rx entries in the range string may be either a single value or a from-to range expressed as a beginning and ending value, separated by a dash. Each item in the range list is interpreted according to the type of the value parameter. String entries are case sensitive. If both value and range are of type string, and value is in the form:

mm/dd/ccyy

then each entry in the range string is interpreted as a date in a similar format. mm/yy is interpreted as mm/01/ccyy if followed by a dash, or mm/31/ccyy if preceded by a dash. The cc value is assumed to be 19 unless specified or unless the SBR=CCYY:## parameter in the miame.ini has been established.

On return, range is converted into a "compiled" format to eliminate the need for parsing it out on the next call. (If used for file record selection, you would typically be calling this routine hundreds or even thousands of times, with different value parameters but the same (or a limited number of) range strings.

A NULL range string matches all, as does a NULL value (for String ranges). Examples:

Range String | Meaning
"AA-CZ,F,JA*" | Match any string starting with "AA" through "CZ" ("ABCD" matches, "CZ1" does not). Also match if Value = "F", or if it equals anything starting with "JA".
"91300-91399,93132,95555" | Match any number 91300 through 91399, or match 93132 or 95555.
"03/15/97,04/97-2/98,3/02/1999" | Date match, including Mar 31 1997, or April 1 1997 through Feb 28 1998, or March 2, 1999.


MIAMEX

xcall MIAMEX, opcode {,param1, param2, ... param-n}

MIAMEX is a collection of utility operations that are gathered together here for efficiency or because they do not fall nicely into other categories. Each of the operations is listed in the following topic, with links to detailed documentation. Interested programmers should also consult the sample program, MIAMEX.BP, which can be found in the EXLIB and which contains examples of the more generally useful operations. Note that operations which are listed in the following tables but do not have additional details are A-Shell internal functions not intended for use by A-Shell programs.

In all of the MIAMEX specifications, the first parameter is function, as specified using the variable name (MX_xxx) defined in ashell.def. These functions are shown in the following two tables, MIAMEX Functions by Number and MIAMEX Functions by Symbol.

Note that good programming techniques require that MIAMEX operation be called with the symbol (text name) rather than the function code (number) so as to make your code more understandable. Seeing a reference to "MX_FINDFIRST" five years from now will be much more informative than seeing "MIAMEX 20."


MIAMEX Functions by Number

Symbol | Value | Function
MX_CMD_STATUS | 1 | Get/set command file status
MX_EXIT | 2 | Exit A-Shell
MX_FSPEC | 3 | Translate AMOS filespec to native
MX_GETCTRLC | 4 | Get Ctrl+C status
MX_GETECHO | 5 | Get echo status
MX_SETPROMPT | 6 | Set command prompt
MX_GETHEX | 7 | Get hex output status
MX_SETHEX | 8 | Set/reset hex mode
MX_OCVT | 9 | Octal conversion (OCVT)
MX_CHKPPN | 10 | Check for ppn
MX_GETERSATZ | 11 | Return ersatz
MX_GETVER | 12 | Return A-Shell version
MX_WSET_STATUS | 13 | Get/set WSET flags
MX_VUE | 14 | VUE
MX_COMPIL | 15 | COMPIL
MX_PREBAS | 16 | CPRE
MX_SYNC_CWD | 17 | Synchronize A-Shell PPN with system path
MX_NXTCMD | 18 | Get next command file line
MX_GETDEV | 19 | Get next device
MX_FINDFIRST | 20 | Find first matching file
MX_FINDNEXT | 21 | Find next matching file
MX_DIRSEP | 22 | Get directory separator
MX_FINDEND | 23 | End directory processing
MX_GETPROMPT | 24 | Get prompt
MX_HASHFILE | 25 | Get hash
MX_PRFSPEC | 26 | Print filespec
MX_COPYFILE | 27 | Copy file
MX_PRINTERR | 28 | Output error message
MX_RENAMERR | 29 | Output rename error message
MX_GETQUEUE | 30 | Return queue block
MX_GETENV | 31 | Return environment variable value
MX_SETEXT | 32 | Set default extension
MX_MATCHWILD | 33 | Match cmdlin
MX_GETCISAM | 34 | Get CISAM/DISAM version
MX_SETCRM | 35 | Set crm
MX_GETHASH | 36 | Get hex status
MX_SETHASH | 37 | Set/reset AMOS hash flag
MX_MKPATH | 38 | Create directory
MX_RMPATH | 39 | Delete directory
MX_GETODBC | 40 | Is ODBC available?
MX_ZAPQUEUE | 41 | Zap queue
MX_ODBCFIRST | 42 | Return first ODBC table
MX_ODBCNEXT | 43 | Return next ODBC table
MX_ODBCEND | 44 | ODBC end
MX_GETLOKSER | 50 | Return LOKSER flags
MX_SETLOKSER | 51 | Set LOKSER flags
MX_GETCMDINP | 52 | Return CMDINP flags
MX_SETCMDINP | 53 | Set CMDINP flags
MX_GETSIG | 54 | Return signal received flags (UNIX only)
MX_CLRSIG | 55 | Clear signal received flags (UNIX only)
MX_SETENV | 56 | Change TERM environment variable (UNIX only)
MX_KILL | 57 | Kill job
MX_SHOWLIC | 58 | Display license
MX_GETOPTIONS | 59 | Return OPTIONS flags
MX_SETOPTIONS | 60 | Set OPTIONS flags
MX_GETTRACE | 61 | Return TRACE flags
MX_SETTRACE | 62 | Set TRACE flags
MX_SETPFK | 63 | Set function key translation or PFK
MX_GETPFK | 64 | Return PFK name
MX_SCRNPIC | 65 | Take screen snapshot
MX_QRBLD | 66 | Force queue rebuild
MX_QLOCK | 67 | Lock queue
MX_QUNLOK | 68 | Unlock queue
MX_GETUMSK | 69 | Return umask (UNIX only)
MX_SETUMSK | 70 | Set umask (UNIX only)
MX_WINMNU | 71 | Same as AUI_MENU, which should be used instead.
MX_LITMSG | 72 | Display LITMSG.xxx message
MX_READJCB | 73 | Return jobtbl.sys record
MX_WRITEJCB | 74 | Write jobtbl.sys record
MX_GETTIME | 75 | Get current system time
MX_TELSER | 76 | Launch Telnet server mode (Windows only)
MX_SHOWWINDOW | 77 | Display/hide Window (Windows only)
MX_GETGDO | 78 | Get global DO parameters
MX_SETGDO | 79 | Set global DO parameters
MX_XCBINFOX | 80 | Reserved
MX_XCBDATAX | 81 | Get/set SBX parameters
MX_EXITSBX | 82 | Exit to dot prompt (even from with an SBX )
MX_GETFKW | 83 | Get FKEYWAIT value (Unix only)
MX_SETFKW | 84 | Set FKEYWAIT value (Unix only)
MX_TITLE | 85 | Get/set Window title
MX_ERRNOMSG | 86 | Get operating system error message by errno
MX_NOBUF | 87 | Disable stream file buffering
MX_FLUSHBUF | 88 | Flush stream file buffer
MX_FLSET | 89 | Clone file channel (within SBX) (similar to M68 FLSET)
MX_BEVEL | 90 | Get/set bevel options (Windows only)
MX_SYSBCLR | 91 | Define BG color # to track system COLOR_3DFACE
MX_HOTKEY | 92 | Enable/disable PolyShell hot keys
MX_ABOUT | 93 | Get license info (used by ABOUT.LIT)
MX_GETRC | 94 | Get current cursor position
MX_GETOFD | 95 | Windows Open File dialog (Windows only)
MX_SHELLEX | 96 | Shell Execute (open/print registered file type)
MX_MKDIR | 97 | Create directory (Windows only)
MX_ATE | 98 | Start ATE
MX_GETREG | 99 | Retrieve registry value (Windows only)
MX_PLAYSOUND | 100 | Play a sound file (Windows only)
MX_GETSW | 101 | Get swap wait value (in ms) (Unix only)
MX_SETSW | 102 | Set swap wait value (in ms) (Unix only)
MX_CLFLAGS | 103 | Get/set ashell command line switches
MX_GETPID | 104 | Get process ID (pid)
MX_CLIPBOARD | 105 | Get/set clipboard (Windows only)
MX_OSVER | 106 | Get operating system version
MX_USRMAP | 107 | Get USRMEM module information
MX_USRLOD | 108 | Load module (or variable) into USRMEM
MX_USRDEL | 109 | Delete module from USRMEM
MX_USRSAV | 110 | Save module from USRMEM to disk
MX_USRIO | 111 | Read/write USRMEM data directly
MX_AMOUSEXLT | 112 | Set AutoMouse translations (Windows only)
MX_MEMORY | 113 | Change user partition size
MX_MARSHAL | 114 | Marshall parameters for remote XCALL
MX_IXCALL | 115 | Indirect XCALL
MX_INICLR | 116 | Process an INI.CLR file
MX_MAPI | 117 | MAPI Send Mail (Windows only)
MX_FILEPOS | 118 | Get/set file pointer within stream
MX_WINCTL | 119 | Same as AUI_CONTROL, which should be used instead.
MX_WINPTR | 120 | Prompt for Windows printer (Windows only)
MX_CHAINTO | 121 | Get/set chain-to on privilege violation
MX_SBRFLG | 123 | Get/set options that are normally set with SBR= in miami.ini
MX_ASHLOG | 124 | Output STRING message to ashlog.log
MX_MCRS | 125 | Retrieve information about last mouse click
MX_SINK | 126 | Sink/unsink specified box
MX_ROUND | 127 | Get/set rounding factor
MX_GETIP | 128 | Get IP address
MX_GUIFLG | 129 | Same as AUI_ENVIRONMENT, which should be used instead.
MX_ASHFILE | 130 | Retrieve startup command and/or name of A-Shell executable
MX_FILESTATS | 131 | Retrieve stats for specified path
MX_FTFORMAT | 132 | Reformat filetime from MX_FILESTATS
MX_EXPFIL | 133 | Expand/reduce a file in place
MX_SYNC | 134 | Invokes operating system sync command
MX_EVENTWAIT | 135 | Same as AUI_EVENTWAIT, which should be used instead.
MX_HTMLHELP | 137 | Same as AUI_HTMLHELP, which should be used instead.
MX_REGISTRY | 138 | Registry operations
MX_AUTOPARENT | 141 | Set parent controls
MX_CMDKBD | 142 | Retrieve CMD file variables
MX_INFDEF | 143 | Get/set INFLD default TYPE codes
MX_DEBUG | 144 | Get/set DEBUG level
MX_UNLOADLIB | 145 | <reserved>
MX_LASTLNO | 146 | Retrieve last line number of program
MX_FLINES | 147 | Count lines, maximum line length in file
MX_GDICALC | 148 | Calculate String length or height
MX_WINSETTINGS | 149 | Get/set A-Shell GUI Settings
MX_RELEASEKBD | 153 | Set/release keyboard hold
MX_DEFTABXYZ | 154 | Set "3D" Tab attributes
MX_INSTNUM | 156 | Return instance number
MX_FINDWINDOW | 157 | Find window by title and/or class and/or handle
MX_GTOCT | 160 | Convert hex or octal to decimal
MX_FILECHINFO | 161 | Returns info about open file based on file channel
MX_SETMEMFLAGS | 163 | Change memory module flags
MX_CHOOSECOLOR | 164 | Display color selection dialog
MX_CHOOSEFONT | 165 | Display font selection dialog
MX_VERINODE | 167 | Verify file information Remember to add to next table also
MX_SETUSRNAM | 169 | Set/override user name
MX_NUMASH | 170 | Return the number of A-Shell instances
MX_BROWSEFOLDER | 170 | Selects a folder or other non-file object (such as a computer).
MX_GETSHELLPATH | 171 | Retrieves the path for a specified Windows directory ID.
MX_PWCRYPT | 172 | Provides simple password encryption.
MX_SHORTCUT | 173 | Create shortcut.
MX_STRCMP | 174 | Compare two strings in various ways.
MX_CHKPCNET | 176 | Checks network state of PC.
MX_AGWRAPPER | 177 | Wraps "raw" ATE commands.
MX_FILEHOOK | 178 | Establish file "hooks" on specific files and file events.
MX_AGINTERPROC | 179 | Send AG commands between instances of A-Shell/Windows.
MX_IATIMEOUT | 180 | Get/set the inactivity timeout period.
MX_CSVDELIM | 181 | Get/set the CSV delimiter character.
MX_SETERR | 182 | Triggers a BASIC error.
MX_ATEFILEXFR | 183 | Performs ATE/ATSD file transfer.
MX_CLRINBUF | 184 | Clears input buffer and typeahead.
MX_MALLOCLIMIT | 185 | Get/set the MALLOCLIMIT.
MX_LASTPRTFIL | 186 | Returns specs of the last file written by the PDFX printer driver.
MX_FILESOCK | 187 | Binds a TCP socket to a sequential file channel.
MX_WEBCACHE | 188 | Provides operations related to A-Shell's web cache feature.
MX_CALLSTACK | 189 | Returns information about the call stack.

Remember to add new routines to the "ByType" and "By Symbol" lists.


MIAMEX Functions by Symbol

Symbol | Value | Function
MX_ABOUT | 93 | Get license info (used by ABOUT.LIT)
MX_AGINTERPROC | 179 | Send AG commands between instances of A-Shell/Windows.
MX_AGWRAPPER | 177 | Wraps "raw" ATE commands.
MX_AMOUSEXLT | 112 | Set AutoMouse translations (Windows only)
MX_ASHFILE | 130 | Retrieve startup command and/or name of A-Shell executable
MX_ASHLOG | 124 | Output STRING message to ashlog.log
MX_ATE | 98 | Start ATE
MX_ATEFILEXFR | 183 | Performs ATE/ATSD file transfer
MX_AUTOPARENT | 141 | Set parent controls
MX_BEVEL | 90 | Get/set bevel options (Windows only)
MX_BROWSEFOLDER | 170 | Selects a folder or other non-file object (such as a computer).
MX_CALLSTACK | 189 | Returns information about the call stack.
MX_CHAINTO | 121 | Get/set chain-to on privilege violation
MX_CHKPCNET | 176 | Checks network state of PC.
MX_CHKPPN | 10 | Check for ppn
MX_CHOOSECOLOR | 164 | Display color selection dialog
MX_CHOOSEFONT | 165 | Display font selection dialog
MX_CLFLAGS | 103 | Get/set ashell command line switches
MX_CLIPBOARD | 105 | Get/set clipboard (Windows only)
MX_CLRINBUF | 184 | Clears input buffer and typeahead
MX_CLRSIG | 55 | Clear signal received flags (UNIX only)
MX_CMD_STATUS | 1 | Get/set command file status
MX_CMDKBD | 142 | Retrieve CMD file variables
MX_COMPIL | 15 | COMPIL
MX_COPYFILE | 27 | Copy file
MX_CSVDELIM | 181 | Get/set the CSV delimiter character
MX_DEBUG | 144 | Get/set DEBUG level
MX_DEFTABXYZ | 154 | Set "3D" Tab attributes
MX_DIRSEP | 22 | Get directory separator
MX_ERRNOMSG | 86 | Get operating system error message by errno
MX_EVENTWAIT | 135 | Same as AUI_EVENTWAIT, which should be used instead.
MX_EXIT | 2 | Exit A-Shell
MX_EXITSBX | 82 | Exit to dot prompt (even from with an SBX )
MX_EXPFIL | 133 | Expand/reduce a file in place
MX_FILEHOOK | 178 | Establish file "hooks" on specific files and file events.
MX_FILEPOS | 118 | Get/set file pointer within stream
MX_FILECHINFO | 161 | Returns info about open file based on file channel
MX_FILESOCK | 187 | Binds a TCP socket to a sequential file channel.
MX_FILESTATS | 131 | Retrieve stats for specified path
MX_FINDEND | 23 | End directory processing
MX_FINDFIRST | 20 | Find first matching file
MX_FINDNEXT | 21 | Find next matching file
MX_FINDWINDOW | 157 | Find window by title and/or class and/or handle
MX_FLINES | 147 | Count lines, maximum line length in file
MX_FLSET | 89 | Clone file channel (within SBX) (similar to M68 FLSET)
MX_FLUSHBUF | 88 | Flush stream file buffer
MX_FSPEC | 3 | Translate AMOS filespec to native
MX_FTFORMAT | 132 | Reformat filetime from MX_FILESTATS
MX_GDICALC | 148 | Calculate String length or height
MX_GETCISAM | 34 | Get CISAM/DISAM version
MX_GETCMDINP | 52 | Return CMDINP flags
MX_GETCTRLC | 4 | Get Ctrl+C status
MX_GETDEV | 19 | Get next device
MX_GETECHO | 5 | Get echo status
MX_GETENV | 31 | Return environment variable value
MX_GETERSATZ | 11 | Return ersatz
MX_GETFKW | 83 | Get FKEYWAIT value (Unix only)
MX_GETGDO | 78 | Get global DO parameters
MX_GETHASH | 36 | Get hex status
MX_GETHEX | 7 | Get hex output status
MX_GETIP | 128 | Get IP address
MX_GETLOKSER | 50 | Return LOKSER flags
MX_GETODBC | 40 | Is ODBC available?
MX_GETOFD | 95 | Windows Open File dialog (Windows only)
MX_GETOPTIONS | 59 | Return OPTIONS flags
MX_GETPFK | 64 | Return PFK name
MX_GETPID | 104 | Get process ID (pid)
MX_GETPROMPT | 24 | Get prompt
MX_GETQUEUE | 30 | Return queue block
MX_GETRC | 94 | Get current cursor position
MX_GETREG | 99 | Retrieve registry value (Windows only)
MX_GETSHELLPATH | 171 | Retrieves the path for a specified Windows directory ID.
MX_GETSIG | 54 | Return signal received flags (UNIX only)
MX_GETSW | 101 | Get swap wait value (in ms) (Unix only)
MX_GETTIME | 75 | Get current system time
MX_GETTRACE | 61 | Return TRACE flags
MX_GETUMSK | 69 | Return umask (UNIX only)
MX_GETVER | 12 | Return A-Shell version
MX_GTOCT | 160 | Convert hex or octal to decimal
MX_GUIFLG | 129 | Same as AUI_ENVIRONMENT, which should be used instead.
MX_HASHFILE | 25 | Get hash
MX_HOTKEY | 92 | Enable/disable PolyShell hot keys
MX_HTMLHELP | 137 | Same as AUI_HTMLHELP, which should be used instead.
fcMX_IATIMEOUT | 180 | Get/set the inactivity timeout period.
MX_INFDEF | 143 | Get/set INFLD default TYPE codes
MX_INICLR | 116 | Process an INI.CLR file
MX_INSTNUM | 156 | Return instance number
MX_IXCALL | 115 | Indirect XCALL
MX_KILL | 57 | Kill job
MX_LASTLNO | 146 | Retrieve last line number of program
MX_LASTPRTFIL | 186 | Returns specs of the last file written by the PDFX printer driver
MX_LITMSG | 72 | Display LITMSG.xxx message
MX_MALLOCLIMIT | 185 | Get/set the MALLOCLIMIT
MX_MAPI | 117 | MAPI Send Mail (Windows only)
MX_MARSHAL | 114 | Marshall parameters for remote XCALL
MX_MATCHWILD | 33 | Match cmdlin
MX_MCRS | 125 | Retrieve information about last mouse click
MX_MEMORY | 113 | Change user partition size
MX_MKDIR | 97 | Create directory (Windows only)
MX_MKPATH | 38 | Create directory
MX_NOBUF | 87 | Disable stream file buffering
MX_NXTCMD | 18 | Get next command file line
MX_NUMASH | 170 | Return the number of A-Shell instances
MX_OCVT | 9 | Octal conversion (OCVT)
MX_ODBCEND | 44 | ODBC end
MX_ODBCFIRST | 42 | Return first ODBC table
MX_ODBCNEXT | 43 | Return next ODBC table
MX_OSVER | 106 | Get operating system version
MX_PLAYSOUND | 100 | Play a sound file (Windows only)
MX_PREBAS | 16 | CPRE
MX_PRFSPEC | 26 | Print filespec
MX_PRINTERR | 28 | Output error message
MX_PWCRYPT | 172 | Provides simple password encryption.
MX_QLOCK | 67 | Lock queue
MX_QRBLD | 66 | Force queue rebuild
MX_QUNLOK | 68 | Unlock queue
MX_READJCB | 73 | Return jobtbl.sys record
MX_REGISTRY | 138 | Registry operations
MX_RELEASEKBD | 153 | Set/release keyboard hold
MX_RENAMERR | 29 | Output rename error message
MX_RMPATH | 39 | Delete directory
MX_ROUND | 127 | Get/set rounding factor
MX_SBRFLG | 123 | Get/set options that are normally set with SBR= in miami.ini
MX_SCRNPIC | 65 | Take screen snapshot
MX_SETCMDINP | 53 | Set CMDINP flags
MX_SETCRM | 35 | Set crm
MX_SETENV | 56 | Change TERM environment variable (UNIX only)
MX_SETERR | 182 | Triggers a BASIC error
MX_SETEXT | 32 | Set default extension
MX_SETFKW | 84 | Set FKEYWAIT value (Unix only)
MX_SETGDO | 79 | Set global DO parameters
MX_SETHASH | 37 | Set/reset AMOS hash flag
MX_SETHEX | 8 | Set/reset hex mode
MX_SETLOKSER | 51 | Set LOKSER flags
MX_SETMEMFLAGS | 163 | Change memory module flags
MX_SETOPTIONS | 60 | Set OPTIONS flags
MX_SETPFK | 63 | Set function key translation or PFK
MX_SETPROMPT | 6 | Set command prompt
MX_SETSW | 102 | Set swap wait value (in ms) (Unix only)
MX_SETTRACE | 62 | Set TRACE flags
MX_SETUMSK | 70 | Set umask (UNIX only)
MX_SETUSRNAM | 169 | Set/override user name
MX_SHELLEX | 96 | Shell Execute (open/print registered file type)
MX_SHORTCUT | 173 | Create shortcut.
MX_SHOWLIC | 58 | Display license
MX_SHOWWINDOW | 77 | Display/hide Window (Windows only)
MX_SINK | 126 | Sink/unsink specified box
MX_STRCMP | 174 | Compare two strings in various ways.
MX_SYNC | 134 | Invokes operating system sync command
MX_SYNC_CWD | 17 | Synchronize A-Shell PPN with system path
MX_SYSBCLR | 91 | Define BG color # to track system COLOR_3DFACE
MX_TELSER | 76 | Launch Telnet server mode (Windows only)
MX_TITLE | 85 | Get/set Window title
MX_UNLOADLIB | 145 | <reserved>
MX_USRDEL | 109 | Delete module from USRMEM
MX_USRIO | 111 | Read/write USRMEM data directly
MX_USRLOD | 108 | Load module (or variable) into USRMEM
MX_USRMAP | 107 | Get USRMEM module information
MX_USRSAV | 110 | Save module from USRMEM to disk
MX_VERINODE | 167 | Verify file information Remember to add to next table also
MX_VUE | 14 | VUE
MX_WEBCACHE | 188 | Provides operations related to A-Shell's web cache feature.
MX_WINCTL | 119 | Same as AUI_CONTROL, which should be used instead.
MX_WINMNU | 71 | Same as AUI_MENU, which should be used instead.
MX_WINPTR | 120 | Prompt for Windows printer (Windows only)
MX_WINSETTINGS | 149 | Get/set A-Shell GUI Settings
MX_WRITEJCB | 74 | Write jobtbl.sys record
MX_WSET_STATUS | 13 | Get/set WSET flags
MX_XCBDATAX | 81 | Get/set SBX parameters
MX_XCBINFOX | 80 | Reserved
MX_ZAPQUEUE | 41 | Zap queue


MIAMEX 1: Set/get command file status

xcall MIAMEX, MX_CMD_STATUS, cmdcode

This command gets or sets command file status. cmdcode is a floating point variable which contains the new command file status to set, and into which the current status is returned. Each possible command file status (:R, etc.) is given a different numeric code from the following table:

Value | Meaning
0 | No command file currently running
1 | Command file is in silent (:S) mode
2 | Command file is in response (:R) mode
3 | Command file is in trace (:T) mode
4 | Command file is executing last line while in silent mode


MIAMEX 2: Exit A-Shell

xcall MIAMEX, MX_EXIT

MX_EXIT causes an immediate exit from A-Shell. Control is returned either to the host machine command level, or to a batch or shell-script file if one is running.

See Also

• MX_EXITSBX


MIAMEX 3: Perform FSPEC on AMOS string

xcall MIAMEX, MX_FSPEC, spec, locpath, ext, flags, ddb, status

MAP1 SPEC,S,40 ! AMOS file specification

MAP1 LOCPATH,S,160 ! Local (native OS) equivalent fspec

MX_FSPEC is used as an approximation to the FSPEC monitor call. It takes an AMOS format file specification or device name (spec), and processes it into its constituent parts of Device name, File name, and extension (ddb). It also optionally returns the host machine pathname corresponding to the AMOS file specification in locpath.

Parameters

spec (String) [in]

should contain the AMOS-format file specification that you want to parse or convert to native format. If the device and/or PPN are omitted, they will be supplied by your current login directory. If the extension is omitted, it will be supplied by the ext parameter. Note that the file does not need to exist, but it must have valid syntax (e.g. "a.a") and not be null (or else an invalid filespec error will result and the returned locpath will either be null or the previously processed filespec). See Comments, below, for information on how to retrieve the current native directory.

locpath (String) [out]

is only used if you wish to return the host machine pathname for the file specification given in spec. This is specified by the FS_TOH bit in the flags parameter, in which case the variable locpath should be mapped to an appropriate length for the longest path you expect to deal with. (The maximum path length under Windows is 260 characters.) Otherwise, the parameter may be specified as a null string (""), and it will be set to "" in case of error.

ext (String) [in]

is the default extension to use when processing a full file specification. It will be used if the given specification contains only a filename and no extension. The extension used is returned in the extension field of the ddb structure variable, and is used in the host format pathname if one is returned.

flags (Num) [in]

is used to determine exactly how the file specification processing is to take place. It is bit-mapped, and each bit may be set by adding together the symbolic values defined in the include file, ashell.def.

Symbol | Value | Description
FS_DRV | 1 | indicates that the drive name and number only are to be processed. When used in conjunction with FS_FMA (2), the device specification given in spec is returned in the ddb structure parameter.
FS_FMA | 2 | indicates that the file specification given in the spec parameter is to be used. Otherwise the already processed specification given in its constituent parts in the ddb structure parameter will be used. It only makes sense to omit this bit if theFS_TOH (4) bit is set, indicating that a host machine pathname is to be returned.
FS_TOH | 4 | indicates that the host machine path name corresponding either to the file specification in spec or in the ddb structure parameter is to be returned in the locpath parameter. If this bit is not specified then locpath may be given as a null string ("")
Definition file: ashell.def

ddb (Structure) [in/out]

is a structure defined in the include file, ashell.bsi, and is defined as follows:

MAP1 DDB

MAP2 DEV,s,6 ! 6 characters AMOS device

MAP2 FILNAM,s,32 ! 6 characters AMOS or 32 host

MAP2 EXT,s,8 ! 3 characters AMOS or 8 host

MAP2 PRJ,s,3 ! 3 character justified P

MAP2 PRG,s,3 ! 3 character justified PN

It is used to receive either the output of the function call if FS_FMA is specified, or the input to it if FS_TOH is specified, or both. Note the size of the filnam and ext fields. If the FS_FMA bit is specified, then the AMOS format file specification passed, can actually be in the format of a local pathname (with long filename), in which case the filename and extension will be processed correctly.

Note that if you are only interested in translating an AMOS-style specification into the equivalent native specification (i.e. using code FS_FMA+FS_TOH) then you do not really need the fields of the ddb parameter and can just supply an X or S variable of 52+ bytes.

status (Num) [out]

returns a non-zero value if the device name (in the spec or ddb parameter/structure) does not exist and the FS_TOH bit is set in the flags parameter. Otherwise it should return zero.

Comments

A common objective is to determine the host directory corresponding to a particular AMOS-style DEVICE:[P,PN] or ersatz device. One way to accomplish this is to start with a dummy filename, like A.A, e.g. "DSK0:A.A[100,222]" or "MYERZ:A.A". Since the A.A will be the last 3 characters of the resulting filespec, you can easily trim them using a substring qualifier, e.g. DIR$ = LOCAL[1,-4].


MIAMEX 4: Get Ctrl+C status

xcall MIAMEX, MX_GETCTRLC, ccon

The ccon parameter is a numeric field into which a non-zero value is returned if Ctrl+C interrupts are currently enabled, and a zero value otherwise.

You can enable/disable Ctrl+C interrupts using CCON.SBR or SET.LIT.


MIAMEX 5: Get echo status

xcall MIAMEX, MX_GETECHO, echon

The echon parameter is a numeric field into which a non-zero value is returned if terminal echo is currently enabled, and a zero value otherwise.

You can enable/disable echo using XCALL ECHO and XCALL NOECHO.


MIAMEX 6: Set command prompt

xcall MIAMEX, MX_SETPROMPT, prompt

The prompt parameter is a string field of up to 20 characters which should be set to the desired comment level prompt string (i.e. to be used in place of the default "dot" prompt).

You can also set the command prompt with SET.LIT. See MX_GETPROMPT to get the current prompt.


MIAMEX 7: Get hex output status

xcall MIAMEX, MX_GETHEX, hexon

The hexon parameter is a floating point variable which will be set to a non-zero value if hex mode is currently set. Otherwise (i.e. if octal mode is set) it will be set to zero.


MIAMEX 8: Set/reset hex mode

Updated June 2016, see History

xcall MIAMEX, MX_SETHEX, hexon

MX_SETHEX sets numeric output to hex or octal. The hexon parameter is a numeric variable which should be set to a non-zero value to enable hex mode; else it will enable octal mode.

You can also set hex or octal output mode with SET.LIT. The most commonly used utility that is affected by this is DUMP.LIT.


MIAMEX 9: Output hex or octal number

xcall MIAMEX, MX_OCVT, number, size, flags {,string}

Symbol | Value | Description
OT_ZER | &h0001 | Disable leading zero blanking
OT_TRM | &h0002 | Output to terminal
OT_MEM | &h0004 | Output to memory
OT_LSP | &h0010 | Output leading space
OT_TSP | &h0020 | Output trailing space
OT_OCT | &h0040 | Force output in octal
OT_HEX | &h0080 | Force output in hex
Definition file: ashell.def

Hex-Decimal Values

This operation is the functional equivalent of the AMOS OCVT monitor call, and is used to output the number in number formatted in either octal or hexadecimal. The default radix used for output (if neither OT_OCT nor OT_HEX is specified) is that set and monitored with MX_GETHEX and MX_SETHEX. The size parameter determines the number of digits in the output result. A zero specifies a floating format in which the number of digits used is just enough to fully contain the result. A non-zero size specifies a fixed number of digits for the result with leading zeros being replaced by blanks. In either case at least one non-blank character will always be output.

The flags parameter is used to determine exactly how the numeric value is to be formatted. It is bitmapped, and each bit may be set by adding together the symbolic values defined in the include file, ashell.def.

The OT_ZER bit disables leading zero blanking. In other words, when a non-zero number is to be printed, leading blanks are converted into spaces. The OT_TRM bit should always be specified, and is included for compatibility reasons. The OT_LSP and OT_TSP bits output an additional leading space and trailing space respectively.

The OT_MEM bit indicates that the output is to be stored in memory (and not output directly to the terminal). If this bit is specified, then the fifth parameter (String) must be present, which is a string or unformatted variable into which the formatted numerical output is returned.

See the wrapper functions Fn'Dec2Hex$(decval,flags,width) and Fn'Hex2Dec(hex$) in the sosfunc: directory (907,10) of the SOSLIB.

History

2016 June, A-Shell 6.3.1516: MX_OCVT now supports 48 bit values, up from 32. This is equivalent to 12 hex characters or 16 octal characters. Note that the standard SOSLIB Fn'Dec2Hex$() function has been updated accordingly.


MIAMEX 10: Check for PPN

xcall MIAMEX, MX_CHKPPN, dev, proj, prog, valid

This operation checks for the existence of the specified PPN on the specified device. Since A-Shell devices and PPNs map to host machine directories, this is equivalent to checking for the existence of the host machine directory which corresponds to the specified device and PPN (according to the DEVICE statements in the miame.ini file).

Parameters

The dev parameter is a string which should be set to a true device and drive, e.g. "DSK0", and not an ersatz device.

The proj and prog parameters are numeric values which form the PPN to be checked, e.g. [proj,prog]. If proj and prog are mapped as B,1 variables, then they are interpreted octally. In other words, if proj = 64 (decimal) and prog = 99 (decimal), the equivalent PPN would be [100,143]. However, if proj and prog are any other types, they are interpreted decimally, the same proj and prog values would be represent PPN [64,99].

valid may be any numeric type and will be returned as non-zero if the specified directory exists.


MIAMEX 11: Get ersatz information

xcall MIAMEX, MX_GETERSATZ, ersatz, dev, proj, prog, status

This operation is used to obtain information about the defined ERSATZ devices.

Note that a short-cut is available to reset to the first ERSATZ device. If the ersatz parameter is a null string, then information on the first ERSATZ device will be returned; it is not necessary to go around a loop waiting for a returned status of one.

Parameters

ersatz (String, 6+)

the ERSATZ device name

dev (String, 6+) [out]

the real device

proj and prog (B,2) [out]

the project and programmer number respectively. See the decryption of these parameters under MIAMEX 19 for notes on decimal vs. octal and backwards compatibility with the old octal PPN system which was upgraded to decimal in A-Shell 5.1.897.

status (F,6) [out]

a value of one is returned if the end of the ERSATZ list is reached, in which case the rest of the parameters do not contain valid data. On the next call, information on the first ERSATZ device will be returned, and then the second, and so on. In these cases the value of status will be zero.


MIAMEX 12: Get A-Shell version

xcall MIAMEX, MX_GETVER, verstr$ {,vmajor, vminor, vedit, vpatch, {ate'vmajor, ate'vminor, ate'vedit, ate'vpatch}}

MX_GETVER returns the current version of A-Shell and, optionally, the individual parts of the version number; and, also optionally and in applicable situations, components of the ATE version number. The version parameter should be a string or unformatted variable large enough to hold the return string (i.e. mapped at least 28 characters), which is in the format: A-Shell version #.#(###). The optional parameters are numeric values; B,1 will work for all except vedit, which should be at least B,2.

The ATE-related parameters have the same format as the corresponding non-ATE parameters. If ATE is not applicable to the current call, those parameters will be returned as 0.

Use GETVER.SBR to return the version of the currently running BASIC program.

Sample return values:

VERSTR$ : "A-Shell Version 5.0.979.9"

VMAJOR : 5

VMINOR : 0

VEDIT : 979

VPATCH : 9


MIAMEX 13: Get/set Tracker flags

xcall MIAMEX, MX_WSET_STATUS, switches {,opcode, ztver}

This operation is used by WSET.LIT in order to control operation of the Tracker. It provides functionality not available under AMOS—namely the ability to modify the Tracker emulation’s under program control.

Parameters

switches (Num) [in/out]

(combine) is a bit-mapped floating-point parameter whose values are as follows:

Value | Description
1 | 132 column mode disabled
2 | Color disabled
4 | Field attributes on mode devices disabled
8 | Force field emulation (Windows only)
16 | ZTERM has been detected
32 | ZTERM was probed for but not detected
64 | Screen area save/restore disabled

opcode (Num) [in]

may be specified as 0 to just retrieve the current settings, or 1 to update the current settings and retrieve the original settings (back into the switches parameter). If not specified, 1 is assumed.

ztver (String, 10+) [in/out]

will receive the ZTERM build number if applicable. Note that the format will be something like "ZV2.0.143a." (The ZV prefix is constant for builds 74+.)


MIAMEX 14: Call into VUE editor

xcall MIAMEX, MX_VUE, filename, gostring

This is used by the A-Shell VUE.LIT program to invoke the A-Shell VUE editor (which is coded in C), but could be used by any program requiring full text editing facilities.

filename is the name of the file (file specification or host pathname) to be edited. You may append any of the valid VUE.LIT switches (/R, /Y, /C, /W) to the end of the FILENAME parameter, but you must convert them to "UNIX format", i.e. use a dash instead of a slash and make them lower case. For example:

FILENAME = "MYFILE.TXT /W /R" ! (wrong)

FILENAME = "MYFILE.TXT –w –r" ! (correct)

If the GO command is used to exit the editor, then gostring (a string parameter of reasonable length) contains a list of commands to be executed, otherwise it is a null string. It would be up to the calling program to process the gostring, presumably by chaining to it as an in-memory command file.

If you only want to display a file but not allow editing of it, then you should specify the –r (read only) switch, or better yet, use EZTYP (which see).


MIAMEX 15: Call into BASIC compiler

Updated January 2014

xcall MIAMEX, MX_COMPIL, filename, switches {,defbuf, vcpattern, status}

MX_COMPIL is used to implement the A-Shell command programs COMPIL.LIT, OCMPIL.LIT, PRE.LIT and OPRE.LIT, by calling into the A-Shell BASIC compiler which is coded in C. See the documentation on COMPIL for more information about the switches and variations of COMPIL.

filename (String) [in]

is the AMOS file specification or host pathname of the program to be compiled. The compiler itself will default the extension to BAS if necessary.

defbuf (String) [in]

contains one or more "define sym = value" statements (corresponding to /C:sym=value command line switches). Each statement must be terminated with chr(10). String values must be quoted. For example, the defbuf equivalent of the command line:

compil prog/x:2/c:MODE=1/c:PLATFORM$=Win

would be:

defbuf = "define MODE = 1" + chr(10) + "PLATFORM$ = ""Win"""+ chr(10)

vcpattern (String) [in]

contains the pattern specified in /VC:pattern

status (Num) [out]

returns 0 if the compile succeeds, else failure.

switches (Num) [in]

is a bitmap of switch values as listed below:

Value | Corresponding COMPIL.LIT switch or variation
&h0000001 | /A, use 24-bit instead of 16-bit transfer addresses
&h0000002 | /M, treat first instance of unmapped variable as an error
&h0000004 | /O, omit line numbers from compiled program
&h0000008 | Act as OCMPIL (instead of COMPIL
&h0000010 | /S, silent output – omit ++include lines
&h0000020 | /N, omit phase two compilation statistics
&h0000040 | /X:1, act as COMPLP – BASIC Plus mode
&h0000080 | /D, limited d/BASIC support
&h0000100 | /X:2, A-Shell extensions
&h0000200 | /V:1, BASIC 1.4a compatibility
&h0000400 | /T, Trace – output source while compiling
&h0000800 | /I, assume old ISAM in ambiguous OPEN statements
&h0001000 | /AV, handle &gt65K variable space
&h0002000 | /B, output errors to prog.lst
&h0004000 | /MX, like /M but complain for every occurrence of each unmapped variable
&h0020000 | /RC, RUN compatibility
&h0080000 | /LF, generate lsx (list) file
&h0100000 | /CI, case insensitive
&h0200000 | /C:sym=value
&h0400000 | /IEEE
&h0800000 | /VC:pattern
&h1000000 | /LI
&h2000000 | /P, preprocess for named parameter support

Hex-Decimal Values

History

2014 January, A-Shell 6.1.1371: Add support for /P.

2010 March, A-Shell 5.1.1177: Add status parameter.


MIAMEX 16: Call into PREBAS pre-compiler

xcall MIAMEX, MX_PREBAS, filename, switches

This is equivalent to MIAMEX function 15 except it calls the PREBAS compiler instead.


MIAMEX 17: Synchronize directories

xcall MIAMEX, MX_SYNC_CWD

Although A-Shell directories generally correspond one-to-one with native directories on the host operating system, it is not automatically the case that the operating system’s idea of your current working directory will always match up to your A-Shell login directory. MX_SYNC_CWD may be used at any point to resolve this problem by synchronizing the current working directory with that of the current PPN. (This is generally only of interest when interfacing to some host operating facility or executing a native operating system command.)

A call to this function is automatically made by LOG.LIT and by HOST.LIT in order to minimize problems. If a different utility is written to change PPN or execute a host command, it might be advantageous to synchronize the working directory.

See MX_GETENV for a way to query the current host operating system working directory.


MIAMEX 18: Get next line of command file

xcall MIAMEX, MX_NXTCMD, cmdline, status {,flag}

This operation returns (and in doing so, by-passes) the next line of the current command (.CMD or .DO) file. It is used in the implementation of GOTO.LIT in order to scan the command file for labels.

Parameters

cmdline should be a string variable long enough to return any expected command line.

status is a floating-point return code indicating the success of the operation. A zero value indicates that either no command file is running, or the end of the current command file has been reached. A non-zero value indicates success, in which case cmdline contains the text of the command line.

If flag (Num) is specified and evaluates to a non-zero value, then the next line of the command file (returned in cmd) will not be removed from the current command file—i.e., a non-destructive read.

Comments

This function is used in the implementation of GOTO.LIT in order to skip over the command line contents up to the target label. The technique can also be useful in a case where you want to effectively abort a CMD/DO file execution in response to some data or environmental condition, perhaps chaining to another CMD/DO file instead.

History

2010 June, A-Shell 5.1.1182: Support returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized

2009 September, A-Shell 5.1.1160: MX_NXTCMD now supports returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized.

2009 May, A-Shell 5.1.1150: Add flag parameter.


MIAMEX 19: Get device definition

Updated August 2016

xcall MIAMEX, MX_GETDEV, dev, proj, prog, drbase, status, {,devflags}

Each call to MX_GETDEV returns information about the next device in the device table. See the DEVICE system parameter for information about how the devices in the device table are defined. When MX_GETDEV hits the end of the device table, it returns a status code and then starts over at the beginning on the next call. You can also force it to restart at the beginning by setting the dev parameter to "".

MX_GETDEV is very similar to MX_GETERSATZ, but returns information about "real" devices rather than ersatz devices.

Parameters

dev (String, 6) [in/out]

On input, if null (""), resets the scan to the start of the device table—i.e. returns the first device in the table. On output, returns the next device in the table, e.g. "DSK1", with no trailing colon. See status.

proj, prog (b,1 or b,2) [out]

For normal device definitions, whose PPNs are implicitly defined by the existence of ###### subdirectories, these parameters will return 0. Only for devices that are explicitly defined with only a single PPN will these parameters be returned with non-zero values. In that case, if proj and proj are mapped as b,2 (preferred), the two parts of the PPN will be returned as decimal values ranging from 0-999. Although deprecated, for backwards compatibility, if proj and prog are mapped as b,1 variables, the values will be encoded as if octal (with a range of 0-377).

drbase (String,100+) [out]

The base path for the device or device/ppn combination is returned here. It will be terminated with a trailing directory separator character, e.g. "C:\VM\MIAME\DSK0\").

status (Num) [out]

Returns 0 on success, else 1 if it hits the end of the device table, in which case the rest of the return parameters should be ignored. Note that the next call after hitting the end of the table will return the first device in the table.

devflags (Num) [out]

If specified, returns attribute flags related to the device (zero or more of the following):

Value | Meaning
&h01 | Read-only device
&h02 | Memory device

See Also

• PPN Numbering

History

2004 August, A-Shell 4.9(897): PPN system converted from octal (0-377) to decimal (0-999). MX_GETDEV updated to support old-style (b,1) and new-style (b,2) proj, prog parameters.


MIAMEX 20: Get first matching file

Updated June 2011; see History

xcall MIAMEX, MX_FINDFIRST, directory, status, filename, size, attrib {,cdate, ctime, udate, utime {, adate, atime}}

This operation, combined with its sister function, MX_FINDNEXT, is used to scan directories for subdirectories or files.

Parameters

directory (String) [in]

This must be set to the directory which is to be scanned for files. This directory specification must be in host operating system format, and include the terminating directory separator. See MX_FSPEC (Perform FSPEC on AMOS string) for information on converting an AMOS-style directory to the equivalent host directory.

status (Num) [out]

On return, status is set to zero to indicate success. A non-zero status indicates an error, most likely that no files or directories match the specification you gave in directory.

filename (String) [out*]

The first entry in the specified directory will be returned in filename. Typically this is a regular file (in name.ext format) but may be a special file, such as another directory or the "." and ".." entries which typically appear at the start of each directory, which you can determine by the attrib flags (below). The returned name will be truncated to fit, but you should specify a reasonably large variable, since UNIX and Windows filenames can be quite long.

size (F,6) [out]

returns the size of the found file, in bytes.

attrib (Num) [out]

is a bit-mapped numeric field into which are placed the various attributes of the file or sub-directory represented by filename, according to the following table:

Symbol | Value | Meaning
FATR_NORMAL | 1 | Normal file
FATR_SUBDIR | 2 | Subdirectory
FATR_READONLY | 4 | You (current user) have read-only permission for this file or directory
Definition file: ashell.def

cdate, udate, adate (String, 10+ bytes) [out]

are the create/status change date, update/modify date, and access date of the file or directory, using the format dd-mon-yr (e.g. "01-Jan-08"). Note that under UNIX systems, the CDATE will be changed when the privileges or ownership of the file is changed.

ctime, utime, atime (String, 5+ bytes) [out]

are the create/status change time, update/modify time, and last access time for the file or directory, using the format (hh:mm).

Comments

* Under Windows, you can actually set directory to a literal or wildcard filename to skip directly to the first matching file. However, this is not recommended, since under UNIX you must specify a directory (not a file path) with a trailing directory separator.

History

2011 June, A-Shell 5.1.1219: Directory scanning bug fix/enhancement: MX_FINDFIRST / MX_FINDNEXT / MX_FINDEND sequences can now be nested. Previously, MX_FINDFIRST effectively executed an implicit MX_FINDEND to terminate the previous sequence, which could have led to a crash or other error if the interrupted sequence was then continued.

Although the documentation has always clearly stated that only one directory scan sequence can be in progress at the same time, the situation can arise in event-driven contexts, or within nested routines, where it is not possible for the local context to be aware of a scan in progress by the calling context, or vice versa. Nesting thus eliminates a cause of hard-to-debug application or system errors.

2008 October, A-Shell 5.1.1126: Embedded %ENV% variables are now supported.


MIAMEX 21: Find next matching file

Updated June 2011

xcall MIAMEX, MX_FINDNEXT, status, filename, size, attrib {,cdate, ctime, udate, utime {, adate, atime}}

MX_FINDNEXT must be preceded by a call to MX_FIND_FIRST. It returns the next file or subdirectory in the path specified in the original call to MX_FIND_FIRST. On exiting, the floating-point status variable, status, contains zero, in which case the remaining parameters are set as for the return from MX_FIND_FIRST, or non-zero to indicate an error (most likely no more files or sub-directories in the path).

Note that the parameter list for this call is identical to that for the MX_FIND_FIRST call, except that the PATH parameter is omitted. The starting path is set by the MX_FIND_FIRST call and maintained internally after that.

See MX_FINDEND for additional information and a program example, and the History note in MX_FINDFIRST.


MIAMEX 22: Get directory separator char

xcall MIAMEX, MX_DIRSEP, character

MX_DIRSEP returns a single byte parameter (usually a string) into which the directory separator character is placed. This is the character used in specifying host pathnames, and is usually a forward slash ( / ) for UNIX systems, and a backslash ( \ ) for Windows systems. Knowing this is useful when parsing native filespecs and also as a quick way of determining which of the two classes of operating systems you are running on. See MX_FINDEND for additional information and a program example.


MIAMEX 23: End directory search

Updated June 2011

xcall MIAMEX, MX_FINDEND

The A-Shell directory scanning system only permits the scanning of one directory at a time with the use of the MX_FINDFIRST and MX_FINDNEXT functions. Once the processing of that directory has been completed, then the MX_FINDEND function must be used to terminate and free up any data areas associated with the scan. The recommended logic for scanning a directory is:

xcall MIAMEX, MX_FINDFIRST, path, status, filename, size, attrib

do while STATUS = 0

....

.. Process directory item here

....

XCALL MIAMEX, MX_FINDNEXT, status, filename, size, attrib

loop

! terminate directory search and free resources

xcall MIAMEX,MX_FINDEND

See the History note in MX_FINDFIRST.


MIAMEX 24: Get command prompt

xcall MIAMEX, MX_GETPROMPT, prompt

MX_GETPROMPT returns the current A-Shell command prompt string. The prompt parameter should be a string variable large enough to hold the longest possible prompt (20 characters). See MX_SETPROMPT to set the current prompt.


MIAMEX 25: Get file hash total

xcall MIAMEX, MX_HASHFILE, path, hash1, hash2, hash3, hash4

MX_HASHFILE returns the hash total for the specified field.

path must be set to the native (host operating system) format file specification of the file to get the hash off. (See MX_FSPEC to convert an AMOS fspec to a native fspec.)

hash1 through hash4 should each be a floating point, to receive the four parts of the hash.

Example

The following example illustrates the use of this function to display a hash total in the format used by DIR/H:

MAP1 HSHSTR,s,4 ! Octal string byte

MAP1 STRING'HASH,s,15 ! Display format hash-total (###-###-###-###)

xcall MIAMEX,MX_HASHFILE,THISIPATH,HASH1,HASH2,HASH3,HASH4

xcall MIAMEX,MX_OCVT,HASH1,3,OT_MEM+OT_OCT,HSHSTR

STRING'HASH = HSHSTR+"-"

xcall MIAMEX,MX_OCVT,HASH2,3,OT_MEM+OT_OCT,HSHSTR

STRING'HASH = STRING'HASH+HSHSTR+"-"

xcall MIAMEX,MX_OCVT,HASH3,3,OT_MEM+OT_OCT,HSHSTR

STRING'HASH = STRING_HASH+HSHSTR+"-"

xcall MIAMEX,MX_OCVT,HASH4,3,OT_MEM+OT_OCT,HSHSTR

STRING'HASH = STRING'HASH+HSHSTR

print STRING'HASH

Note that for display purposes, the standard AMOS and A-Shell hash-total formats treat the numeric values as octal.

For related and additional informating on hash methods, see DIGEST and HASH.


MIAMEX 26: Format last file spec

xcall MIAMEX, MX_PRFSPEC, string

MX_PRFSPEC retrieves the last processed file specification and formats it in standard AMOS format (i.e. dev#:file.ext[p,pn]) where dev# and [p,pn] are omitted if the file is on the current device or in the current directory.

As a practical matter, the last processed filespec will be the one last processed via MX_FSPEC.


MIAMEX 27: Copy file

(1) xcall MIAMEX, MX_COPYFILE, src$, dst$ {,flags, status}}

(2) xcall MIAMEX, MX_COPYFILE, chin, chout

The first syntax moves or copies files based on their names. The second syntax copies the contents of the source to the destination using file channels and thus requires that the input and output files be opened and closed by the calling application. The routine distinguishes between the two calling formats based on the data type of the second argument. If it is a string (S or X) then it is treated as the src$ parameter and the first syntax is used. If it is numeric (B or F) then it is treated as chin and the second syntax is used.

In most cases, the first syntax is preferable, as it is easier to use, more flexible, more efficient, and with fewer side effects. See Comments, below, for details on the differences between the two methods.

Parameters

src$, dst$ (String) [in]

source and destination file specifications, either AMOS-style or native

chin, chout (Num) [in]

input and output file channels. chin must be opened for INPUT or RANDOM. chout must be opened for OUTPUT (or APPEND), or RANDOM. It is up to the application to properly close these channels on return from the subroutine.

flags (Num) [in] (default 0)

Symbol | Value | Meaning
CPYF_MOVE | &h0001 | Move file instead of copy file
CPYF_REPL | &h0002 | Allow replacement of existing destination
CPYF_SETRO | &h0010 | Force read-only bit to be set on output
CPYF_CLRRO | &h0020 | Clear read-only bit on output
Definition file: ashell.def

If neither of the read-only flags are set, then the status of the read-only flag is preserved, unless copying from a device with the ,RO flag, in which case the read-only flag will be cleared. The read-only flags only have meaning in WINDOWS.

status (F,6) [out]

Value | Meaning
0 | Success
-1 | Destinations exists and CPYF_REPL flag not specified
-2 | Source does not exist
-3 | Invalid parameter types
<other> | System error code. For UNIX, this will be the return code from the mv or cp utility. For Windows, it will be a Windows system error code (translatable by MIAMEX,86). See Comments.

Note that under UNIX, the operation invokes the mv or cp utilities, which must be available in the PATH.

Comments

Advantages of the new (filespec, syntax #1 above) method over the old (file channel, syntax #2 above) method include:

• The Move option (CPYF_MOVE) is much more efficient than normal Copy, provided source and destination are on the same volume or file system. If not, then the move is simulated by a Copy followed by a Delete of the source.

• Move preserves the file creation and file modification times.

• The new Copy preserves the file modification time (but updates the file creation time because it is creating a new file). The old syntax, by contrast, causes both the creation time and modification time to be updated.

• Simplifies the logic for protecting against accidental overwrite, as well as for detecting common errors in the operation. With the old method, in addition to needing the separate file opens and closes, you would have needed to also use lookup operations to check for the most common considerations of source-does not-exist or destination-already-exists.

On the other hand, the old (file channel) syntax offers the following capabilities that are not possible with the (new) filespec syntax:

• You can append the source file to the destination by opening the destination for APPEND.

• If the destination exists, you can overlay the source on it, starting at an arbitrary position, by first opening the destination channel for APPEND, and then using the MIAMEX,118 function to position the destination stream pointer prior to the copy operation. Note that this requires A-Shell 4.9.958 or later.

Warning: when intermixing two kinds of output to an open file channel (e.g. MX_COPYFILE and PRINT #CH statements), you should first disable file buffering for that channel (MX_NOBUF), lest the different buffering schemes used by the two methods result in jumbled output.

History

2007 November, A-Shell 4.9.988: Undex UNIX, if an error (other than -1, -2, or -3) occurs, the full text of the error message can be found in the temporary file <jobnam>.tmp, on return from the xcall.

2006 October, A-Shell 4.9.968: MX_COPYFILE no longer defaults to xxx extensions

2006 April, A-Shell 4.9.954: Add syntax (1)


MIAMEX 28: Output error message

xcall MIAMEX, MX_PRINTERR, errnum

MX_PRINTERR outputs the standard error message associated with the last processed error. It is generally used within LIT programs to display standard error messages. errnum is a floating point which will receive the error number.

See ERRMSG for a more powerful and flexible method of handling error messages.


MIAMEX 29: Output rename error message

xcall MIAMEX, MX_RENAMERR

MX_RENAMERR displays a specialized error message of the type associated with a failure to rename a file. It is probably only used with the RENAME.LIT program.


MIAMEX 30: Get queue block contents

xcall MIAMEX, MX_GETQUEUE, blkno, qblock

MX_GETQUEUE retrieves the contents of the queue block specified by the numeric parameter blkno, returning it in the unformatted variable qblock. qblock should be mapped as:

MAP1 Q'BLOCK ! Queue data block

MAP2 QNEXT,b,2 ! Pointer to next queue block

MAP2 QTYPE,b,2 ! Queue block type (see table)

MAP2 QOWNER,b,2 ! Owner of queue block

MAP2 QJUNK,b,2 ! Currently unused

MAP2 QDATA,x,32 ! 32 bytes of data

MAP2 QD'FLOCK,x,@QDATA ! Format of FLOCK record

MAP3 ACTION,b,2 ! Action

MAP3 MODE,b,2 ! Mode

MAP3 RECORD,b,4 ! Record number

MAP3 CHANNEL,b,4 ! Channel number [12] was 2

MAP2 QD'XLOCK,x,@QDATA ! Format of XLOCK record

MAP3 LOCK1,i,4 ! Primary lock code

MAP3 LOCK2,i,4 ! Secondary lock code

MAP3 LOCK3,b,2 ! Lock class: 0=xlock

Queue block zero is a control record of a different layout, which should not be accessed.

Each of the data queue blocks shares the same first four fields, followed by a 32 byte area whose format depends on the block type (qtype):

Value | Queue block type
0 | Unused block
3 | FLOCK – normal
4 | XLOCK
6 | FLOCK – inactive
7 | ZLOCK (proprietary format)
8 | RLOCK (proprietary format)
9 | FLOCK – pending

The number of queue blocks is set by the QUEUE= statement in the miame.ini file.

To scan through all of the active queue blocks, start at blkno 2 and then proceed to set each new blkno to the qnext field, until it becomes zero.


MIAMEX 31: Get environment variable

Updated October 2014; see History

xcall MIAMEX, MX_GETENV, envvar, value {,flag}

MX_GETENV retrieves the definition of an environment variable; use MX_SETENV to define environment variables.

Parameters

envvar (String) [in]

The name of the environment variable (e.g. "MIAME"). Use of the % delimiters surrounding the name is optional, i.e. "MIAME" and "%MIAME%" are equivalent. Environment variables are not case sensitive under Windows, but they are under UNIX, so it it best to stick with the convention of using all upper case. There is no particular limit to the length of an environment variable name.

value (String) [out]

Returns the definition of the specified environment variable. If not defined, returns a null string. There is no particular limit to the length of an environment variable definition. It will truncated if needed to fit into the variable provided.

flag [in]

If specified and set to 1, then the returned value will be de-mangled—i.e., converted from the DOS 8.3 compressed format to the full long format, if possible. See AG_GETENV for samples.

Comments

MX_GETENV only works relative to the system that the program is running on, i.e., it will not retrieve an environment variable definition from the remote telnet client. To accomplish that for ATE, see AG_GETENV.

Environment variables may be defined in various ways depending on the host operating system. Under Windows, you can use the Control Panel "System" applet. Under UNIX, they are set by shell commands, e.g. "MIAME=/vm/miame". The set command will typically display the current definitions.

In addition to system defined environment variables, A-Shell understands a few special variables which do not have to be set externally. One is "%CurrentDirectory%", which will return the current working directory in the host operating system. Two others, which are only available under Windows, are "%WindowsDirectory%" and "%SystemDirectory%", which return the directory spec of the "Windows" and "Windows System" directories. Another two are set by A-Shell when it launches: %MIAME% is the directory where the miame.ini file is, and %MIAMEFILE% is the full path spec of the miame.ini file.

History

2014 October, A-Shell version 6.1.1391: Passing an empty environment variable name parameter now causes MX_GETENV to return the entire list of environment variable definitions, delimited by a chr(10) character between each NAME=VALUE string. Also, you can now specify a dynamic string variable (S,0) for the return parameter, which will expanded as needed.


MIAMEX 32: Set default file extension

xcall MIAMEX, MX_SETEXT, ext

MX_SETEXT may be used to set the default file extension for a subsequent file open operation.


MIAMEX 34: Get ISAM version and serial

xcall MIAMEX, MX_GETCISAM, fspec, version, serial

MX_GETCISAM returns the version number and serial number of the ISAM or ODBC library associated with the specified fspec. version and serial should be mapped as strings of 33+ bytes. It is mainly used within ISMUTL.

ISAM-A support requires an add-on license to A-Shell. If not licensed, the serial string will be returned as "<not licensed>".

History

2009 September, A-Shell 5.1159: Routine modified to support returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized.


MIAMEX 36: Get AMOS hash mode status

xcall MIAMEX, MX_GETHASH, status

MX_GETHASH returns a flag indicating whether we are in AMOS hash compatibility mode. In this mode, the hash algorithm (used by DIR/H) treats LF line terminators are treated the same as CRLF pairs, so that normal text files will have the same hash code under UNIX, which typically uses LF line terminators, as they do under AMOS, which typically uses CRLF terminators.

The status parameter (F,6) returns 0 if not in AMOS hash compatibility mode, else non-zero.


MIAMEX 37: Set/reset AMOS hash mode

xcall MIAMEX, MX_SETHASH, flag

MX_SETHASH allows you to set or reset the AMOS hash compatibility mode. The status parameter (Num) should be set to 0 to reset (clear) AMOS hash compatibility mode, else non-zero to set it.

See MX_GETHASH for further notes on AMOS hash compatibility mode. Also note that the SET.LIT command allows you to query and set/reset this option.


MIAMEX 38: Create path

xcall MIAMEX, MX_MKPATH, dirspec, status

MX_MKPATH creates a new native operating system directory. MX_MKPATH may (and should) be called for any operating system.

Parameters

Parameter | Type | I/O | Description
dirspec | String | in | the directory name to create. This should be in native file format, but (as of build 960) may include embedded environment variables (e.g. %MIAME%\NEWDIR).
status | Num | out | will return 0 for success, else an error number.

Comments

MX_MKDIR will be invoked automatically if this function is requested under Windows. Therefore, it may be best to always use MX_MKPATH in your application and let A-Shell decide when to convert it to MX_MKDIR. The exception would be if your application which is running on a server (with ATE clients) wants to explicitly create a directory on the ATE client. In this case, you must use MX_MKDIR and set the remoteflag parameter to "R."

Note that this function supports embedded environment variables, e.g.:

xcall MIAMEX,MX_MKPATH,"%MIAME%\901902",STATUS

In general this function will not succeed if the parent directory doesn't already exist.


MIAMEX 39: Delete path

xcall MIAMEX, MX_RMPATH, dirspec, status

MX_RMPATH deletes the specified native operating system directory.

dirspec is the directory name to delete, e.g. "C:\VM\JUNK" or "/vm/junk".

status (F,6) will return 0 for success, else an error number. You may use MX_ERRNOMSG to translate the error number to a text message.


MIAMEX 41: Zap jobtbl and queue blocks

xcall MIAMEX, MX_ZAPQUEUE, jobno

MX_ZAPQUEUE removes the jobtbl record and any associated queue blocks for the specified job number. Needless to say, this will not be appreciated if the user is actively running, and should only be used in extreme circumstances or when you are sure the user is no longer active. jobno is the job number of the user to zap.

MX_ZAPQUEUE is used by KILL, QUTL and SYSTAT/K/Z commands. The last of these, SYSTAT/K/Z, is the preferred and best way to remove resources left over from a job that has aborted without cleaning itself up.


MIAMEX 50: Get LOKSER status

xcall MIAMEX, MX_GETLOKSER, lokflag

MX_GETLOKSER returns a flag indicating if LOKSER is active or not. lokflag (F,6) will be returned as 0 if LOKSER is not active, while a non-zero value indicates that LOKSER is active.


MIAMEX 51: Set LOKSER status

xcall MIAMEX, MX_SETLOKSER, lokflag

MX_SETLOKSER allows you to turn LOKSER on or off. lokflag (Num) must be set to 0 to turn LOKSER off, or non-zero to turn it on.

You may also use SET.LIT to query or change the LOKSER status.


MIAMEX 52: Get CMD file input status

xcall MIAMEX, MX_GETCMDINP, cmdinp

MX_GETCMDINP returns a flag indicating whether command file input mode is active (for all subsequent INFLD operations). See MX_SETCMDINP for more details. cmdinp (Num) will be returned as 0 to indicate that CMD file input mode is not on; non-zero indicates that it is on.


MIAMEX 53: Set CMD file input status

xcall MIAMEX, MX_SETCMDINP, cmdinp

MX_SETCMDINP allows you to turn command file input mode on and off for subsequent INFLD.SBR (or INPUT.SBR) calls. In the normal case, BASIC INPUT and monitor level input operations will read from an active command file, but image mode input, such as XCALL INFLD or XCALL INPUT, will not. However, you can override this and force INPUT.SBR and INFLD.SBR to read from a command file, either by passing the CMDINP argument to INFLD, or by adding the "p" character to the SBR=INFDEF: string (in the miame.ini), or by using SET CMDINP from the dot prompt, or by setting this flag.

cmdinp (Num) should be set to 0 to turn command file input mode off, or 1 to turn it on.


MIAMEX 54: Get signal received status

xcall MIAMEX, MX_GETSIG, sigmask

(UNIX only) MX_GETSIG returns a bitmap indicating which signals have been received since the last time this function was called.

Parameters

sigmask (F,6)

Returns with zero or one of the following bits set to indicate which signal (if any) was received:

Symbol | Value | Name | Meaning
SR_INT | &h0001 | SIGINT | Ctrl+C
SR_CHLD | &h0002 | SIGCHLD | Child process terminated
SR_USR1 | &h0004 | SIGUSR1 | Receipt of ITC or IJC message
SR_USR2 | &h0008 | SIGUSR2 | PolyShell swap operation
SR_HUP | &h0010 | SIGHUP | Hangup (telnet or terminal session disconnected)
SR_KILL | &h0020 | SIGKILL | Kill (cannot be trapped so will never be seen)
SR_TSTP | &h0040 | SIGTSTP | Background task waiting for terminal context to perform input operation
SR_ALRM | &h0080 | SIGALRM | Alarm signal (used by sleep timers and WAKNO.SBR)
SR_TERM | &h0100 | SIGTERM | Default kill signal
SR_PIPE | &h0200 | SIGPIPE | Broken pipe or socket connect (other end has terminated)
Definition file: ashell.def

Hex-Decimal Values


MIAMEX 55: Clear signal received status

xcall MIAMEX, MX_CLRSIG, sigmask

(UNIX only) MX_CLRSIG allows you to clear specific bits in the signal received mask. This would be useful in a situation where you wanted to check whether a certain signal was received during a certain time frame. (First you would clear the bit for that signal, then later you would check, using MX_GETSIG, if the bit was set.)

sigmask (Num) should be set to the sum of the signals from the table above (see MX_GETSIG) that you want cleared. Use –1 to clear all of the signal flags. 0 does nothing.

SUBMIT/W uses this function, along with function 54. First it clears the SIGCHLD signal flag (2), then submits the task, then sleeps, checking every second to see if the SIGCHLD signal flag has been set, which it will be when the submitted task terminates.


MIAMEX 56: Define environmental variable

Updated and reviewed April 2011

xcall MIAMEX, MX_SETENV, envdef {,status}

MX_SETENV is used to define environment variables for the current process, including the special case of TERM, for which see Comments, below. To set environment variables for the remote ATE client, see AG_GETENV.

Parameters

envdef (String) [in]

Contains a definition string of the form "name=value" specifying the name of the environment variable to be set (e.g. defined or modified) and its value. For example, "TERM=AM62CG", or "MYNAME=Jack"

status (signed numeric) [out]

If specified, will return one of the following:

Code | Meaningt
0 | Success
-1 | General error
-2 | Overflow of memory set aside for environment variables.

Comments

In general, setting an environment variable doesn't have any immediate side effect. Instead the value is simply stored, for the purposes of retrieving it later, either using MX_GETENV, or indirectly by referencing the variable name in some other expression context, as in the examples below:

xcall MIAMEX, MX_SETENV, "MYPATH=c:\vm\miame\jack", status

...

open #ch, "%MYPATH%\myfile.log", output

In the example above, we use the %envvar% syntax, which is recognized by Windows as well as by A-Shell, regardless of the platform, in nearly all contexts where a filespec may be used. If specifying an environment variable in a UNIX shell context, use the syntax $env, e.g. $MYPATH.

Environment variable definitions are available only to the current A-Shell prcess, and to those child processes launched by it (e.g. by HOSTEXor MX_SHELLEX). As an example of the former, under UNIX:

xcall MIAMEX, MX_SETENV, "MYPATH=/vm/miame/jack", status

...

xcall HOSTEX, "ls -l $MYPATH/a*", STDOUT$

A-Shell itself defines and recognizes several environment variables.

The TERM environment variable, used by UNIX—and A-Shell—to indicate the type of terminal in use, is a special case. When set from within an A-Shell session connected to a remote terminal (e.g. a TELNET or SSH session), A-Shell also re-initializes its terminal configuration and possibly changes its internal terminal "driver" to match the terminal type.

For A-Shell/UNIX, the TERM variable is typically established automatically when the TELNET/SSH session is initiated. But you may also set it manually prior to launching A-Shell (from the shell prompt), or you can set it via the -td command line switch.

Update Notes

Prior to 5.0, MX_SETENV used a different syntax:

xcall MIAMEX, MX_SETENV, envvar, value, status

Where envvar was the name of the variable to set and value was the value. This syntax is still supported for compatibility but is deprecated.


MIAMEX 57: Send signal to another process

xcall MIAMEX, MX_KILL, pid, signal, status

(UNIX only) MX_KILL allows you to send any UNIX signal to another process, provided you have sufficient privileges. It provides essentially the same functionality as the UNIX kill utility (which, despite its name, allows sending any signal).

Parameters

pid (Num) [in]

is the process ID number of the target process. (You can get this information from SYSTAT, or perhaps by reading the jobtbl directly.)

signal (Num) [in]

is the signal to send, from the following table. Note that the actual signal numbers associated with the names are not guaranteed to be uniform across versions of UNIX, although these (taken from Linux) are fairly standard. Signals that have no plausible use in applications have been omitted. (Also, note that these numbers are not related at all to the numbers in the SIGMASK used in functions 55 and 56.) Signal 0 is particularly useful for determining if a target process still exists.

Symbol | Value | Meaning
None | 0 | Used to determine if target PID exists
SIGHUP | 1 | Hangup (telnet or terminal session disconnected)
SIGINT | 2 | Ctrl+C
SIGQUIT | 3 | Abort foreground processes, without core dump
SIGABRT | 6 | Force abort; similar to SIGQUIT
SIGKILL | 9 | Kill (cannot be trapped)
SIGUSR1 | 10 | User signal (used by ITC, IJC messages)
SIGUSR2 | 12 | User signal (used by PolyShell)
SIGALRM | 14 | Alarm signal (used by sleep timers and WAKNO.SBR)
SIGTERM | 15 | Default kill signal; generates error 251
Definition file: ashell.def

status (Num) [out]

Returns 0 to indicate success (i.e. the signal was delivered to the target process, or, in the case of the pseudo-signal 0, it indicates that the target process exists, regardless of whether the sender has sufficient privileges to send a real signal). For any real signal (i.e. signal > 0), status will return -1 if the sender does not have sufficient privileges to deliver the signal.

In order to deliver a signal to another process, it must be logged in as the same effective user as the sender, or the sender must be root. One way to ensure this is to use the "setuid" bit on the ashell executable to make all A-Shell users the same effective user. Search this doc for "ashkill" for further information on that subject.


MIAMEX 59: Get OPTIONS flags

xcall MIAMEX, MX_GETOPTIONS, options1 {,options2}

MX_GETOPTIONS returns a bitmap field indicating which options1/options2 have been set. Note that these options are the same ones that are defined in the A-Shell initialization file, miame.ini. The normal way these flags are set is via the OPTIONS parameter in miame.ini, or by SET.LIT, or by MX_SETOPTIONS. Note that miame.ini uses the symbol name without the (GOP_ or GOP2_) prefix.

See related information and a sample program under the next topic, MIAMEX 60: Set OPTIONS flags.

Options1 Symbol | Value | Description
GOP_CRNL | &h00000001 | Force CRNL line terminators
GOP_EXTFIO | &h00000002 | Extended file I/O options
GOP_AS400 | &h00000004 | AS400 telnet mode (strip 8s and 11s)
GOP_LATIN1 | &h00000008 | Latin1 character set
GOP_OEM | &h00000010 | Set internally for OEM fonts
GOP_EFFUSR | &h00000020 | Use effective rather than login user
GOP_AMOSRUNSBR | &h00000040 | Execute AMOS.SBR in-process
GOP_BRKALC | &h00000080 | Prefill random file allocations with ]]]
GOP_HEXDEC | &h00000100 | "Hexadecade" dates
GOP_NOLEADFF | &h00000200 | Strip leading formfeeds from print files
GOP_NOAUTOXLT | &h00000400 | Defeat certain auto F-key translations
GOP_NTTS | &h00000800 | Force Windows Terminal Server mode
GOP_FPROUND | &h00001000 | Round floating point results to 48 bits
GOP_FLDEMU | &h00002000 | Emulate field terminal (Windows)
GOP_EXITWAIT | &h00004000 | Forces wait for confirmation before closing session launched with –e
GOP_ABSLOOKUP | &h00008000 | Return absolute value in LOOKUP
GOP_QCLOSE | &h00010000 | Close qflock between accesses
GOP_QBUFFER | &h00020000 | Normal qflock buffering
GOP_LOCALCOPIES | &h00040000 | Implement multiple spool copies via multiple submissions
GOP_SHLPATH | &h00080000 | Special search path for SHL
GOP_AUTOCCON | &h00100000 | Auto-enable Ctrl+C at start of each program
GOP_RAWTABS | &h00200000 | Raw tab output to terminal
GOP_XABORT | &h00400000 | Allow X out of window
GOP_NOXABORT | &h00800000 | Disable OK in X abort dialog
GOP_STRICT | &h01000000 | Strict AMOS compatibility
GOP_NUMPAD_COMMA | &h02000000 | Treat decimal point on Windows numpad as comma
GOP_AUTOX | &h04000000 | Allow auto expansion of ISAM and memo files
GOP_IDXLOK | &h08000000 | Lock entire ISAM IDX during update
GOP_MMAPTIME | &h10000000 | Force update of modify time of mmaped files every minute
GOP_AUTO_MEMOPEN | &h20000000 | Check user memory when opening file; open in memory if present
Definition file: ashell.def

Hex-Decimal Values

Options2 Symbol | Value | Description
GOP2_NOPSDLG | &h00000001 | Disable the print screen (Ctrl+P) dialog and just print directly; see the PRINTER system parameter.
GOP2_NODELSYS | &h00000002 | Do not delete the JOBTBL.SYS and QFLOCK.SYS files on exit, ever. (Otherwise they are delete if no other users are in A-Shell.)
GOP2_GUISPCINDENT | &h00000008 | Activate "intelligent" GUI indenting
GOP2_AUTOTPRINT | &h00000010 | Treat PRINT statements as TPRINT
GOP2_AUTODLGSTATE | &h00000020 | If OPTIONS=AUTODLGSTATE is set in miame.ini, you can clear it within a program via: xcall MIAMEX, MX_GETOPTIONS, options1, options2 xcall MIAMEX, MX_SETOPTIONS, options1, options2 and not GOP2_AUTODLGSTATE
GOP2_EFS_OUT_AMOS | &h00000100 | Auto encrypt output files opened with AMOS specs (requires EFS add-on)
GOP2_EFS_OUT_HOST | &h00000200 | Auto encrypt output files opened with native/host specs (requires EFS)
GOP2_EFS_ALLOCATE | &h00000400 | Auto encrypt on allocate (requires EFS)
GOP2_EFS_ALCINDEX | &h00000800 | Auto encrypt on ALLOCATE’INDEXED (requires EFS)
GOP2_INI_AV | &h00001000 | VUE looks for ini.av instead of ini.vue
GOP2_SBX_RUNDIR | &h00002000 | Search for SBX in same dir as RUN first
GOP2_NOSPOOL | &h00004000 | Disable spooling.
GOP2_NOCAPTURE | &h00008000 | Disable screen capture (Ctrl+P)
GOP2_MSYNC_MAP | &h00010000 | Sync entire map on write to memory mapped file.
GOP2_MSYNC_PAGE | &h00020000 | Sync page on write to memory mapped file
GOP2_NTTS | &h00040000 | Variation of NTTS
GOP2_SEQLOK | &h00080000 | Sequential file locking (UNIX)
GOP2_LONGDIR | &h00100000 | Use long (10.3) directory format (DIR/L)
GOP2_ISAMDISAM | &h00200000 | Emulate ISAM w/ DISAM
GOP2_MANIFEST | &h00400000 | Look for mft files
GOP2_3DTAB | &h00800000 | Allow TAB(X,Y,Z)
GOP2_AUTOX_RAN | &h01000000 | Auto-expand "random" (aka "contiguous") data files, record by record as needed
GOP2_RCDIMX | &h02000000 | COMPIL /RC allows DIMX
GOP2_TCPNODELAY | &h04000000 | (ATS only) Set TCP "No Delay" option (i.e. disable the "Nagle algorithm")
Definition file: ashell.def

Hex-Decimal Values


MIAMEX 60: Set OPTIONS flags

xcall MIAMEX, MX_SETOPTIONS, options1 {,options2}

MX_SETPOPTIONS allows you to set OPTIONS flags on the fly. options1 and options2 (Num) may be set to any combination of the flags from the tables shown for MIAMEX 59. Note that these options are the same ones that are defined in the A-Shell initialization file, miame.ini; see the the OPTIONS parameter in miame.ini for the full listing.

Note that when setting options2 values, you cannot avoid also setting the options1 values. So you should always first retrieve the current options with MIAMEX 59, then set or clear the desired flags in the options1 and options2 variables, then use them to update the options in MIAMEX,60. The most recent options1/options2 flags are defined in ashell.def as GOP_xxx and GOP2_xxx.

Example

To set the GOP2_RUNDIR flag and clear the GOP_ABSLOOKUP flag (and then restore the original settings), use code similar to the following:

MAP1 options1,b,4

MAP1 options2,b,4

MAP1 save'options1,b,4

MAP1 save'options2,b,4

xcall MIAMEX, MX_GETOPTIONS, options1, options2 ! retrieve current options

save'options1 = options1 ! save original settings for later restore

save options2 = options2

! NOTE: when setting/clearing flags, use logical operators and/or/not rather

! than +/-; otherwise be careful not to add a flag that is already set

! or subtract one that is already clear!!

options1 = options1 and not GOP_ABSLOOKUP ! clear GOP_ABSLOOKUP flag

options2 = options2 or GOP2_RUNDIR ! set GOP2_RUNDIR flag

xcall MIAMEX, MX_SETOPTIONS, options1, options2 ! update options

! Later, to restore the original options:

xcall MIAMEX, MX_SETOPTIONS, save'options1, save'options2


MIAMEX 61: Get TRACE flags

Updated October 2016; see History

xcall MIAMEX, MX_GETTRACE, trflags

MX_GETTRACE retrieves the current set of trace options. trflags (F,6) will be set to indicate the current trace options from the following table. When specifying trace operations in miame.ini, use the symbol name with the TROP_ prefix. All log operations are written to ashlog.log, and the traces which go to the ashlog file will also go to the Debug Message Window if it is open. See Event Tracing for a detailed description of tracing functionality.

Symbol | Value | Notes
TROP_AMSORT | &h00000001 | Display sorting trace dialog
TROP_SYSERR | &h00000002 | Display system error dialog
TROP_SQL | &h00000004 | SQL tracing
TROP_LP | &h00000008 | Line printer tracing display
TROP_SIGNAL | &h00000010 | Display received signals
TROP_SIGHUP | &h00000020 | Log hang-ups
TROP_LOCKS | &h00000040 | Display lock trace
TROP_LOG | &h00000080 | Log various details
TROP_JOBS | &h00000100 | Log job info
TROP_QOPEN | &h00000200 | Log qflock opening
TROP_GDIPRT | &h00000400 | Display GDI print directives
TROP_FOPENS | &h00000800 | Log file opens
TROP_XCALL | &h00001000 | Log XCALLs
TROP_AMOS | &h00002000 | Log xcall AMOS operations
TROP_DEBUG | &h00004000 | Log maximum details
TROP_INOUT | &h00008000 | Log ins & outs
TROP_BASERR | &h00010000 | Log BASIC errors
TROP_ISAM | &h00020000 | Log ISAM operations
TROP_USRMEM | &h00040000 | Log user memory operations
TROP_MALLOC | &h00080000 | Log memory allocations
TROP_RW | &h00100000 | Log reads and writes
TROP_SOCKS | &h00200000 | Log socket operations
TROP_XLOCKS | &h00400000 | Log XLOCK calls
TROP_XDEBUG | &h00800000 | Combine with other flags to increase detail
TROP_PERF | &h01000000 | Log performance for certain operations
TROP_GUI | &h02000000 | Log internal GUI operations
TROP_EFS | &h04000000 | Log Encrypted File System (EFS) operations
TROP_ATE | &h08000000 | Log ATE commands
TROP_KBD | &h10000000 | Log keyboard data and operations
TROP_XTREE | &h20000000 | Log XTREE operations
TROP_JOBLCK | &h010000000 | Causes all unresolved lock/unlock operations on the jobtbl.sys file to be traced in the file jobtbl.lck. Note that the bit TROP_JOBLCK is beyond the 32 bit range of the typical 32 bit flags word, so you need to use B5, B6, I6, or F6/F8 to retrieve or set this bit.
Definition file: ashell.def

Hex-Decimal Values

History

2016 September, A-Shell 6.3.1526: Add TROP_JOBLCK.


MIAMEX 62: Set TRACE flags

xcall MIAMEX, MX_SETTRACE, trflags

MX_SETTRACE allows you to set tracing options on the fly. trflags (Num) may be set to any combination of the tracing flags in the table shown under MIAMEX 61 above. See Event Tracing for a detailed description of tracing functionality.

Tracing flags may also be set with the TRACE statement in the miame.ini or with the SET TRACE command; see those discussion for more details about these options.

Note that all of the traces which go to the ashlog file will also go to the Debug Message Window if it is open, and, conversely, you can activate any of the traces from Debug Message Window by right-clicking on it and picking Properties.


MIAMEX 63: Load PFK file

xcall MIAMEX, MX_SETPFK, pfkspec {,status)

MX_SETPFK loads a private (PFK-style) function key translation module into memory. Unlike the IFX and VUX translation tables, which are named after the terminal driver and loaded by default, a PFK-style translation table may have any name (with a PFK extension). When loaded, such a translation table will override any existing translations in the IFX file. Thus, they are handy for loading translations that are specific to a particular program or perhaps even a particular user.

pfkspec (Num) must contain the file specification of a translation table created by FIXTRN which has a PFK extension (e.g. "MYDIR:ABCDE.PFK").

status (Num) will be set to 0 on success, or 1 if the file was not found

Use FIXTRN <name>.PFK to create a PFK style translation table. You can also use LOAD <name>.PFK to load it into memory, and DEL to delete it. To delete it within a program, use MIAMEX 109: Delete module from memory.


MIAMEX 64: Display loaded PFK filename

xcall MIAMEX, MX_GETPFK, pfkspec

MX_GETPFK returns the name of the currently loaded PFK translation file, if any. pfkspec (string variable) will be set to the filespec of the current PFK file.


MIAMEX 65: Manage screen picture

xcall MIAMEX, MX_SCRNPIC, flags

MX_SCRNPIC invokes the screen picture routine to print or capture a picture of the current screen. This is the same routine that is called when you hit Ctrl+P in most input fields, except that here you have the ability to eliminate the pop-up dialog. flags (Num) may be any combination of the following:

Symbol | Value | Meaning
SPICF_APPEND | &h0001 | Append screen picture to current picture file, if any. (Otherwise overwrite it.)
SPICF_SPOOL | &h0002 | Print the picture file to the default screen picture printer; else just create the print file (in <jobnam>.BUF).
SPICF_DIALOG | &h0004 | Display the screen picture dialog, otherwise just do the operation silently.
SPICF_DELETE | &h0008 | Delete the picture file after printing.
SPICF_DLGOPT | &h0010 | Same as option 4 (display dialog) except that it may be overridden
SPICF_STRIP | &h0040 | Strips trailing blanks from each line of the output file
SPICF_FINAL | &h0080 | Adds "FINAL" to header
SPICF_GUICSV | &h0100 | Dump GUI Control Table
Definition file: ashell.def

The default screen picture printer may be set via the PRINTER=p1,p2{,NODLG} statement in the miame.ini file. The first printer(p1), is the default printer for other print operations, and the second printer, if specified (p2) is the default screen picture printer. If the third parameter is specified as "NODLG", then screen pictures that are requested via the Ctrl+P command will print without displaying the dialog.

Subtopics

Dump GUI Control Table


Dump GUI Control Table

This option dumps the current GUI control table to <jobnam>.CSV. The intent is to make it possible for developers who are using GUI-enhanced text (e.g. TPRINT, DPRINT, INFLD) to extract the information about the resulting text and edit controls and combine it with the text-based screen dump information to create an "enhanced text" screen picture. The details of how to do that have been left to the individual developer. The layout of the CSV data is similar to that of the "Dump Control Info to Spreadsheet" function, but simplified and improved somewhat by adding the explicit font information. The columns headers should help identify the data.


MIAMEX 66: Rebuild queue

xcall MIAMEX, MX_QRBLD

MX_QRBLD forces the qflock.sys file to be rebuilt. This will be done automatically if any broken links are detected, so the possibility of invoking it manually is of only academic interest.


MIAMEX 67: Lock queue

xcall MIAMEX, MX_QLOCK

MX_QLOCK locks the qflock.sys file. It should be called before trying to read the qflock.sys file, and should then be followed by MIAMEX 68: Unlock queue to unlock it.


MIAMEX 68: Unlock queue

xcall MIAMEX, MX_QUNLOK

MX_QUNLOK removes the lock on the qflock.sys file which was placed by a prior call to MIAMEX 67: Lock queue.


MIAMEX 69: Get UMASK

xcall MIAMEX, MX_GETUMSK, umask

(UNIX only) MX_GETUMSK retrieves the current UMASK setting. umask (Num) will return with the current value of the UMASK, treating it as if it were a decimal number.

For example, if the UMASK is 111 (which is actually an octal pattern), the returned umask value will be 111 (decimal).


MIAMEX 70: Set UMASK

xcall MIAMEX, MX_SETUMSK, umask

(UNIX only) MX_SETUMSK establishes a new UMASK setting.

umask (Num) should be set to the 3-digit decimal number, which if interpreted as octal, represents the desired UMASK setting. For example, to set the UMASK to 117, simply set umask=117. (In other words, you can ignore the fact that the UMASK is actually an octal representation of a bit pattern.)

A-Shell’s default UMASK is 111. If you set umask=000, A-Shell will instead use the mask set by the shell. Otherwise it will use the specified mask.

Note that the bits in the umask clear the corresponding bits in the file creation mask, which starts at 666 (rw-rw-rw-). So setting UMASK=111 will result in no change to the rw-rw-rw- mask. But UMASK=137 would result in rw-r---- (rw by the file owner, read only by members of the group, otherwise no access).

You may also set the UMASK in the miame.ini file, using UMASK=xxx.

Change the "default parameter" (last parameter) to match the new default'msg$ and the text to say:


MIAMEX 72: Print msg from msg file

xcall MIAMEX, MX_LITMSG, cat, msgno {, row, col, var, msgfile, arg, default'msg}

MX_LITMSG is mainly used within LIT utilities to display language-independent messages, although you can add use it to reference your own (properly formatted) message files as well. A "properly formatted" message file consists of lines in the following format:

<cat>,<msgno>,<message>{,<arg>}

<cat>,<msgno>,<message>{,<arg>}

etc

<cat> and <msgno> are typically formatted as three digit numbers, as in the example below. Any message may optionally be followed by a comma a numeric value which can optionally be returned to the calling program for whatever purpose. Comments are typically inserted by using <cat> and/or <msgno> values of 000. The lines of the file must be sorted, first by <cat> and then by <msgno>.

When a message file is accessed, it is loaded into user memory (for efficiency in handling subsequent accesses). When testing/updating the message file, remember to use DEL * to clear the user memory in order to get a fresh copy of the message file.

Parameters

cat (Num)

is the message category number (corresponding to <cat> in the example above). In the case of the LITMSG.xxx files, each LIT utility would have its own cat value, as shown in the following table.

Symbol | Value | Notes
MSG_CMDLIN | 0 | Misc CMDLIN messages
MSG_ABOUT | 1 | ABOUT.LIT messages
MSG_TELSER | 2 | TELSER.LIT messages
MSG_SEND | 3 | SEND.LIT messages
MSG_FORCE | 4 | FORCE.LIT messages
See definition file msgtbl.def for complete listing

msgno (Num)

is the message number within the cat category (corresponding to <msgno> in the example).

row, col (Num)

may be optionally specified to have the message displayed at the given row and column position. If either is zero, or they are omitted, then the message will be displayed at the current cursor position. If row is negative, then the message is not displayed but instead only returned in the var parameter.

var (String)

will return the text of the message if specified. The maximum supported line length for message files was 100 in A-Shell 5.0; it was increased to 256 in A-Shell 5.1.1106.

msgfile (String)

may optionally give the complete filespec of the message file. If the extension is missing, it will be set to match the current language (as defined in the LDF or language definition file specified in the LANGUAGE statement of the miame.ini, e.g. USA, SPA, FRE, etc.). If the parameter is blank or omitted, the default is "DSK0:LITMSG[1,4]" (with the extension being supplied as just described).

arg (Num)

if specified, will return the optional <arg> field of the current message, if any.

default'msg (String)

specifies the default message text to be used if the message is not located in the message (or the message file does not exist). Often, for maximum program readability, this parameter is specified as a literal string to make it obvious what the expected text of the message is. See the example below.

Example

Here is an excerpt from the LITMSG.USA file:

000,000,#

000,000,# A-Shell LIT command message table

000,000,# Language: English (US Only)

000,000,#

000,000,# Following 000,### messages are generic lit/cmdlin messages

000,000,# 001,### messages are from about.lit

000,000,# 002,### message are from telset.lit, etc.

000,001,?Exceeded maximum number of devices

000,002,?Cannot read

000,003,greater than

000,004,^ Specification error

000,005,?Device not found or mounted

000,006,file

000,007,disk block

000,008,Total of

000,009,%No files transferred

000,010,transferred

000,011,%No files deleted

000,012,deleted

001,000,# ABOUT.LIT messages...

001,001,Serial #

001,002,Licensed to:

001,003,Nodes Licensed:

001,004,Nodes in Use:

001,005,Jobs in Use:

xcall MIAMEX, MX_LITMSG, 1, 2, -1, -1, msg$, msgfil$, 0, "License Issued to"

The above call, assuming that msgfil$ was blank or set to "SYS:LITMSG" and the current language extension was "USA", and the above file was stored as SYS:LITMSG.USA, would return msg$ = "Licensed to". If the file was not found, then it would return "License Issued to" (because of the default'msg$ parameter).


MIAMEX 73: Read job control block

xcall MIAMEX, MX_READJCB, jobno, buffer {,lokflg}

XMX_READJDB reads a job control block or record from JOBTBL.SYS.

Parameters

jobno (Num)

the job number of the block to read. (This is equivalent to the record number, starting at 1 for the first job.) jobno 0 refers to the control record, which should not be accessed.

buffer

the record buffer to receive the data. It should be mapped per the JCB'REC map statement in JOBTBL.MAP (see SOSLIB).

The jcb’jobtyp field values are defined by the JOBTYP symbols in SOSLIB:JOBTBL.DEF .

The jcb’jobsts field values are defined by the JCBSTS symbols in SOSLIB:JOBTBL.DEF .

lokflg (Num)

may optionally be set to 1 to lock the record prior to reading it (leaving it locked thereafter). To unlock it you would then need to write the record back, using Function 74, and also specifying the same lokflg=1.

To scan all of the job table records, start at JOBNO=1 and keep incrementing it, skipping records with JCB'JOBTYP = JOBTYP'FREE, and quitting when you hit a record with JCB'JOBTYP = JOBTYP'EOF.


MIAMEX 74: Write job control block

xcall MIAMEX, MX_WRITEJCB, jobno, buffer {,lokflg}

MX_WRITEJCB is identical to the previous one (function 73), except that it writes a jobtbl record instead of reading it. Needless to say, it should used with extreme caution, since writing invalid information to JOBTBL.SYS could cause undesirable results.

The parameters are the same as for function 73.


MIAMEX 75: Get system time

Updated Oct 2016; see History

xcall MIAMEX, MX_GETTIME, secs {,usecs, utcoffset}

MX_GETTIME returns the number of seconds, and optionally microseconds, since 00:00:00 January 1, 1970, Coordinated Universal Time (aka the "Epoch").

Parameters

secs (Num)

will receives the number of seconds elapsed since the "Epoch". Since as of 2003 this number is well over 1 billion seconds, you would be well advised to map secs as a 4 or 5 byte binary or a floating point.

usecs (Num)

will be set to -1 if the feature is not supported (e.g. AIX, SCO) or else the number of microseconds to add to SECS. Note that under Windows, the actual resolution is only milliseconds, so USECS will always be a multiple of 1000. The microseconds value is probably not useful in itself but could be useful for measuring the amount of time that a very short operation takes (by calling MX_GETTIME twice, once before and once after). The MIAMEX.BP sample program in [908,30] has been updated to do just that, showing the time to execute a FOR/NEXT loop of 10000 iterations.

utcoffset (signed Num) [out]

Returns offset in seconds between local time and UTC (Universal Coordinated Time, aka Greenwich Mean Time). Offset will be negative for timezones West of Greenwich. A value of -1 indicates an error. Verions of A-Shell prior to 6.3.1518 will ignore the parameter; so unless you check the version, you should probably set your utcoffset value to -2 before calling the routine so that you can detect if it worked.

If you are using this function to measure an interval, keep in mind the possibility that the system clock might get updated during that interval, rendering your results meaningless.

The TIME system variable in BASIC returns the number of seconds since midnight.

See Also

TIMES.SBR for a better way to measure precise intervals.

MX_FTFORMAT.SBR to format the time.

The TIME system variable, which returns the number of seconds since midnight.

History

2016 July, A-Shell 6.3.1518: Add utcoffset parameter.


MIAMEX 76: Start telnet server

xcall MIAMEX, MX_TELSER, port, status {,wait}

(Windows only) MX_TELSER allows you to turn your current A-Shell/Windows client into a telnet server for a single remote client. Your session will continue to run normally until a telnet client connects; at that point, your window will be hidden and all terminal I/O redirected to the remote telnet client.

Beginning with A-Shell 1176 of March 2010, passing 0 for the port value now closes/releases any socket resources opened by a prior MX_TELSER call. This allows the operation to be cleaned up and restarted. Also, when the client disconnects, the server job reliably receives error 250. (Previously it may have only gotten a Ctrl+C signal.)

Parameters

port (Num)

specifies the port number to accept the incoming connection request on.

status (F,6)

returns a code indicating the success of the operation, from the following table:

Value | Meaning
0 | Success
-1 | Unable to load Winsock library
-2 | Winsock 1.1+ not present
-3 | Unable to create listening socket
-4 | User abort (Ctrl+C while waiting for connection)

Wait (Num)

may be used to specify options (combine zero or more from the following table):

Value | Meaning
1 | Minimize window immediately and wait for connection before returning from subroutine. (Otherwise it returns immediately with the wait operation waiting in background for the connection.)
2 | Launch a new instance to wait for a subsequent connection upon accepting the first connection
4 | Make waiting window totally invisible

You can restore visibility to an invisible window waiting for a connection by using SEND.LIT or SEND.SBR to send it a message consisting of just an exclamation point (!).

History

2010 March, A-Shell 5.1.1176: Minimize window immediately and wait for connection before returning from subroutine. (Otherwise it returns immediately with the wait operation waiting in background for the connection.)


MIAMEX 77: Show window

xcall MIAMEX, MX_SHOWWINDOW, flags

(Windows only) MX_SHOWWINDOW redisplays the A-Shell window according to the specified option.

It is identical to AUI_WINDOW, which see for more information.


MIAMEX 78: Get global DO params

xcall MIAMEX, MX_GETGDO, status, g0 {,g1, g2, ... , g9}

MX_GETGDO retrieves the currently set global DO parameters. These are parameters that may be set within a program and then retrieved later and used as arguments in a DO file command line.

status (Num) returns 0 for success or –1 to indicate failure.

g0 through g9 (String) will receive the current values of the up to 10 global DO file parameters.

For more information on this topic, see Global DO File Parameters.

History

2009 September, A-Shell 5.1.1159: Routine modified to support returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized.


MIAMEX 79: Set global DO params

xcall MIAMEX, MX_SETGDO, status, g0 {,g1, g2, g3, g4, g5, g6, g7, g8, g9}

MX_SETGDO may be used to set up to 10 global DO parameters. These are parameters may be retrieved later using Function 78 or used as arguments on a DO file command line. The entire set of up to 10 DO file parameters is set at once, replacing any prior values. (Even if you specify only g0, the prior values of g1 through g9 will be set to null.)

status (Num) returns 0 for success or –1 to indicate failure.

go through g9 (String) will receive the current values of the up to 10 global DO file parameters.

For more information on this topic, see Global DO File Parameters.


MIAMEX 80: Get XCALL param info

xcall MIAMEX, MX_XCBINFOX, xcbadr, xcbcnt, xcbstructx

MX_XCBINFO is needed at the start of an SBX subroutine to retrieve information about the parameters which were passed to the subroutine. Because every subroutine needs this information, the XCALL.BSI file which is included by every subroutine includes a call to this function.

Parameters

xcbadr (Num)

must be set to the address of the parameter structure. This value is passed on the command line to the SBX routine.

xcbcnt (Num)

returns the number of parameters passed.

xcbstructx

is a structure containing information about the parameters, mapped as follows:

MAP1 XCBSTRUCTX

MAP2 XCBSTRUCT(20) ! up to 20 parameters

MAP3 XCB'PTYPE,b,2 ! 0=X, 2=S, 4=F, 6=B, +8=array)

MAP3 XCB'PSIZE,b,2 ! size of parameter

Refer to the documentation on writing subroutines for more information on this and related MIAMEX functions.


MIAMEX 81: Get/set params in SBX

xcall MIAMEX, MX_XCBDATAX, xcbadr, opcode, parmno, var

MX_XCBDATAX This function is needed to pass parameter data between a calling program and an external SBX routine.

Parameters

xcbadr (Num)

must be set to the address of the parameter structure. This value is passed on the command line to the SBX routine.

opcode (Num)

must be set to 0 to retrieve a parameter or 1 to pass it back. (For convenience, these values are mapped in the XCALL.BSI file as xcbget and xcbput, respectively.)

parmno (Num)

is the number of the parameter to receive or send (starting from 1).

var

is the actual variable to receive or send. It should be mapped in a way that is "reasonably compatible" with the actual type and size passed to the subroutine, although conversions and truncations will be applied automatically if necessary.

Refer to the documentation on writing subroutines for more information on this and related MIAMEX functions.

Note also that MX_XCBDATAX has been largely superseded by the A-Shell BASIC extensions XGETARGS, XGETARG, and XPUTARG.

History

2009 September, A-Shell 5.1.1159: Routine modified to support returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized.


MIAMEX 82: Exit SBX

xcall MIAMEX, MX_EXITSBX

MX_EXITSBX may be used to abort from an SBX subroutine directly to the dot prompt. This is necessary, since merely ending an SBX routine (with the END statement) will return to the calling program.

Refer to SBX Subroutines for more information on this and related MIAMEX functions.

See Also

• MX_EXIT


MIAMEX 83: Get FKEYWAIT time

xcall MIAMEX, MX_GETFKW, waitms

(UNIX only) MX_GETFKW retrieves the current FKEYWAIT (function key sequence completion wait) value for this terminal. waitms (Num) will receive the wait time, in milliseconds.


MIAMEX 84: Set FKEYWAIT time

xcall MIAMEX, MX_SETFKW, waitms

(UNIX only) MX_SETFKW sets the current FKEYWAIT (function key sequence completion wait) value for this terminal. waitms (Num) should be set to the desired wait time, in milliseconds.

For related information, See the discussion of FKEYWAIT in the documentation on miame.ini.


MIAMEX 85: Get or set window title

xcall MIAMEX, MX_TITLE, opcode, title

MX_TITLE gets or sets the title string which will be displayed in the Windows title bar or applicable terminal emulator.

MX_TITLE can also be performed using the SET.LIT TITLE option. Note that if $NC, $ND, $NP, or $PN is specified, the title display will be automatically updated whenever the corresponding information changes.

Parameters

opcode (Num)

should be set to 0 to retrieve the current title or 1 to set it.

title (String)

is the title string, either returned for opcode 0 or to set for opcode 1. title string may contain any of the following special macros:

Title | Meaning
$TS | Display title on top status line rather than on title bar of window. Valid only at the start of the TITLE string.
$NC | Name of current program or LIT command
$ND | Name of current disk device, e.g. "DSK0"
$NJ | Name of current job
$NP | Name of current program (RUN only)
$PA | Platform A-Shell compiled for, e.g. "Windows/32"
$PN | Current PPN, e.g. "[7,6]"
$VA | A-Shell version, e.g. "4.9(942)"
$VP | Version of current program


MIAMEX 86: Get error message

Updated August 2010

xcall MIAMEX, MX_ERRNOMSG, errno, message

MX_ERRNOSMG returns the operating system’s text message associated with the specified operating system error code (aka errno).

errno (Num)

is the error number for which you want the message. Note that many MIAMEX functions return operating system errors as negative numbers; these should be converted to absolute value before passing to this function. See History, below.

message (String)

returns the error message.

See ERRMSG or DERR for information relating to displaying the text corresponding to AlphaBASIC error numbers.

History

2010 August, A-Shell 5.1.1189: It is no longer necessary to convert negative system error numbers to positive before calling the routine. System error codes are all positive, but many subroutines return them as negatives to distinguish errors from other return values, leading many people to forget to use abs() to convert them to positive before using MX_ERRNOMSG.


MIAMEX 87: Disable stream buffering

xcall MIAMEX, MX_NOBUF, channel

(UNIX only) MX_NOBUF will disable the normal stream buffering on output streams (i.e. files open for output, and the console itself, aka stdout). By default UNIX systems buffer output streams to minimize the amount of system overhead involved in writing to them. For files, the buffer size may be several K. For the terminal or console, the buffering is generally limited to a single line.

In general this buffering is highly desirable, but there may be cases where it is annoying. One situation occurs when you are treating a physical port as a file, in order to control device connected to that port. In such a case, you may write out a small command to the file/port thinking that the device will see it immediately, but due to the buffering, it would not. A more typical situation involves writing some kind of status information (aka "life signs") to the screen during a lengthy process. Unless each update of the status information ended with a line terminator, it would simply be buffered, with the result that instead of seeing dots or percentage completion indicators steadily appear on the screen, there is a delay, and then it all appears at once. One (but not the only) solution to these problems would be to just disable buffering on the file channel in question.

channel (Num) is the file channel to disable buffering on. The file must be open for output (or append). For the terminal device, use file channel 0 (which is automatically opened for you at the start of each program).

An alternate approach is to force the buffer to be flushed on demand. For terminal devices, you can do this with Tab(-1,254), or simply by ending a PRINT statement without a semicolon. For file devices, you can use Function 88.

This buffering issue does not affect data files that are open for random I/O, ISAM, etc.


MIAMEX 88: Flush stream buffer

xcall MIAMEX, MX_FLUSHBUF, channel

(UNIX only) MX_FLUSHBUF is similar to the previous one but instead allows you to flush (or "unbuffer") the data, which has been buffered but not yet written to the specified file channel.

channel (Num) is the file channel to flush the buffer of. The file must be open for output (or append). For the terminal device, use file channel 0 (which is automatically opened for you at the start of each program).

See MIAMEX 87: Disable stream buffering for more information about buffering.


MIAMEX 89: Clone file channel

xcall MIAMEX, MX_FLSET, ch, status, recvar'adr {,stavar'adr}

MX_FLSET may be used within an SBX routine to link up with the control variables associated with a random or ISAM file that was opened in the calling program.

Parameters

ch

is the file channel (opened in the parent program) that you want to access.

status (F,6)

returns to a code reflecting the outcome of the operation:

Value | Meaning
-1 | Parameter error
0 | File CH was not open
1 | Success: file was opened for INDEXED access (ISAM 1.0)
2 | Success: file was opened for INDEXED’EXCLUSIVE
3 | Success: file was opened for RANDOM access
4 | Success: file was opened for INPUT
5 | Success: file was opened for OUTPUT or APPEND
6 | Success: file was opened for INDEXED access (ISAM-A)
7 | Success: file was opened for INDEXED’EXCLUSIVE (ISAM-A)

recvar’adr (X,6)

is an unformatted variable whose origin or location is the same as the F,6 variable which you want to use for specifying the record number for this file. We have to resort to this trick of mapping it as an X type so that we can get the true address of the variable, because otherwise floating point arguments to subroutines are pushed on the stack. So, for example, you should map it like this:

MAP1 RECNOX ! (specify this to MIAMEX, MX_FLSET)

MAP2 RECNO,F,6 ! (actual record number control var)

or

MAP1 RECNO,F,6 ! (actual record number control variable)

MAP1 RECNOX,X,6,@RECNO ! (specify this to MIAMEX, MX_FLSET)

In either case, specify the recnox variable in the MIAMEX call, but use the recno variable to set the record number within the file.

statvar’adr (X,6)

is only used in the case of an ISAM-A file, and is used to specify the ISAM status variable that will return the result of each ISAM-A operation. It must be mapped and specified to the subroutine using the same trick as for recvar’adr above.

Comments

Once you successfully execute the MX_FLSET operation, you can have full access to the RANDOM, ISAM, or ISAM-A file within the subroutine.

Refer to SBX Subroutines for more information on this and related MIAMEX functions.


MIAMEX 90: Get/set beveling options

xcall MIAMEX, MX_BEVEL, opcode, bevel, linedraw

(Windows only) MX_BEVEL allows you to query or set the beveling options, which are otherwise available on the Edit menu or via the SET BEVEL command.

See the Tab(-10,x) Function Listing for an equivalent Print Tab command (AG_BEVEL).

Parameters

opcode (Num)

should be set to 0 to query the current options or 1 to set them

bevel (Num)

indicates the bevel mode:

Value | Meaning
0 | Beveling off
1 | Beveling set to automatic
2 | Beveling set to program control. In this case, to turn beveling on within a program, you can use "? Tab(-10,BEVEL); str(FLAGS); chr(127)" where FLAGS are values that control beveling options, with the most useful choices being 0 (off), 255 (on, with no line drawing characters) or 15 (beveling, but use line drawing characters also).

linedraw (Num)

should be set to 0 for enabled, or 1 for disabled. (The recommendation is to disable line drawing when beveling is active so that lines will be represented entirely by the 3D raised objects.)


MIAMEX 91: Get/set background color

xcall MIAMEX, MX_SYSBCLR, opcode, sysbclr {,syswinc, systxtc}

(Windows and ATE) MX_SYSBCLR allows you to assign one of the background color numbers (0-15) to reference the default Windows color for dialog box backgrounds (typically gray). The idea would then be to use Tab(-3,BGCOLOR) to use that color as your background color. The advantage of tying this color number to the Windows system background color instead of just setting it to a specific color, is that then it will automatically change when the Windows desktop color scheme is changed. For example, if the user switches to a "Valentine’s Day" scheme, the cool gray Window backgrounds will all change to pinkish ones.

Parameters

opcode (Num)

may be specified as 0 to query the current system background color number, or 1 to set it.

sysbclr (Num)

will return the currently defined system background color number (for opcode 0), or establish it (for opcode 1).

syswinc (0-7)

applies to one of the background colors in the color palette

systxtc (0-7)

refers to one of the foreground colors.

You can also set this with SET TERM SYSBCOLOR n.


MIAMEX 92: Enable/disable PolyShell keys

xcall MIAMEX, MX_HOTKEY {,enable}

xcall MIAMEX, MX_HOTKEY, hotkey, swapkey

(UNIX only) MX_HOTKEY allows you to temporarily disable the PolyShell hot or swap keys, or reassign them. The typical motivation for temporarily disabling them is in situations where you are allowing an external process to control the screen (for example, an AutoLog communication session). In such a case, swapping jobs with PolyShell may not be advisable.

Parameters

enable (Num)

may be set to zero to disable the hot and swap keys, or 1 to re-enable them. (The default, if the parameter is omitted, is 0 to disable.)

hotkey (Num)

may specify the ASCII key value of the new PolyShell hot key (or 0 to disable it).

swapkey (Num)

may specify the ASCII key value of the new PolyShell swap key (or 0 to disable it).


MIAMEX 93: Get ABOUT info

Updated February 2017; see History

xcall MIAMEX, MX_ABOUT, prdname, version, serial, coname, key, licnodes, phynodes, lognodes, licoptions, expflags, reldate, expdate, inifile {,jobtbl'fspec, jobtbl'inode, jobtbl'cdate, jobtbl'ctime}

MX_ABOUT retrieves several pieces of information relating to the current license and environment. It is mainly used by ABOUT.LIT, but might be useful within in application to check for maintenance expiration, number of licensed users, etc. A quick look at the output of ABOUT.LIT will answer many questions about the parameter output.

Parameters

Parameter | Type | I/O | Description
prdname | (String) | [out] | will return the A-Shell platform-specific name, e.g. "A-Shell/Linux" or "A-Shell/Windows/32".
version | (String) | [out] | will return the A-Shell version string, e.g. "Ver 4.7(825)".
serial | (Num) | [out] | will return the serial number.
coname | (String) | [out] | will return the company name that the license was issued to.
key | (String) | [out] | will return the license key (aka PIC code).
licnodes | (Num) | [out] | will return the maximum number of nodes licensed.
phynodes | (Num) | [out] | will return the current number of physical nodes in use.
lognodes | (Num) | [out] | will return the current number of logical nodes in use. (The logical node count should count each job, whereas the physical count may be less if multiple jobs are identified as being connected with the same session or are running in background.)
licoptions | (String) | [out] | will return a string of descriptive tokens identifying license options, such as "COM-XCALL", "PolyShell", etc.
expflags | (Num) | [out] | Returns indication of the license status combined with a flag indicating whether there is a runtime (vs. maintenance) expiration. See EF_xxx flags in ashell.def, reproduced below.
reldate | (String) | [out] | will return the release date of the current executable (dd-mon-yyyy).
expdate | (String) | [out] | will return the maintenance or runtime expiration date of the license (dd-mon-yyyy).
inifile | (String) | [out] | will return the fully qualified native filespec of the miame.ini file.
jobtbl’fspec | (String) | [out] | will return the fully qualified native filespec of the jobtbl.sys file.
jobtbl’inode | (Num) | [out] | will return the inode of the jobtbl.sys file. (Applies to UNIX only; will be set to 0 under Windows.)
jobtbl’cdate | (String) | [out] | will return the creation date (or last status change date) of the jobtbl.sys file (dd-mmn-yy) format. Note that under UNIX, the "c date" will be updated by any change to the privileges or ownership of the file, so it may not reliably indicate the actual creation time.
jobtbl’ctime | (String) | [out] | will return the creation time (or last status change time) of the jobtbl.sys file (hh:mm) format.

EF_xxx Flags

Symbol | Value | Description
EF_NORMAL | 0 | license good
EF_DEMO | 1 | demo mode
EF_BADKEY | 2 | bad key
EF_BADCO | 3 | bad company
EF_BADOS | 6 | bad os
EF_EXPIRED | 7 | expired runtime
EF_EXPIRED_EXE | 8 | expired maint
EF_ATSD | 10 | ATSD not licensed
EF_BADMAC | 12 | MAC address not valid
EF_SERIAL | 13 | serial # out of range
EF_BADKEYFMT | 14 | bad key format
EF_BADKEYVER | 15 | bad key version
The following bit is independent of those above
EF_RUNTIME | &h020 | runtime expiration, else maint

History

2017 February, A-Shell 6.3.1544: Updated expflags. Previously, it returned only 0 (maintenance) or 1 (runtime), plus 16 to indicate expired.


MIAMEX 94: Get cursor position

xcall MIAMEX, MX_GETRC, row, col

MX_GETRC retrieves the current position of the cursor. row and col (Num) will return the current cursor row and column, respectively.


MIAMEX 95: Display open file dialog

Updated July 2013; see History

xcall MIAMEX, MX_GETOFD, path, filter, title, flags {,defext, fname, type}

(Windows/ATE only) MX_GETOFD displays the standard Windows open file or save file dialog. It can only take place on a GUI-enabled client, either ATE or A-Shell/Windows. Note that the routine can be called with just two parameters; see History.

Parameters

path (String, up to a maximum of 4096 bytes) [in/out]

On input, must contain the default filespec or the default directory, fully qualified, in AMOS or Windows notation. See Comments.

On return, it will contain the full filespec (in Windows notation) of the selected file(s). If more than one file was selected (see OFN_ALLOWMULTISELECT in flags), the individual filespecs will be separated by chr(10) characters, and all but the first filespec will be stripped down to just the file name and extension, since they will all be in the same directory.

filter (String) [in]

is a set of pairs of strings, concatenated all together using pipes ("|") for delimiters, determining which files will display in the dialog box. The first string in each pair is descriptive, and will display in the "Files of Type" area of the dialog box. The second string in each pair is a wildcard specification for that kind of file. If you have more than one wildcard spec for a particular descriptive name, then separate them with semicolons. For example:

FILTER="Data files|*.DAT|Text files|*.TXT; *.LST"

Note that the "Files of Type" control is actually a drop-down box and that "Data files" will show as the initial choice, and "Text Files" will be the next choice in the list. If you want them all appear together, then just specify one pair of strings, such as:

FILTER="Image Files (*.pcx, *.jpg, *.bmp)|*.pcx; *.jpg; *.bmp"

Also note: do not include any spaces on either side of the | delimiter characters lest they be confused with the pattern, causing a failure to match any files.

title (String) [in]

may be set to the desired title of the dialog box. The default is "Open". This is the main difference between the File Open and File Save versions of the dialog box. See type parameter.

flags (Num) [in/out]

May be set to any combination of the options shown below.

Note that since the parameter may be updated on return from the function (see OFN_EXTENSIONDIFFERENT and OFN_NOREADONLYRETURN), you'll have to use an actual variable for the flags parameter if you want to be so advised. Otherwise you can just specify an expression consisting of the literal flags, e.g. OFN_PATHMUSTEXIST+OFN_FILEMUSTEXIST.

Symbol | Value | Description
OFN_HIDEREADONLY | &h00000004 | Hides the read-only checkbox
OFN_NOCHANGEDIR | &h00000008 | This function is no longer supported (as of Windows NT4 / 2000 / XP).
OFN_NOVALIDATE | &h00000100 | Do not force filename entered to contain only valid characters.
OFN_ALLOWMULTISELECT | &h00000200 | Allow the selection of multiple files. (OFN_EXPLORER flag should be set along with this.) Successive names will appear, null delimited, in the returned PATH variable.
OFN_EXTENSIONDIFFERENT | &h00000400 | Set on return if the extension entered differs from defext
OFN_PATHMUSTEXIST | &h00000800 | Specified directory must exist
OFN_FILEMUSTEXIST | &h00001000 | Specified file must exist. (Implies that OFN_PATHMUSTEXIST)
OFN_CREATEPROMPT | &h00002000 | Prompt for permission to create the file if the file does not already exist
OFN_NOREADONLYRETURN | &h00008000 | Set on return if file not read-only, directory writeable
OFN_NONETWORKBUTTON | &h00020000 | Disables the network button
OFN_EXPLORER | &h00080000 | Forces the dialog box to be in the new Explorer-style. This is the default in most cases, except when OFN_ALLOWMULTISELECT is set.
OFN_DONTADDTORECENT | &h02000000 | (Win2000/XP) Do not add file to the user’s most recently used document list
Definition file: ashell.def

Hex-Decimal Values

defext (String) [in]

may specify the default file extension. Do not include the period. If specified and the user types a filename with no extension, this will be appended to the returned path and fname parameters.

fname (String) [out]

is an optional convenience that will return just the filename and extension, without the rest of the path, saving you from having to parse it out of the path string. Note, however, that it is not guaranteed to be in the directory you initially specified. Parameter is ignored if OFN_ALLOWMULTISELECT is set. Maximum length is approximately 256.

type (Num) [in]

If specified and set to 1, the main button will say "Save" rather than "Open". This and the title are the main differences between an Open dialog and a Save dialog.

Comments

Note that if the initial path or directory is in the form of a drive letter and colon with no trailing slash (e.g. "C:"), MX_GETOFD automatically appends "\" to avoid confusion. Such ambiguous specs are otherwise likely to be misinterpreted by A-Shell and/or Windows.

If there is an error in the format of the parameters, such that the dialog fails to display, A-Shell will open the debug message window and display a short message with the internal Windows error number; see descriptions in the following table.

Error Number | Error Type | Description
0x0001- 0x000C | System errors | These suggest low level problems in Windows (lack of resources, inability to lock memory, etc.
0x3001 | Subclass failure | Suggests lack of PC memory
0x3002 | Invalid filename | File spec in path parameter invalid
0x3003 | Buffer too small | Selected file name is too long to fit in the provided return buffer

See Also

• MX_BROWSEFOLDER

• MX_GETSHELLPATH

History

2016 March, A-Shell 6.2.1425: minimum number of parameters has been reduced from five to two, allowing you to call it with just xcall MIAMEX, MX_GETOFD, PATH$

2013 July, A-Shell 6.1.1355: filenames containing commas are now quoted; previously they were not, which almost certainly led to incorrect parsing of the response

2013 July: 2009 October, A-Shell 5.1.164: Append "\" when needed


MIAMEX 96: Shell execute

Updated January 2014; see History

xcall MIAMEX, MX_SHELLEX, status, objectspec , {action ,parms ,dir, showflags ,waitflag, clisvr, exitstatus}

(Windows or ATE only) MX_SHELLEX provides an interface to "Shell Execute," which is one of the two fundamental mechanisms for launching a new process under Windows. The other method is known as "Execute Windows Command Line" or "CreateProcess" or "Win Exec," and is used by HOSTEX.SBR and AG_WINEXEC.

Shell Execute is the method used by Windows itself when you click on a file or shortcut in Explorer, or even type a command line in the Start..Run dialog, and although it supports the ability to form command lines with parameters, it is most commonly used by specifying just an object (e.g. a file, URL, folder, etc.), and letting Windows decide which application is needed to perform the default (or specified) action on the object. Windows does this based on a table of file type associations in the Registry (which you can edit by means of the File Types dialog on the Explorer Tools...Folder Options menu).

See the Tab(-10,x) Function Listing for an equivalent Print Tab command (AG_SHLEXEC).

Parameters

Note that all parameters after objectspec are optional.

status (F,6)

will return one of the following:

Value | Meaning | Value | Meaning
0 | Success | 8 | Out of memory
-1 | Out of system resources | 11 | Bad format
-15 | ATE failure to respond | 26 | Sharing error
2 | File not found | 27 | File association incomplete
3 | Path not found | 31 | No association defined
5 | Access denied | 32 | DLL not found
 |  | 1223 | See Comments, below

objectspec

is the specification (Windows format) of the file/object to open or act on, or the URL to link to. For example, you might specify a XLS file, such as "C:\Windows\Temp\My Spreadsheet.XLS", in which case the presumed action would be to launch the spreadsheet program (e.g. Excel) to open the spreadsheet. For example, you might specify a URL, such as "http://www.microsabio.com" in which case the presumed action would be launch the browser and link to the specified web site or HTML document.

Embedded environment variables (using the %env% notation, e.g. %temp%\test.doc) are supported.

You may also specify an executable, such as "%systemroot%\system32\mspaint.exe". (Use the parms parameter for the remainder of the arguments and switches to be passed to the executable.)

A special macro, "$ASHELL" can also be used to launch another session of A-Shell using the same executable and ini file as the current session. You can combine this with additional switches in the parms parameter to customize the action of the new session.

Note that in the ATE environment, the objectspec will be evaluated by (and relative to) the ATE client, not the server. If the object originates on the server, you'll have to first transfer it to the ATE client before using Shell Execute on it.

action (String)

may specify an action: open, edit, print, find, explore or runas. If omitted, the default action for that file association is performed. Typically the default action is "open", which just opens the document. Such actions are defined with the file association in the Explorer Tools...Folder Options...File Types dialog.

Note that the "runas" action invokes the request for elevation dialog. For GUI commands, this is automatic, but for console commands (e.g. regsvr32), it is not, and this would be the only way to get it to prompt the user for the elevation needed. (Otherwise the operation would just fail.) Unfortunately there is no way to programmatically supply the administrator password. If you need something like that, you may want to check out a Microsoft-sponsored utility called "PsExec".

parms (String)

is an optional list of parameters. Typically parms is used when objectspec contains the name of an executable (e.g. "%miame%\bin\ashw32.exe"), in which combination of objectspec and parms may effectively form a complete command line. parms has a maximum size of 1024 characters.

dir (String)

is an optional starting directory. This can generally be omitted or specified as "".

showcmd

is an optional numeric parameter specifying the way to show the window launched by the program associated with the object and action. If omitted, the default window size will be used. Note that if you do specify the parameter, a value of zero means to make the window invisible. The values are the same as for MIAMEX 77: Show window. Note that this is only a suggestion to the target application. There is no way to force it to follow your suggestion if it insists otherwise.

waitflag

Value | Description
0 | No wait. Focus will most likely remain on launched app.
1 | Wait until launched app exits before returning.
2 | Don't wait, but try to get the focus back.
4 | Disables the normal 10 second time out waiting for the ShellExecute operation to complete.

Note that waiting (1) doesn't necessarily wait until the launched app exits. It only waits until the app "signals", which can mean different things for different applications. (It will wait for A-Shell).

Option 2 will now get the focus and keep getting it (if necessary) over a period of 4 seconds, in order to deal with difficult apps (like image viewers) that may take a couple of seconds to launch, after which they set the focus on themselves.

Ten seconds is normally more than enough time to determine whether the launch was successful or not, but there are some cases, most notably under Vista when the launch requires the user to confirm "elevation", that the server was otherwise timing out while ATE was still waiting for the ShellExecute to return. In such as case, an unreliable error status was often being returned, and then when the command finally did return, the normal response code was ending up in the keyboard buffer, possibly confusing the application. Specifying the +4 flag should not have any effect on older versions of A-Shell or under non-ATE situations.

Note that wait is independent of the existing waitflag option +1, which suspends ATE until the launched application completes. +4 only waits until the program is launched, not until it is closed.

clisvr (String, 1) [in]

may be set to "S" (for server), or "L" (for local, which is the same as server in this context); anything else is treated as meaning "client". The option only has significance in the ATSD environment where the possibility exists of performing the function relative to the ATSD server or the client. In all other cases, the parameter is ignored and the operation is performed relative to the client, or returns an empty string if an applicable client is not present.

Beginning with A-Shell 1373 of January 2014, local mode (clisvr = "S" or "L") now supports the waitflag options and the exitstatus parameter. Previously, these only worked in the normal/default (client) mode where the operation is forwarded to ATE via the AG_SHLEXEC command. Also, both modes now support shell commands that require COM initialization.

exitstatus (signed Num) [out]

returns the exit status of the launched process

Comments

This method is generally preferred over the "Execute Windows Command Line" method (e.g. executing an explicit command line with an explicit location and name for the executable) since it eliminates three of the biggest problems normally associated with launching local applications: knowing the actual name of the executable, the command line syntax, and directory where it is located. All of these are taken care of by the association definition.

Under Vista, there is an added bonus in that "Shell Execute" will automatically request "elevation" if necessary in order to perform the specified action, whereas "CreateProcesss" will simply fail if the user doesn't have the necessary privileges.

Aside from a -15 return code for timeout, applications should be aware of return code 1223, which indicates that the user was given some kind of prompt to enable or accept the launch of the program (such as with Vista 'elevation'), and the user chose to cancel rather than allow the launch.

In addition to an individual parameters length of 1024 bytes, there is an overall limit of 4096 bytes for all of the arguments combined. If the limit is exceeded, the routine will return with status 8 (out of memory).

Example

See this discussion on the A-Shell Forum.

History

2012 Janary, A-Shell 6.0.173: Add support for waitflag and exitstatus to clisvr.

2014 January, A-Shell 6.1.1372: Local mode (clisvr = "S" or "L") now supports the waitflag options and the exitstatus parameter. Previously, these only worked in the normal/default (client) mode where the operation is forwarded to ATE via the AG_SHLEXEC command. Also, both modes now support shell commands that require COM initialization.

2012 July, A-Shell 6.0.1254: Add exitstatus parameter.

2011 July, A-Shell 5.1.1226: Add clisvr parameter.

2011 January, A-Shell 5.1.1202: MX_SHELLEX refinement: remove 260 character limit on objectspec, and increase the 500 character limit on the parms argument to 1024. There remains an overall limit of 4096 bytes for all of the arguments combined. If the limit is exceeded, the routine will return with status 8 (out of memory).


MIAMEX 97: Make directory

xcall MIAMEX, MX_MKDIR, dirspec, status, {remoteflag}

(Windows only) MX_MKDIR provides a native Windows equivalent to MX_MKPATH to create a directory.

Parameters

Parameter | Type | I/O | Description
dirspec | String | in | the directory name to create. This should be in native file format, but (as of build 960) may include embedded environment variables (e.g. %MIAME%\NEWDIR).
status | Num | out | will return 0 for success, else a Windows system error number (183 for already-exists). -15 indicates ATE timeout. See MX_ERRNOMSG for translating system error codes to messages.
remoteflag | String, 1 | in | may be optionally specified to clarify, in ATE environments, whether the directory is to be created on the server ("L" for local or "S" for server) or on the ATE client ("R" for remote or "C" for client). Specifying "L" on a UNIX machine is an error (returns status = -1) because this MIAMEX function only creates Windows directories.

Comments

MX_MKDIR will be invoked automatically if MX_MKPATH is requested under Windows. But your application still needs to be aware of whether it is running under Windows or UNIX because the directory naming syntax is typically different. Note that to create a directory on the ATE client, you must use MX_MKDIR, since MX_MKPATH does not have the remoteflag option.

There is no harm in attempting to create a directory that already exists; in fact, this may be easier than trying to first determine whether it exists. If the directory already existed, the return value will be 183, which should probably be handled as a non-error.

In general this function will not succeed if the parent directory doesn't already exist.

History

2011 July, A-Shell 5.1.1226: The remoteflag parameter can now also accept "C" (for client) as an alias to "R" (remote) and "S" (server) as an alias to "L" (local). This is intended to reduce the chance of accidentally using the Client/Server notation in place of the Remote/Local notation. Experience has shown that some people are confused over which is the "Remote" and which is the "Local", which is why we've moved towards the Client/Server notation, which seems less confusing.


MIAMEX 99: Get registry string

xcall MIAMEX, MX_GETREG, key, subkey, name, value

(Windows/ATE only) MX_GETREG allows you to retrieve values from the system Registry. Also see MIAMEX 138: Registry operations, which offers a more extensive set of registry access capabilities.

Parameters

key (Num or B,4)

must be one of the following specified values:

Symbol | Value
HKEY_CLASSES_ROOT | &h80000000
HKEY_CURRENT_USER | &h80000001
HKEY_LOCAL_MACHINE | &h80000002
HKEY_USERS | &h80000003
HKEY_PERFORMANCE_DATA | &h80000004
HKEY_DYN_DATA | &h80000005
Definition file: ashell.def

Hex-Decimal Values

subkey (String)

is the sub key within the specified key section of the Registry. This may have multiple parts, e.g. "Software\Microsoft\MediaPlayer\Player\RecentFileList".

name (String)

is the name of the particular value to look for within the specified subkey. You may specify a blank string to get the default value. (Many subkeys have only a default value.) For the subkey example given above, the likely names will be "File0", "File1", etc.

value (type corresponding to registry data type)

will return the value of the specified item. The parameter type specified must match the type of the registry item: use B,4 for REG_DWORD items, string for REG_SZ and REG_EXPAND_SZ items, unformatted for other types. Dynamic strings (S,0) are allowed, but the internal maximum size is 1024; data items larger than 1024 bytes will come back as null strings. Environment variables, found in registry items of type REG_EXPAND_SZ, will be expanded. See History for details.

Comments

In the case of ATE (with one of the GUI-enabled "G" emulations), the request will be automatically forwarded to the ATE client, even when the server is Windows (i.e. ATSD). To query the server-side registry, use MX_REGISTRY instead.

History

2012 April, A-Shell 6.0.1248.3: Add automatic expansion of environment variables in REG_EXPAND_SZ items. Increase maximum supported string length from 256 to 1024.

2006 April, A-Shell 4.9.963: This function is now supported in ATE.


MIAMEX 100: Play sound

xcall MIAMEX, MX_PLAYSOUND, fspec {status, flags}

(Windows only) MX_PLAYSOUND allows you to play a WAV (sound) file directly. You could also use MX_ERRNOMSG to launch the media player to play a specified sound file, but this method avoids the complication of another application and gives you more control. .

Parameters

fspec

must contain the file specification (AMOS or Windows syntax) of the WAV file to play (or the "event label" – see flags value &h10000 below).

status (Num) optional

returns 0 (FALSE) if it failed to play, else non-zero (TRUE) for success.

flags (Num) optional

may be used to specify flags used by the Windows PlaySound() function:

Value | Meaning
&h00001 | Return immediately (while sound still playing). To terminate the playback later, call this function again with fspec="".
&h00008 | Play sound continuously. Must be used with flag 1 (1+8=9). To terminate the sound later, call with fspec="".
&h00010 | Do not stop a currently playing sound. (Otherwise a request to play a sound file will terminate any sound file currently playing; this is why setting fspec to null terminates the current sound file.)
&h02000 | Do not wait if the sound driver is busy.
&h10000 | FSPEC is not interpreted as a file specification but as an "event label" defined in the registry. See HKEY_USERS\.Default \AppEvents \EventLabels. These are the "sound events" that you can associate sound files with using the Control Panel Sound applet (only the registry names may differ from the names displayed in that applet). Typical examples are "SystemAsterisk" and "NmainMouseClick".

Hex-Decimal Values


MIAMEX 101: Get swap wait time

xcall MIAMEX, MX_GETSW, waitms

(UNIX only) MX_GETSW retrieves the current swap wait time in milliseconds. See MIAMEX 102 for more details).

waitms (Num) will be returned with the current time in milliseconds, or zero to indicate that it is still set to the default (or undefined for the current terminal).


MIAMEX 102: Set swap wait time

xcall MIAMEX, MX_SETSW, waitms

(UNIX only) MX_SETSW allows you to change the swap key wait time for certain terminal drivers (normally set by the SWAPWAIT parameter of the miame.ini, or 1000 ms by default). Currently this only affects the wyse50 driver, and was implemented because the standard wait is a full 1 second, which is apparently necessary on some versions of the terminal but not on terminal emulators. The main downside of the extra wait occurs within PolyShell, where it delayed the repaint of the new screen when swapping sessions. To allow this to remain as flexible as possible, the default value of zero simply causes the terminal driver to use its normal wait time (which in the case of wyse50 is 1000 milliseconds or 1 second). To minimize the wait, set it to 1.

waitms (Num) should be set to the desired wait time in milliseconds, or zero to use the default.


MIAMEX 103: Get/set cmd line flags

xcall MIAMEX, MX_CLFLAGS, opcode, clflags

MX_CLFLAGS allows you to determine which command line switches were specified when A-Shell was launched, and to effectively set the flags that are associated with these switches.

Parameters

opcode (Num)

should be set to 0 to query the current command line flags, or 1 to set them.

clflags (Num)

will either return the current command line flags (if opcode is 0) or supply the new switch settings (if opcode is 1). The flags and corresponding switches are listed in the following table. (Omitted values have been reserved for internal use and are of no interest to applications.) Switches that make no sense to set at runtime (i.e. most of them) are marked "RO" for "read only".

Symbol | Value | Switch | Meaning
CLF_VER | &h00000001 | -v | Display version on A-Shell startup. (RO)
CLF_EXIT | &h00000002 | -e | Force A-Shell to exit when current command or command file is complete.
CLF_DEV | &h00000008 | -d | Display A-Shell console device name on startup. (RO)
CLF_INI | &h00000010 | -i | Specify miame.ini name.
CLF_NOHANG | &h00000100 | -h | Ignore hangup signal.
CLF_PSHELL | &h00000200 | -p | Running under PolyShell. (RO)
CLF_HANGDELAY | &h00000400 | -hd | Delay processing of hangup signal.
CLF_HANGPARENT | &h00000800 | -hp | Send hangup signal to parent on exit.
CLF_QUIET | &h00001000 | -q | Quiet mode. (RO)
CLF_SUBMIT | &h00002000 | -t | Simulate slave task mode. (RO)
CLF_SETTINGS | &h00004000 | -o | Specific windows settings file specified. (RO)
CLF_CHILD | &h00008000 | -2 | Child session. (RO)
CLF_NOPSH | &h00010000 | -1 | Disallow use of PolyShell job switching. (RO)
CLF_HIDE | &h00020000 | -z | Hide window. (RO)
CLF_SNAPSHOTS | &h00040000 | -ba | Append auto-snaphots to specified buffer. (RO)
CLF_MAXFOCUS | &h00080000 | -m | Force maximized window. (RO)
CLF_NOX | &h00100000 | -mx | Remove "X" and system menu. (RO)
CLF_CGI | &h00200000 | -cgi | CGI mode. (RO)
CLF_ATS | &h00800000 | -awts | ATS (A-Shell Telnet Server) mode. (RO)
CLF_HEI | &h01000000 | -hei | Generate error 250 immediately on hangup.
CLF_HETCKI | &h02000000 | -hetcki | Treat tcki like kbd wait after hangup
CLF_LITE | &h04000000 | -lite | AshLite mode. (RO)
CLF_MIN | &h10000000 | -min | Start minimized. (RO)
CLF_SYSTRAY | &h20000000 | -tray | Like –z but with icon in system tray. (RO)
CLF_ATE | &h40000000 | -ate or -atecfg | Used internally by TELNET and ATE to signify ATE mode.
CLF_NOMENU | &h80000000 | -nm | No menus (menu bar hidden).
Definition file: ashell.def

Hex-Decimal Values

Comments

Note that when setting the command line flags, you have to set them all at once. To set just one, first retrieve the current flags and then OR in the flag you want to set, and then use opcode 1 to set the entire collection of flags.

Refer to the documentation on the command line switches for more information about what these switches do.


MIAMEX 104: Get process ID

xcall MIAMEX, MX_GETPID, pid

MX_GETPID retrieves your current process ID number. A process ID (aka PID) is a positive integer which uniquely identifies a process. They are assigned by the operating system when the process is created, and recovered (for subsequent reuse) when the process terminates. PIDs are most useful in UNIX, where they are the most common way to identify or communicate with another process. They are less useful but still valid in the Windows environment.

pid (Num) will return your process ID. Note that these numbers can get quite large on large systems, so you should specify at least a B,3 (or a floating point).


MIAMEX 105: Get/set clipboard text

Updated and reviewed, October 2010

xcall MIAMEX, MX_CLIPBOARD, opcode, text {,status {,srow, scol, erow, ecol}}

MX_CLIPBOARD allows you to retrieve or set the text contents of the clipboard.

Parameters

opcode (Num) [in]

Value | Description
0 | Retrieve clipboard text contents
1 | Set clipboard text either from screen coordinates (if non-zero) or from text parameter
2 | Same as 0 but applies to ATE client
3 | Same as 1 but applies to ATE client
5 | Mark area specified by coordinates

Note that in non-ATE A-Shell/UNIX environments, opcode 0 and 1 will simulate clipboard operations by reading/writing to a file MEM0:<job>.CLP[1,1] if the file exists. If it does not exist, status will be set to -1 (same as if the Windows clipboard could not be opened).

text (String) [in/out]

will receive the clipboard text contents for opcode 0 and 2. For opcode 1 and 3, if you want to specify a string containing the text to copy to the clipboard, then put it in the text parameter and do not specify the srow, scol, erow, and ecol parameters (or set them to 0). Otherwise, if you want to copy a rectangular area of the current screen to the clipboard, then specify the coordinates in the last four parameters, in which case text will be ignored. The maximum effective size for text is about 3K.

status (F,6) [out] optional

Value | Description
0 | Success
-1 | Unable to open clipboard; locked?
-2 | Clipboard can be opened but not read, or there is no text available in the clipboard
-3 | Unable to lock memory
-4 | Invalid coordinates

srow,scol,erow,ecol (Num) [in]

Optional coordinates used with opcodes 1, 3 to specify the screen area to be copied to the clipboard. (Set them all to 0 in order to load the clipboard from the text parameter instead of the screen.) For opcode 5, they specify the screen area to be marked. Ignored for all other opcodes.

Notes

• In non-Windows, non-ATE environments (e.g. A-Shell/UNIX with a non-GUI client), opcodes 0 and 1 will simulation clipboard operations by reading/writing to a file MEM0:<job>.CLP[1,1] if the file exists. If it does not exist, status will be set to -1 (same as if the Windows clipboard could not be opened.)

• Other than the non-GUI A-Shell/UNIX case just mentioned, you can safely used opcodes 2 and 3 in place of 0 and 1 (i.e. add +2) without regard to whether the configuration involves ATE or some other Windows architecture (standalone, peer-to-peer, Terminal Server, etc.)

History

2010 November, A-Shell 5.1.1194: Limits removed on buffers controlling clipboard size. Buffers now auto-expand, making size of clipboard objects unlimited.

2009 September, A-Shell 5.1.1159: Routine modified to support returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized.

2009 February, A-Shell 5.1.1139: Prior to this release, the amount of text that could be copied to the clipboard was limited to about 3K. While this remains the case when copying from screen coordinates, or when running under ATE (opcodes 2 and 3), for opcodes 1 and 3 in local Windows mode (copying a string supplied by the application), the amount is now only limited by available Windows resources.


MIAMEX 106: Get OS Information

xcall MIAMEX, MX_OSVER, osname, {,osver, osrel, asplatform}

MX_OSVER retrieves information about the current host operating system or ATE, including its name, version, and release, plus the platform that this copy of A-Shell was compiled for. This can be useful in applications which wish to take advantage of features that are only available under certain platforms.

Parameters

osname (String, 10+) [out]

returns the name of the host operating system. For Windows, the possibilities are: "Win95", "Win98", "WinME", "WinNT 3.51", "WinNT 4.0", "Win2000", and "WinXP". (.NET Server currently is indistinguishable in this field from XP.) If the version information is not recognized, it will be reported as "Win X.Y" where X is the major version number and Y is the minor version number. For 64-bit versions, "/64" will be appended to the end. For UNIX/Linux, OSNAME will return the same as the "uname -s" command, e.g. "Linux," "SCO_SV," "AIX."

osver (String, 16+) [out]

returns the "version" of the operating system. For Windows, this might contain "OSR2" for Win95, "SE" for Win98, or "Service Pack 6" for NT. For UNIX/Linux, it will be what "uname -v" returns, e.g. a date string for Linux, or "5.0.5" (SC0), or "4" (AIX 4.3).

osrel (String, 16+) [out]

returns the "release" of the operating system. For Windows, this will be the build number. For UNIX/Linux, this will be what "uname -r" returns, e.g. "2.4.2-2" (Linux), "3.2" (SCO), "3" (AIX 4.3).

asplatform (String, 16+) [out]

returns the generic platform that this copy of A-Shell was compiled for. This is the same string that would be returned in the SYSDOS field in GETJTB.SBR. Examples are: "AIX", "SCO Unix", "Linux", "Windows/32".

ATE

Beginning with A-Shell 4.9.988 of May 2007, which is required on both the A-Shell and ATE ends, MX_OSVER supports returning information about the ATE client. The expanded syntax is:

xcall MIAMEX, MX_OSVER, osname {,osver, osrel, asplatform, ate'osname, ate'osver, ate'osrel, ate'platform}

The parameters ate'osname, ate'osver, ate'osrel, and ate'platform are equivalent to the osname, osver, osrel and asplatform parameters, except they return the information about the ATE client, if applicable. Otherwise they return null strings.

The MIAMEX.BP sample program in [908,30] of the EXLIB has been updated to illustrate the new fields.

Windows Names and Versions

The return values of the function are not as easy to to compare to a particular threshold as they might be—but then again, neither are the underlying OS versions themselves. Certain "recognized" versions of Windows will report a "friendly name" (e.g. "Win7") while unrecognized versions will just show "Win x.y" where x.y is the underlying major.minor version reported by Windows itself. Here is a table of those values:

Microsoft Public Name | Internal Version | OSname*
Windows 10 | 10.0 | **
Windows 8.1 | 6.3 | **
Windows Server 2012 R2 | 6.3 | WinSvr2012R2
Windows 8 | 6.2 | Win 6.2
Windows Server 2012 | 6.2 | Win 6.2
Windows 7 | 6.1 | Win7
Windows Server 2008 R2 | 6.1 | WinSvr2008R2
Windows Server 2008 | 6.0 | WinSvr2008
Windows Vista | 6.0 | WinVista
Windows Server 2003 R2 | 5.2 | Win 5.2
Windows Server 2003 | 5.2 | Win 5.2
Windows XP 64-Bit Edition | 5.2 | Win 5.2
Windows XP | 5.1 | Win 5.1
Windows 2000 | 5.0 | Win 5.0
Windows ME | 4.90 | Win 4.90
Windows 98 | 4.10 | Win 4.10
Windows 95 | 4.0 | Win 4.0
Windows NT | 4.0 | Win 4.0
Windows NT | 3.? | Win 3.51

* /64 is appended for 64-bit OS versions

** Prior to A-Shell 6.2.1420.5, Windows 8.1 and above would report itself as Windows 8.

History

2011 June, A-Shell 5.1.1221: The osname parameter will now be returned with "/64" appended to the end when running a 64 bit Windows OS.


MIAMEX 107: Scan user memory

xcall MIAMEX, MX_USRMAP, idx, name, size {,flags, ver}

MX_USRMAP is analogous to the AMOS SRCH monitor call, allowing you to locate modules in user memory. The maximum number of modules which can be loaded into user memory per job is 96.

This function is used by the MAP.LIT utility, which would be the normal way to see what modules you have loaded.

Background

Although an attempt has been made to provide some of the same user memory functionality as AMOS, the design here is considerably different. The most notable difference is that under AMOS, user memory is one contiguous chunk of physical memory, and the modules are stacked end to end, starting from the lowest available address. The BASIC runtime system then typically takes over the space from the top of the last loaded module to the top of the partition. Deleting a module under AMOS causes all subsequent modules to be shifted down, which might be disastrous to a program that was currently running (and counting on the prior physical location of some memory structures).

Under A-Shell, the user memory partition (defined by the MEMORY statement in the miame.ini, or by the use of MEMORY.LIT or the MX_MEMORY) is mainly used just for the BASIC runtime system’s work area. Any modules, including the RUN program itself, are loaded into dynamically allocated, non-contiguous, memory chunks. Thus the nominal partition size has no real effect on the number or size of the modules which can be loaded, and loading and deleting of individual modules has no effect on any other modules or currently running programs. A-Shell keeps track of the modules which are loaded via an index table, which is analogous to a disk directory, containing the module name, size, location, and other flags.

Parameters

idx (Num) [in/out]

indicates the starting position in the memory index table to search forward from (0 to start at the beginning). It will be returned with the position of the located module, (0=not found), allowing it to be used in a subsequent call to scan forward from there.

name (String) [in/out]

should be set to the name and extension of the module to locate (e.g. "EMAILX.SBX"), or blank to locate the first module after the position specified by idx. It will be returned with the name of the located module.

size (Num) [out]

will return the size of the located module, in bytes.

flags (Num) [in] optional

will return flags relating to the module status, from the following table:

Symbol | Value | Description
USRMEM_INUSE | &h0001 | Module currently running. Cannot be deleted under any circumstances.
USRMEM_LOCKED | &h0002 | Module is locked in memory. This prevents it from being deleted (with a special switch) and can be set by specifying this flag on the load operation.
USRMEM_PERM | &h0004 | Module was manually loaded and will be left in memory until manually deleted.
USRMEM_CACHE | &h0008 | Module was auto-loaded and will be cached in memory for a "reasonable" amount of time.
USRMEM_UNLOCK | &h0010 | This is a command flag, not a module flag, but is listed here because it is needed with the delete function to delete a module that has the USRMEM_LOCKED flag.
USRMEM_NOFILE | &h0020 | Needed in order to load a memory module directly from a variable.
Definition file: ashell.def

ver (String, 13+) [out] optional

will return the version of the module if it is a LIT, SBX, or RUN.

See Also

• MX_SETMEMFLAGS

History

2008 June, A-Shell 5.1.1116: You can also use the BASIC LOOKUP statement or function call to check for the existence of a module in user memory. For example:

IF LOOKUP("MEM:MYFILE.DAT") THEN

See the discussion on DEVICE system parameter for details on defining the MEM: device.


MIAMEX 108: Load module into memory

xcall MIAMEX, MX_USRLOD, idx, fspec$ {,flags, var, count}

MX_USRLOD allows you to create and load a memory module from a file or a variable. Unlike under AMOS, this can be done while running a BASIC program.

Parameters

idx (Num) [out]

will return the index entry number where the module was loaded, or 0 if not loaded. (-1 indicates that the module was already locked into memory.)

fspec$ [in]

must be set to the specification of the file to load into memory. (If the USRMEM_NOFILE flag is specified, then fspec just sets the name of the module in memory.)

flags (Num) [in]

may be set to any sensible combination of the memory module flags. Normally this would only be used to set the USRMEM_LOCKED flag to lock the module in memory, or to specify the USRMEM_NOFILE flag (which is required when loading the module from a variable). See MX_USRMAP for a table of applicable flags.

var (Raw) [in]

When specified in conjunction with the USRMEM_NOFILE flag, the module is loaded directly from the specified variable. This provides a mechanism similar to COMMON.SBR, which has the advantage of not having any particular limits on the module size or name.

count [in]

This parameter makes it easier to load full or partial arrays into a memory module.

When flags contains USRMEM_NOFILE (meaning that the module is to be loaded from contents of the variable var, with fspec$ indicating the desired name of the memory module), then if var is actually an array element, e.g. VAR(1), then count can be specified to indicate the number of elements to load starting with the specified element. For example:

MAP1 ARRAY(70),S,25

XCALL MIAMEX,MX_USRLOD,MIDX,"MYMOD.SYS",USRMEM_NOFILE,ARRAY(1),70

The above would load 70 elements of the array, starting with ARRAY(1) into a memory module named "MYMOD.SYS", whose index number would be returned in MIDX.

Warning #1: It is impossible for the subroutine to know whether the count value you specify is actually valid (i.e. not larger than the array), so the responsibility is yours.

Warning #2: The type of the array must not be F,6 or F,4. (These two types get converted to F,8 by the generall XCALL handler, causing the address of the array seen by the subroutine to not match that seen by the caller.)

Note: count is the number of array elements, not the number of bytes. In the example above, count is specified as 70, which results in 70 elements of the array, or 70 x 25 = 1750 bytes being loaded. In contrast, to read/write more than one array element at a time in MX_USRIO, you would need to specify the number of bytes, not elements. This is a likely error when using both MX_USRLOD and MX_USRIO together.

See the notes under MIAMEX 107 for more information on A-Shell’s user memory architecture.

See Also

LOAD.LIT which is the typical way to load a module into memory.


MIAMEX 109: Delete module from memory

xcall MIAMEX, MX_USRDEL, idx, name {,flags}

MX_USRDEL allows you to delete a module from user memory.

Parameters

idx (Num)

will return the index entry number of the deleted module, if successful, or 0 if not deleted.

name

should be set to the name and extension of the module to delete (e.g. "EMAILX.SBX").

flags (Num)

may be set to USRMEM_UNLOCK to allow deletion of a module that is locked in memory.

See Also

• The notes under MX_USRMAP for more information on A-Shell’s user memory architecture.

• DEL.LIT, which is the typical way to delete a module from memory.

• MX_SETMEMFLAGS


MIAMEX 110: Save memory module

xcall MIAMEX, MX_USRSAV, status, name

XMX_USRSAV allows you to save a memory module to a disk file.

Parameters

status (F,6)

will return the number of bytes written to disk if successful, 0 if the module was not found in memory, and a negative number to indicate an error. Currently defined error conditions are: -1 if there was a discrepancy in the number of bytes written (perhaps indicating a disk quota or limit was exceeded); -2 if the file could not be opened (perhaps indicating a privilege or write protect problem); and –3 if there was an error in processing the file specification (perhaps indicating that you are not logged into a valid directory).

name

should be set to the name and extension of the module to save (e.g. "EMAILX.SBX"). It will be saved to your current logged in directory.

See Also

• The notes under MIAMEX 107 for more information on A-Shell’s user memory architecture.

• SAVE.LIT, which is the typical way to save a memory module to disk.


MIAMEX 111: Read/write memory module

Updated July 2008

xcall MIAMEX, MX_USRIO, status, module, opcode, var, {offset, bytes}

MX_USRIO allows you to read and write directly to a memory module. This is a relatively advanced technique that might be useful either to maximize performance in an I/O intensive operation, or to gain the equivalent functionality of a dynamically allocated unformatted variable. (For the latter, it would be necessary to first create a dummy disk file of the desired size, then use MX_USRLOD to load it into memory.)

Parameters

status (F,6) [out]

for read/write operations, will return the number of bytes successfully transferred (0 if the module was not found, negative numbers for errors). For the search operation, returns the position (0 based) if found, else -1 to indicate not found.

module (String or Num) [in]

must be set to the name or index number of the module to access. If it is a string, it is interpreted as the name and extension of the module (e.g. "EMAILX.SBX"). If it is a numeric parameter, it is interpreted as the index number of the module. (The index number can be obtained from the module name and extension using MX_USRMAP, and its subsequent use would be more efficient by eliminating the need to scan the memory module list to locate the module by name on each access.)

opcode (Num) [in]

indicates the operation per the following below.

Value | Description
0 | Read bytes
1 | Write bytes. See Notes, below.
2 | Read records. See Notes, below.
3 | Write records
4 | Search for string, case insensitive
5 | Search for string, case sensitive

var (Raw or String) [in/out]

For opcodes 1 and 3, must contain the data to be written. For opcodes 0 and 2, receives the data read. For opcode 4 and 5, must be set to the string to search for. Note: do not use a dynamic variable in read modes.

offset (Num) [in]

specifies the starting offset from the beginning of the memory module. If opcode is 0 or 1, the offset is assumed to be in bytes. If opcode is 2 or 3, it is in records (of size defined by the size of the var parameter, or the value of the bytes parameter, if specified). Note that the first byte or record is at offset 0, not 1..

bytes (Num) [in]

indicates the number of bytes to read or write. In record mode (opcode 2 and 3) it may be omitted, in which case the size of the var parameter will determine this.

Notes

Opcodes 3 and 4 are like 0 and 1 except they treat the data as if it were 512-byte-blocked, i.e. organized like disk file records when the SPAN'BLOCKS option is not used. If the record length does not divide evenly into 512, and the data was loaded either from an array or from a file using the SPAN'BLOCKS, then you will need to use opcodes 0 and 1 instead, e.g. to read the Nth record using opcode 0, set offset = sizeof(var) * (N-1). Other differences with the record-oriented opcodes are that the bytes parameter becomes optional (defaulting to the the size of the var parameter), and the offset parameter unit becomes records rather than bytes.

See the notes under MX_USRMAP for more information on A-Shell’s user memory architecture.

History

2008 June, A-Shell 5.1.1116: As of A-Shell 5.1.1116.4, you can also read from a module loaded into user memory by opening it as a sequential file using the MEM: device. For example:

open #ch, "MEM:MYFILE.DAT", input

do

input line #ch, pline

if eof(ch)=0 or pline#"" then

<process pline>

else

exit

endif

loop

close #ch

See discussion of the miame.ini DEVICE system parameter for details on defining the MEM: device.

2006 September, A-Shell 4.9.967: MX_USRIO now allows you to read and write full or partial arrays. No new parameters are needed. The only change is that now, if the specified var is an array element, then the bytes specified is trusted, even if it exceeds the size of the var parameter. (This is needed, because when a subroutine parameter is specified as array element, e.g. VAR(1), then the size seen by the subroutine is the size of the element, not the size of the entire array.) To transfer 70 elements worth of data from the memory module loaded in the example shown above in MX_USRLOD, back into the ARRAY, you could use the following:

MAP1 ARRAY(75),S,25

xcall MIAMEX, MX_USRIO, STS, MIDX, 0, ARRAY(1), 0, 70*25

You could also copy from the ARRAY to the memory module in the same way, using opcode 1. The only difference between this and the MX_USRLOD operation is that MX_USRLOD will create the module if it doesn't already exist.


MIAMEX 112: Set AutoMouse translations

xcall MIAMEX, MX_AMOUSEXLT, opcode, status, flags, s1, t1, ... s10, t10

MX_AMOUSEXLT allows you to define or otherwise control AutoMouse translations within a program. AutoMouse is an A-Shell scheme, which can be activated or deactivated from the Edit menu, which allows the user to double-click on a text "token" anywhere on the screen to transmit those characters to the keyboard. A "token" is a string of characters delimited by any non-alpha, non-numeric characters (i.e. space or punctuation). This MIAMEX function allows you to extend or control this capability by creating translation strings that are not limited to "tokens" (as just defined) and which can transmit arbitrary text (rather than the characters of the string which is double-clicked on).

Parameters

opcode (Num)

should be set to one of the following:

Value | Operation
0 | Add (or create new) translation list
1 | Clear existing translations
2 | Temporarily disable translations
3 | Re-enable translations
4 | Disable intelligent doubleclick
5 | Restore doubleclick to state it was prior to last opcode 4 or 6.
6 | Enable intelligent doubleclick

status (F,6)

returns 0 on success, else an error code. Currently defined errors are –1 (cannot allocate memory for translations) and –2 (translations exceed memory limit of 2048 bytes).

The remaining arguments are only used if opcode=0.

flags (Num)

affect the way the translations work. Currently the only defined flag value is 1, which indicates that the translation is not case sensitive.

s1...s10

strings representing the text which may appear on the screen, to be clicked on and translated (to the corresponding t1...t10 values). Note that these strings may contain spaces and other non-alphanumeric characters, which would otherwise be considered delimiters. The maximum length of each string is 132 characters.

t1 through t10

strings containing the characters to be transmitted to the keyboard when the corresponding string (in s1 through s10) is double-clicked. They may also be specified as B or F variables, in which case the define the byte value of a single byte to be transmitted. (This may be more convenient than string representation when dealing with control characters, e.g. 1= Ctrl+A, 27=Escape, etc.).

You do not have to specify all 10 pairs of sn and tn strings, and even if you do, interpretation will stop at the first null sn string. There is no particular limit to the number of translation pairs you can define (using as many calls to this function as necessary). The total combined limit on the sn and tn strings is 2048 characters.

opcode 4, 5 and 6 are primarily of interest for eliminating the situation in which double-clicking on an empty part of a form sends a CR, which is treated the same as clicking on the currently focused button.


MIAMEX 113: Change memory partition

xcall MIAMEX, MX_MEMORY, newsizk, status

MX_MEMORY allows you to change the size of your user memory partition on the fly, although not within a function or procedure.

Parameters

newsizk

is the desired new size (in Kilobyte units, e.g. 1024 = 1024K).

status (F,6)

Value | Meaning
0 | successful
-1 | invalid—pathologically small—newsizk value.
-2 | the program is currently executing a function or procedure; this conflicts with the memory resize operation due to inter-dependencies between the partition and the function call stack.

See Also

• MEMORY.LIT, which is implemented via the MX_MEMORY function.

• The MEMORY system parameter.


MIAMEX 115: Indirect XCALL

xcall MIAMEX, MX_IXCALL, sbrnam, xcbadr, status

MX_IXCALL allows you to forward the calling parameter from one BASIC SBX subroutine to another, evaluating the new subroutine name on the fly.

Parameters

sbrnam (String)

is the name of the new subroutine to call.

xcbadr (F,6)

is the address of the parameter structure which was passed to the original routine.

status (F,6)

will return 0 for success, >0 for subroutine not found or unable to load, else <0 for other system errors.

Comments

MX_IXCALL is used in the RXCALL.SBX routine, which allows you to remotely call a routine running on another machine. See the documentation on SBX Subroutines about RXCALL, as well as for information on the XCALL parameter structure.


MIAMEX 116: Process color ini file

xcall MIAMEX, MX_INICLR, fspec, status

MX_INICLR allows you to process (or reprocess) the specified color initialization file. Normally, this file is called DSK0:INI.CLR[7,0] and is processed automatically when A-Shell is launched. But it may be useful to be able to edit this file and reprocess it, or switch to a different color settings file, without restarting A-Shell.

fspec must contain the file specification (AMOS or native format) of the color settings file to process. If blank, the default is DSK0:INI.CLR[7,0]. If no extension is specified, the default extension is CLR.

Refer to Color Configuration for details on the format of the INI.CLR file.


MIAMEX 117: Send MAPI mail

Updated May 2011

xcall MIAMEX, MX_MAPI, status, fspec {,flags, subject, text, xdata, fspec2, fspec3, ...fspecn}

(Windows only) MX_MAP provides a simple way to send the contents of a file via interactive email. It launches the current email client program (e.g. Outlook, Eudora, etc.) and then inserts the contents of the file into the body of the message. The user has only to address the message and optionally type in introductory comments. To send email without user interaction, an A-Shell module called EMAILX is available from MicroSabio.

Note that this call requires that the Windows "Simple MAPI" interface be installed. This will happen automatically in most cases, as it is included in Outlook Express. But it is not installed by default with the full server version of Exchange Server. In that case, you need to manually install the "simple MAPI" subsystem from your Windows media or Microsoft.

Parameters

status (F,6)

will return a status code indicating the success or failure of the operation, from the following table. Note that the negative error numbers relate to errors within the MIAMEX subroutine, while the positive errors are returned from the MAPI interface itself.

Value | Meaning | Value | Status
0 | Success | 11 | MAPI Attachment not found
-1 | MAPI interface not available on this computer | 12 | MAPI Error opening attachment
-2 | Unable to load MAPI32.DLL | 13 | MAPI Error writing attachment
-3 | Unable to get address of MAPI SendMail function | 14 | MAPI Unknown recipient
-4 | Unable to allocate memory | 15 | MAPI Bad receipt type
-5 | Unable to open fspec | 16 | MAPI No messages
-7 | fspec not found | 17 | MAPI Invalid message
1 | MAPI User abort | 18 | MAPI Text too large
2 | MAPI General failure | 19 | MAPI Invalid session
3 | MAPI Logon failure | 20 | MAPI Type not supported
4 | MAPI Disk full | 21 | MAPI Ambiguous recipient
5 | MAPI Insufficient memory | 22 | MAPI Message in use
6 | MAPI Access denied | 23 | MAPI Network failure
8 | MAPI Too many sessions | 24 | MAPI Invalid edit fields
9 | MAPI Too many files | 25 | MAPI Invalid recipients
10 | MAPI Too many recipients | 26 | MAPI Not supported

fspec

is the file specification (AMOS or native format) of the file to send via email.

flags (optional, Num)

may contain any combination of the following values:

Value | Meaning
1 | Receipt requested
2 | Send file(s) as attachments
4 | Send using HTML fixed pitch
12 | Very small fixed type
32 | Send without user interface (see Comments below)

subject (optional, String)

may be set to the desired subject of the message. (Otherwise the user can type a subject in interactively.)

text (optional, String)

may be set to any text which will be inserted in the message prior to the specified file. (This might be useful for introductory comments.)

xdata (optional, String)

May contain a single recipient address, using either of these formats:

johndoe@somedomain.com

John Doe <johndoe@somedomain.com>

Note that in the second case, the friendly name may or may not actually get picked up by the email client, but the actual email address should be recognized in either case.

fspec2...fspecn (String)

specifies additional attachments (if you have more than one).

Comments

If flag 32 is used to send the message without user interaction in the email client, you must include a valid recipient address in the xaddr parameter. Even then, because of the security risks of letting programs "commandeer" the email client to send messages in this way, the client may reject the attempt entirely, or it may prompt the user for confirmation. These kinds of responses by the email client are outside of the control of A-Shell.

To send mail without user interface and with more control, see A-Shell's EMAILX module. For sending email messages from an application after first creating a PDF file, see the PDFX module.

History

2008 November, A-Shell 5.1.1130: Add flag 32 and support recipient address in the xdata param.

2006 May, A-Shell 4.9.957: Update to current syntax. Old syntax: xcall MIAMEX, MX_MAPI, status, fspec {,flags, subject, text}


MIAMEX 118: Get/set stream position

xcall MIAMEX, MX_FILEPOS, chan, opcode, pos {,filidx}

MX_FILEPOS allows you to get or set the current file position within a sequential file which is open for input or output.

Parameters

chan (Num)

should be set to the channel number of the open sequential file.

opcode (Num)

must be set to 0 to get the current file position or 1 to set it.

pos (F,6)

is the position (offset in bytes from the start of file). For opcode 0 (get), the current position is returned in this parameter. For opcode 1 (set), pos must be set to the desired new file position.

filidx (B,4)

is an optional handle to a "file index" which can be created and passed back to you by XTREE.SBR. If filidx is specified and opcode = 1, then rather than setting the file pointer to the byte position specified by pos, it instead interprets pos as the desired line number, and uses the index referenced by filidx to locate that line number directly (without having to scan the file sequentially).

If there is an error in the operation, pos will be returned as -1.

History

2006 June, A-Shell 4.9.958: You can use this capability to write to an arbitrary position within an existing sequential file by first opening the file for APPEND, then positioning the stream pointer with MIAMEX,118, after which you can write to the new position in the output file using standard output commands such as PRINT #CH.


MIAMEX 120: Prompt for Windows printer

Updated and Reviewed April 2012

xcall MIAMEX, MX_WINPTR, status, printer {port, driver, orientation, length, width, formname, duplex, bin, color, resolution}

(Windows/ATE) MX_WINPTR displays a standard Windows printer selection dialog and returns information about the printer selected. This might be useful for building printer initialization files (see Defining Spoolers) based on the selected printer. Or, you can take it one step farther and just use the full Windows printer name (as returned in the printer parameter) directly when sending files to the printer. For more information, see EZSPL and PRINT.LIT.

Note that this operation can only take place on a GUI-enabled client, either ATE or some form of A-Shell/Windows.

Parameters

Parameter | Type | I/O | Description
status | Num | out | 0: User cancelled out of the printer selection dialog -1: Feature not supported (requires ATE or A-Shell/Windows) -2: Invalid ATE response (ATE must be build 960+) >0: OK
printer | String | out | the descriptive printer name of the printer selected by the user. This is normally the name which appears under the icon in the printer selection window.
port | String | out | port name. This could be a traditional physical port (like LPT1:), or a logical network port (like NET01: or IP_192.158.200.250).
driver | String | out | name of the driver. In most cases with newer versions of Windows, this will be the universal spooler driver "winspool" (which in turn calls the hardware-specific driver).
orientation | Num | out | 1=portrait, 2=landscape
length | Num | out | paper length in tenths of millimeters
width | Num | out | paper width in tenths of millimeters
formname | String | out | name of form (e.g. "Letter", "Legal", etc.)
duplex | Num | out | 1=simplex, 2=duplex (vert), 3=duplex (horz)
bin | Num | out | bin number
color | Num | out | 1=monochrome (B & W), 2=color
quality | Num | out | If greater than zero, indicates the resolution in DPI. Otherwise: -1 = draft, -2 = low, -3 = medium, -4 = high.

History

2012 April, A-Shell 6.0.1248: Switch to a more modern version of the printer selection dialog for better compatibility with Windows 8. Main visual difference is the addition of the "Apply" button. At the application level, you can now retrieve several additional parameters about the current printer selection: orientation, paper length, width, form name, duplex option, bin, color versus mono, and the quality (resolution). In addition to the new parameters, the status parameter now indicates whether the user hit the "Print" button (1) or the "Apply" and then the "Cancel" (2). Note that this is only for information purposes, since neither "Print" nor "Apply" actually changes the internal default settings in the printer. But the application might choose to interpret the two cases differently.

2006 July, A-Shell 4.9.960: This function now supports ATE. Thus, the application on the server can now prompt the user to choose a windows printer, and then, using AG_SPOOLCFG, send this information to the ATE client prior to printing to it via the DEVICE=AUXLOC: option. Note that to be effective, this requires that a printer init file exist for the specified printer name in the ASHCFG: directory of the ATE client (aka %MIAME%\dsk0\001007).


MIAMEX 121: Set/get chain-to on priv error

xcall MIAMEX, MX_CHAINTO, opcode, progrm

MX_CHAINTO allows you to define a program to chain to automatically if an attempt is made to run a program for which the user does not have sufficient (read) privileges. This is useful if you wish to use the operating system file access privileges for restricting access to sensitive programs (as an alternative, for example, to password protecting them). If no chain-to specification is defined, then such an attempt will cause the program to abort, displaying an "access denied" message, probably leaving the user at the dot prompt. By defining a chain-to program, when such an error occurs, the user will automatically be redirected to the specified program (which might be a menu, or perhaps an error recovery program).

Parameters

opcode (Num)

should be set to 0 to retrieve the current chain-to specification into the progrm variable, or 1 to set the new chain-to specification from the contents of the progrm argument.

progrm (String)

will either return (for opcode 0) or be used to set (for opcode 1) the chain-to specification. It should be a RUN or LIT program in AMOS format (no CMD or DO files allowed). Examples would be "MAIN.RUN" or "DSK0:MAIN.RUN[100,22]" or "SYS:HOST.LIT."

Comments

If the application allows the user to move around to different PPNs, it would be wise to include the complete specification for the desired chain-to program (else it might not be found). Also note that even though the program can be found, the user may no longer be in the expected directory, so a robust program would probably want to log the user to the expected directory automatically (see LOG).


MIAMEX 123: Get/set SBR= flags

Rewritten May 2013

xcall MIAMEX, MX_SBRFLG, opcode, flags1 {flags2}

MX_SBRFLG is used to programmatically retrieve and/or set A-Shell system options that are normally set with the SBR= statement in the miame.ini file. See the system parameter SBR for more detailed descriptions of the various flags. An example is provided after the tables.

Parameters

opcode (Num) [in]

0 (MXOP_GET) to retrieve the current flags, 1 (MXOP_SET) to set them

flags1 (B,4 of F) [in/out]

Symbol | Value | Meaning
SBRF_BSMID5 | &h00000001 | Affects sequential serach in SERCH.
SBRF_INFLD143 | &h00000002 | Affects the operation of J justified types in INFLD.SBR.
SBRF_INFLDPS | &h00000004 | Impacts the operation of types "P" and "S" in INFLD.
SBRF_INFLDB3 | &h00000008 | Causes INFLD to add blank spaces for comma-formatted fields.
SBRF_INFLDLDROP | &h00000010 | Special handling for type "L" operation in INFLD.
SBRF_MXLOCK | &h00000020 | Forces XLOCK to conform exactly to standard documentation.
SBRF_MESAGRTN | &h00000040 | Changes behavior of MESAG.
SBRF_MALLOCSORT | &h00000100 | Affects the memory allocation strategy of BASORT.
SBRF_COMMONNDR | &h00000200 | Non-destructive read in COMMON.
SBRF_PRTCHK1 | &h00000400 | Causes PRTCHK to return 1 if printer is found, 0 if it is not.
SBRF_PRINTNOFF | &h00000800 | Eliminates formfeed character in PRINT.
SBRF_XPPNOCT | &h00001000 | Affects how XPPN displays PPN value.
SBRF_AMOSJOB1 | &h00002000 | Causes JOBNAM to return the name of the parent job.
SBRF_TRIMCTL | &h00004000 | Causes TRIM to remove leading and trailing control characters.
SBRF_INFLDR | &h00008000 | Causes INFLD to not apply right-justification to the returned field.
SBRF_INFLDEDIT | &h00010000 | Provide support for a variation of INVUE.
SBRF_AXLOCK | &h00020000 | Causes A-Shell to exactly duplicate the behavior of XLOCK under AMOS.
SBRF_LSTLINSTRIP | &h00040000 | Strips comments from command line before returning them to LSTLIN.
SBRF_PGRW_TTI | &h00080000 | Affects how INFLD type codes "$" and "H" are handled.
SBRF_BOX_MINATTR | &h00100000 | Minimizes the use of attributes (particularly reverse video) used with certain box drawing operations (particularly INMEMO).
SBRF_INFLD_V1 | &h00400000 | Eliminates the need to specify the V parameter to INFLD.
SBRF_EZPRTX | &h00800000 | Causes EZTYP to use EZPRTX.
SBRF_FLOCKD | &h01000000 | Disables validation of the file channel and record number parameters in FLOCK.SBR
SBRF_FLOCKL | &h02000000 | Backs up FLOCK exclusive record locks with LOKSER locks (provided that LOKSER is enabled). May be useful when different applications (one using FLOCK, the other LOKSER) share files.
SBRF_INFLD_KEEPALIVE | &h04000000 | Sends a few bytes every 15 seconds while waiting for input.
SBRF_PCKLST_GUI | &h08000000 | Use XTREE (GUI) in place of PCKLST (text)
SBRF_INFLDCBRJ | &h10000000 | Right-justifies text label.
SBRF_SUBMIT2 | &h20000000 | Forces a new process to be the grandchild of the current process.
SBRF_NO_MMAP | &h40000000 | Disables memory mapping in certain ERS proprietary subroutines.
SBRF_XMASCB_OPEN | &h80000000 |
Definition file: ashell.def

Hex-Decimal Values

flags2 (B,4 of F) [in/out]

Note that for opcode 1, if flags2 not specified, no changes will be made to those flags; in other words, the absence of the flags2 parameter is not equivalent to a parameter containing zero.

Symbol | Value | Meaning
SBRF2_GUISELPOS | &h00000001 | INFLD GUI caret at start
SBRF2_AUTO_TABX | &h00000002 | auto add MBF2_TABX to MBF_TAB
SBRF2_PRINT_TIME | &h00000004 | add time to PRINT.SBR hdr
SBRF2_PRINT_JOBUSN | &h00000008 | add user to PRINT.SBR hdr
SBRF2_AUTO_DLGMAX | &h00000010 | auto max dlgs > desktop
SBRF2_INFLD_PRINTS | &h00000020 | INFLD ^P : File>Printscreen
SBRF2_XTREE_EXPCSV | &h00000040 | XTREE add Export CSV to mnu
SBRF2_XTREE_EXPTSV | &h00000080 | XTREE add Export TSV to mnu
SBRF2_XTREE_EXPOPEN | &h00000100 | XTREE open after export
SBRF2_XTREE_PRINT | &h00000200 | XTREE add print to mnu
SBRF2_XTREE_SRCH | &h00000400 | XTREE add search to mnu
Definition file: ashell.def

Example

To retrieve the current SBR= flags and then set or clear the SUBMIT2 flag:

map1 sbrflags1,b,4

map1 sbrflags2,b,4

xcall MIAMEX, MX_SBRFLG, MXOP_GET, sbrflags1, sbrflags2 ! retrieve

sbrflags1 = sbrflags1 or SBRF_SUBMIT2 ! set SUBMIT2

or

sbrflags1 = sbrflags1 and not SBRF_SUBMIT2 ! clear SUBMIT2

xcall MIAMEX, MX_SBRFLG, MXOP_SET, sbrflags1, sbrflags2 ! set

Comments

MX_SBRFLG normally only operates relative to the server. In the ATE environment, use the AG_SBRFLAGS command to retrieve/set the client flags.


MIAMEX 124: Output to ashlog.log

xcall MIAMEX, MX_ASHLOG, string

MX_ASHLOG outputs the string message to the ashlog.log file. It is useful when you want to log your own messages in the same stream that A-Shell uses for its system messages. MIAMEX 124 was added to A-Shell in build 862, 02 Feb 04.


MIAMEX 125: Get last MCRS click info

xcall MIAMEX, MX_MCRS, clickinfo, row, col

MX_MCRS retrieves information about the last mouse click (when mouse cursor reporting has been activated via TCRT 158). clickinfo returns a bitmap consisting of the following:

1 Left button

2 Right button

8 Double click (else single click)

For example, 1 is a standard left click, while 10 is a right double-click. row and col indicate the row, col position of the click. MIAMEX 125 was added to A-Shell in build 862, 02 Feb 04.


MIAMEX 126: Sink/unsink field

xcall MIAMEX, MX_SINK, opcode, srow, scol, erow, ecol, bgc

Causes the specified box to be "sunk" or "unsunk", based on opcode (1 to sink, 0 to unsink). This is the same routine used by INFLD to give the field being editing the appearance of being slightly sunken. You can also get this effect by using the MBF'SUNKEN flag with MIAMEX 119 to create a static text control with that style, but in that case, you cannot freely write on top of the control. With MIAMEX 126, the effect does not conflict with character-level I/O to that screen area (which is why it works with INFLD). MIAMEX 126 was added to A-Shell in build 866, 12 Feb 04.


MIAMEX 127: Get/set rounding factor

xcall MIAMEX, MX_ROUND, opcode, factor

MX_ROUND allows you to get (opcode = 0) or set (opcode = 1) the new variable rounding factor. Basically the factor is set to the level of precision you would like. 1 means round all variables to the nearest integer. .01 would be to the nearest one hundredth. 0 disables the feature. Note that the setting persists across programs. For an in-depth discussion of the floating point rounding issue, see Rounding of Floating Point Variables.

History

2004 April, A-Shell 4.9.878: Routine added to A-Shell


MIAMEX 128: Get IP address

xcall MIAMEX, MX_GETIP, ip$

Returns the IP address of client workstation.

See Also

• GETMAC.SBR

• CONDEV.SBR.

History

2004 April, A-Shell 4.9.879: Routine added to A-Shell


MIAMEX 130: Get startup command

xcall MIAMEX, MX_ASHFILE, startcmd {,ashfile, ashexe}

MX_ASHFILE returns various parts of the command line with which the current session of A-Shell was launched.

Parameters

startcmd (String) [out]

Returns the initial A-Shell command line, i.e. the part of the overall command line by which A-Shell was launched, that was left to process when it first gets to the dot prompt. If A-Shell was launched without specifying a startup command, the default is "astart."

ashfile (String) [out]

For Windows, returns the name of the settings (.ash) file that was specified on the ashw32 command line (-o parameter). For UNIX, returns a null string.

ashexe (String) [out]

Returns the ashell executable name, as specified in the command line. This may, or may not be fully qualified, depending on what was specified in the launch command line. Under UNIX, likely possibilities are "ashell" or "/vm/miame/ashell." Under Windows, a likely possibility is "c:\vm\miame\bin\ashw32.exe."

Examples

Original command line (UNIX): ./ashell -i /vm/miame/miame.ini main.cmd

startcmd: "main.cmd"

ashfile: ""

ashexe: "./ashell"

Original command line (Windows): c:\vm\miame\bin\ashw32.exe -i c:\vm\miame\miame.ini -o c:\vm\miame\custom.ash main.cmd

startcmd: "main.cmd"

ashfile: "c:\vm\miame\custom.ash"

ashexe: "c:\vm\miame\bin\ashw32.exe"


MIAMEX 131: Get file stats

Updated June 2011; see History

xcall MIAMEX, MX_FILESTATS, loc'rem, path, bytes {, mtime, ctime, mode, ver, hash, owner, group}

MX_FILESTATS returns stats for the specified PATH, either on the local system or the remote PC via ATE.

When MX_FILESTATS is used to query the status of a file on the PC (via ATE), if the filespec is a UNC spec (i.e. starts with "\\"), then the timeout wait is extended from 5 to 15 seconds. This eliminates most problems with ATE timing out before Windows times out, if the UNC spec is not available. The shorter timeout wait was leading to ATE becoming unsynchronized with the server, which in some cases was leading to application confusion.

See the Tab(-10,x) Function Listing for an equivalent Print Tab command (AG_FILESTATS).

Parameters

loc'rem (String, 1) [in]

"L" for local system, "R" for remote PC, "C" for client/cache. See History, below, for more info on "C."

path (String) [in]

specifies a native path or AMOS-style filespec. If native, may include embedded environment variables using the %env% syntax. Note that if loc'rem is "R," and AMOS specification in path will be interpreted relative to the INI file used by ATE on the PC.

bytes (F) [out]

returns the size of the file. If path is not found bytes will be set to -1. -2 indicates that you are attempting to use a remote PATH when you do not have ATE support.

mtime, ctime (F or B,4) [out]

return the last modification time and creation time, in seconds since "the epoch" (Midnight Jan 1, 1970). This format is very convenient for comparing file times, but be forewarned that comparing file times on different machines (e.g. to decide if a file transfer/update is needed) requires that you synchronize the clocks on the machines in question! If you want to display the file times in a more human-friendly format, use MX_FTFORMAT.

mode (F or B,2+) [out]

returns the mode bits indicating the type and other attributes of the file. The most interesting bits are:

Symbol | Value | Meaning
FSTS_PRVPX | &h0001 | execute privilege (other)
FSTS_PRVPW | &h0002 | write privilege (other)
FSTS_PRVPR | &h0004 | read privilege (other)
FSTS_PRVGX | &h0008 | execute (group)
FSTS_PRVGW | &h0010 | write (group)
FSTS_PRVGR | &h0020 | read (group)
FSTS_PRVOX | &h0040 | execute (owner)
FSTS_PRVOW | &h0080 | write (owner)
FSTS_PRVOR | &h0100 | read (owner)
FSTS_SSWT | &h0200 | save swapped text after use (sticky)
FSTS_SGID | &h0400 | set group id on execution
FSTS_SUID | &h0800 | set user id on execution
FSTS_PIPE | &h1000 | pipe
FSTS_SPC | &h2000 | chr/special
FSTS_DIR | &h4000 | directory
FSTS_NORM | &h8000 | regular file
Definition file: ashell.def

Hex-Decimal Values

ver (String) [out]

returns the file version information (for RUN, LIT and SBX files only), in the format "a.b.c{.d{.e})" where a=vmajor, b=vminor, c=vsub, d=vedit, e=vpatch. Note that because this format may not be convenient for easily comparing two versions to see which is later, optionally you can retrieve the string in the format "aaaaa.bbbbb.ccccc.ddddd.eeeee" by passing a string mapped as 30 bytes for the ver parameter.

Files that do not have versions will return empty version strings (rather than either of the formats described above).

The function does not yet support retrieving version strings from EXE and DLL files, but that may be added in a future update.

hash (String, 15+) [out]

returns the file hash code in the format ###-###-###-###

owner, group [out]

may be returned as either integers or strings. If passed as B,4 variables, the numeric value (uid and gid) will be returned. Otherwise, the string names will be returned. Note that their owner and group info applies only to UNIX versions of A-Shell, but may be supported under some Windows versions in the future.

History

2011 June, A-Shell 5.1.1222: A new loc'rem parameter value ("C", for client/cache) checks for the file on the local client computer, including looking in the cache and other default local directories. In the case of ATE, this is similar to the "R" (remote) option except that if the file is not found in the specified directory, a search will be made of the other directories that ATE normally checks when trying to open files at the behest of the server (%ATECACHE%, %ATEPERMCACHE%, %MIAME%\icon, and possibly others). In the case of local A-Shell/Windows, this is like the "L" (local) option, except that it also checks the above-mentioned directories. (The cache directory environment variables will typically not be defined for A-Shell/Windows, and thus will be ignored, but the %MIAME%\icons subdirectory and perhaps others may still be valid and searched.) See AG_FILESTATS if you want to retrieve the actual filespec of the found file.

2010 May, A-Shell 5.1.1182: Add new parameters owner and group.

2009 February, A-Shell 5.1.1139: Modify routine to retrieve version and hash along with other file info.


MIAMEX 132: Format file time

Updated September 2011; see History

xcall MIAMEX, MX_FTFORMAT, ftime, strtime, {,sdate, stime}

MX_FTFORMAT is used to format a numeric filetime of the type returned by MX_FILESTATS into a more friendly format.

ftime (Num) [in]

File time in the format returned by MX_FILESTATS (seconds since 1970)

strtime (String, 24+) [out]

Formatted time, e.g. "Sun Jul 31 16:02:41 2011"

sdate (B,4) [in/out]

If specified, returns the date corresponding to ftime. Can be passed to ODTIM for formatting.

stime (Num) [in/out]

If specified, returns the number of seconds since midnight. Can be passed to ODTIM for formatting.

History

2011 September, A-Shell 5.1.1235: Add optional parameters sdate and stime to return the file time in the standard system date and time formats used by ODTIM.

2004 May, A-Shell 4.9.885: Routine added to A-Shell.


MIAMEX 133: Expand/reduce file in place

Updated December 2009

xcall MIAMEX, MX_EXPFIL, ch, addrecs, status

Note that it is up to you to update any control records or other internal structures to correspond to the new file size. Remember to release your exclusive access after doing so.

Parameters

ch

is the channel number that the file is open (for random exclusive access). If running LOKSER, you should probably open the file for RANDOM (exclusive) before expanding it. If not running LOKSER, you are free to use some other locking scheme. Although the XCALL will not stop you from expanding a file without first gaining exclusive access, you are likely to run into synchronization conflicts with other users who have the file open. For one thing, those users will not be able to access the expanded area (until they close and reopen the file), so if you update a control record they may try to access the new area and get an illegal record number.

addrecs

is the number of logical records to add (addrecs > 0) to or subtract (addrecs < 0) from the file, based on the record size passed in the file open statement. It will be converted to the appropriate number of 512 byte blocks to add or subtract. Added blocks will be filled with ]]] characters.

status

returns the new total number of logical records in the file if the operation is successful. 0 indicates a parameter or other configuration error trapped by the XCALL (generally accompanied by a displayed message.) <0 indicates an operating system error number, which you can retrieve the message for using MIAMEX,86,STATUS,MSG

History

2009 December, A-Shell 5.1.1167: Add ability to reduce file size.

2004 June, A-Shell 4.9.893: Routine added to A-Shell as expand-only file function.


MIAMEX 134: Registry operations

Documentation added May 2016

xcall MIAMEX, MX_SYNC {,ch, sts, flags}

(UNIX only) MX_SYNC (134) invokes one of the operating system "sync" commands to force some or all of the file system cached updates to be flushed to disk. Normally this operation is managed by the operating system in background, but there are times when you may want to be sure that file updates have been written to permanent disk prior to proceeding with then next application step.

Parameters

ch (Num) [in]

If specified and non-zero, just updates for the file currently open via that channel are flushed. Internally the operation uses the standard UNIX library call fsync() or syncfs() or msync(), depending on the platform and whether the file has been memory mapped. Otherwise, if ch = 0 or not specified, all cached data and metadata updates are flushed using the sync() call.

sts (Num) [out]

If specified, a status value will be returned here...

Group | Description
0 | success
-2 | ch not open
-3 | file type unknown or not applicable (e.g. input only)
-4 | operation not supported on this platform (e.g. Windows)
>0 | operating system errno value (see MX_ERRNOMSG)

flags (Num) [in]

If specified and set to 1, and ch > 0, and the platform supports GNU libraries, then syncfs() is used instead of fsync(). (syncfs flushes all of the data and metadata in the disk partition containing the specified file, whereas fsync only flushes the data and metadata for the specified file.)

Notes

Warning: Aside from being a relatively costly operation (in terms of performance), it is impossible to be certain that the data is actually written to permanent storage by the time the call returns. This is because even though the operating system may execute a synchronous write operation, there's no way to be sure that the disk driver (RAID, SAN, network, whatever) actually writes the data to the permanent media before returning. (It might have its own cache buffering system.)

History

2016 January, A-Shell 6.3.1502: Time elapsed in the sync() or fsync() call is now logged in microseconds if the XDEBUG trace flag set. This was motivated by suspicions that the sync() call is taking longer under CentOS/RHEL 6 and 7 than under CentOS/RHEL 5. Such suspicions can now be easily quantified. Also, fsyncing now supported for ISAMA files—e.g. xcall miamex, mx_sync, ch {,sts}.


MIAMEX 138: Registry operations

xcall MIAMEX, MX_REGISTRY, opcode, <params depending on opcode>

(Windows only) MX_REGISTRY provides a range of Registry operations. The symbols and values for opcode are shown in the following table. Parameters, which are dependent on the function being called, are listed and discussed in the topics covering the various functions. See also MX_GETREG (simplified retrieve with ATE support).

Symbol | Value | Function
REGOP_OPEN | 1 | Open
REGOP_CREATE | 2 | Create
REGOP_SET | 3 | Set
REGOP_READ | 4 | Read
REGOP_ENUMKEYS | 5 | Enumerate keys
REGOP_ENUMVALS | 6 | Enumerate values
REGOP_CLOSE | 7 | Close
REGOP_DELKEY | 8 | Delete Key
REGOP_DELVALUE | 9 | Delete Value
REGOP_DELIMS | 64 | Replace Null Delimiters
Definition file: ashell.def

Comments

MX_REGISTRY does not recognize ATE. If executed in a non-Windows environment (whether ATE or not), it will be essentially a null operation. If executed in the ATSD environment, it will return information from the server registry, not the client. If you want to retrieve registry information from the ATE client, either use MX_GETREG for simple retrieval, or package your MX_REGISTRY operations in an SBX which can be executed on the client side via AG_XFUNCS or MX_AGWRAPPER.

Although direct access to the Registry is not available for applications running A-Shell/UNIX, Steve Evans of Caliq has developed a pair of routines (INIX.SBX and SYSREG.SBX) which allow information to be saved using a similar model but which work on all platforms. See the routines in the SOSLIB for details.

History

2009 September, A-Shell 5.1.1159: MX_REGISTRY now supports returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized.

2005 March, A-Shell 4.9.925: Routine was enhanced to provide an option for more friendly delimiters when retrieving or setting REG_MULTI_SZ values. This value type is used for lists of names, like bin names or paper size names, and consists of strings separated by a null byte, with the last string terminated by two null bytes. This format makes sense in C, but in BASIC, it is difficult to deal with the embedded nulls. The new option replaces the null terminators, except for the very last one, with chr(128) characters. For the set opcode, you may optionally use these same chr(128) characters to build your value string. The option is activated by adding 64 (REGOP_DELIMS) to the opcode. This applies to opcodes 4 and 6.

See the sample program REGPTR.BP for a working example.


Open

This call is needed to open up a branch of the Registry and returns a handle which can be used in subsequent opcodes.

xcall MIAMEX, MX_REGISTRY, REGOP_OPEN, hkey, subkey, rights, hkeynew, status

Parameters

hkey (B,4) [in]

can be a key returned in the hkeynew parameter from a previous open, or more likely, one of the following symbols (from ashell.def) for the main hives in the Registry:

Symbol

HKEY_CLASSES_ROOT

HKEY_CURRENT_USER

HKEY_LOCAL_MACHINE

HKEY_USERS

subkey [in]

is a string combining one or more levels beneath the level referenced by the key hkey, for example:

SUBKEY = "SOFTWARE\MicroSabio\JBCT\ATE"

Note that subkey is not case sensitive on lookup, but when creating keys, the case specified will be retained. (Same idea as with Windows filenames.)

rights [in]

is a numeric variable combining one or more of the following bits relating to the kind of rights you want to request for this key:

Symbol | Value | Description
RGKEY_QUERY_VALUE | &h000001 | Ability to query a value
RGKEY_SET_VALUE | &h000002 | Ability to change or set a value
RGKEY_CREATE_SUB_KEY | &h000004 | Ability to create a new sub key
RGKEY_ENUM_SUB_KEYS | &h000008 | Ability to enumerate sub keys
RGKEY_WOW64_32KEY | &h000200 | access key from 32 bit registry view
RGKEY_WOW64_64KEY | &h000100 | access key from 64 bit registry view
RGKEY_DELETE | &h010000 | ability to delete key
Definition file: ashell.def

Hex-Decimal Values

hkeynew (B,4) [out]

will return the handle to the opened key, and will be needed for subsequent operations. Note that in a non-Windows environment, since the operation will do nothing, it will not update the hkeynew parameter. You should therefore set it to zero initially, so that you can check to make sure that it comes back with a non-zero value.

status (F,6) [out]

returns 0 for success, or else an error code. You can convert the error code to a message using: xcall MIAMEX, MX_ERRNOMSG, status, msg. Note that status may not be set in the case of the non-Windows environment; see hkeynew comments for error checking advice.


Create

This is used to when saving values to the Registry. It will create the specified subkey if it does not exist, or if the subkey already exists, it will open it.

xcall MIAMEX, MX_REGISTRY, REGOP_CREATE, hkey, subkey, rights, hkeynew, status

The parameters are nearly the same as for Open. The main difference is that the status parameter can return either of the following:

STATUS=1 (Key was created)

STATUS=2 (Key already existed and was opened)


Set

This is used to write a new or updated value to the Registry.

xcall MIAMEX, MX_REGISTRY, REGOP_SET, hkey, name, type, value, status

Parameters

hkey (B,4) [in]

must be set to the hkeynew value returned from a previous call to Create or Open a key.

name (String) [in]

is the name of the value to write. (These are the items that appear in the left side of the right hand pane of REGEDIT.EXE.)

type (Num) [in]

specifies the type of value you want to write:

Symbol | Value | Description
REG_NONE | 0 | No type
REG_SZ | 1 | Null terminated string
REG_EXPAND_SZ | 2 | Same as (1) but signals that string may contain embedded environment variables (e.g. "%TEMP%\xyx.log")
REG_BINARY | 3 | Raw binary data (use X format)
REG_DWORD | 4 | 4 byte integer (use B,4 format)
REG_MULTI'SZ | 7 | List of null terminated strings, with a double null terminating the list. See Replace Null Delimiters for an alternative to using null delimiters (with are hard to work with in BASIC).
Definition file: ashell.def

value (String, Raw, or B,4 depending on type) [in]

The data to write to the named item.

status (F,6) [out]

0 for success, else error code.


Read

Read is used to read a single value from the Registry.

xcall MIAMEX, MX_REGISTRY, REGOP_READ, hkey, name, type, value, status

Parameters

hkey, name

must be set as in opcode 3 (Set)

type (Num) [out]

is ignored on input, and is updated by the call to indicate the data type of the value returned (see table of data types under Set).

value (String, Raw, or b,4 depending on the type of the data) [out]

returns the data. Note that the application is expected to either know the type of data, in which case it can supply an appropriate form of value, or it can use the overlay technique and then extract the data based on the returned type field. Also note that for string data, value must be large enough to include the trailing null. For example, you might map value as:

MAP1 VALUEX,X,512

MAP1 VALUE$,S,,512,@VALUEX

MAP1 VALUE,B,4,@VALUEX

status (F,6) [out]

0 for success, else error code.


Enumerate keys

This is used to list the subkeys of the opened key.

xcall MIAMEX, MX_REGISTRY, REGOP_ENUMKEYS, hkey, subkey, index, status

Parameters

hkey [in]

must be set as in opcode 3 (Set)

subkey (String) [out]

will return the subkey name.

index (Num) [in]

should be set to 0 for the first subkey, and incremented for each subsequent subkey. There is no particular order to the subkeys, so do not put any special significance on index.

status (F,6) [out]

0 for success, else error code. Error 259 indicates that there are no more keys to enumerate.


Enumerate values

This is used to list the named values for the opened key.

xcall MIAMEX, MX_REGISTRY, REGOP_ENUMVALS, hkey, name, index, type, value, status

Parameters

hkey [in]

must be set as in opcode 3 (Set)

index (Num) [in]

should be set to 0 for the first value, and incremented for each subsequent value. There is no particular order to the values, so do not put any special significance on index.

name (String) [out]

will return the value name corresponding to index.

type (Num) [out]

will return the type of the value (see types under Set).

value (type depends on type) [out]

will return the value of the named item. See Read for notes on how to map it to support multiple types.

status (F,6) [out]

0 for success, else error code. Error 259 indicates that there are no more values to enumerate.


Close

This function is used to close a handle previously opened.

xcall MIAMEX, MX_REGISTRY, REGOP_CLOSE, hkey, status

hkey [in]

must be set to the handle of the key to close (as returned in HKEY2 by the open or create operations).

status (F,6) [out]

0 for success, else error.


Delete Key

Added October 2008

This function deletes a registry key. It was was added to A-Shell in build 1127 of 12 October 2008.

xcall MIAMEX, MX_REGISTRY, REGOP_DELKEY, hkey, subkey, rights, status

hkey (B,4) [in]

must specify an open registry handle returned from a previous REGOP_OPEN operation (or may be one of the built-in hive handles, e.g., HKEY_CURRENT_USER, etc.) Note that to delete a key, the the RGKEY_DELETE (&h00010000) access right must have been specified in the REGOP_OPEN call. To delete a value, the RGKEY_SET_VALUE access right must have been specified in the open.

subkey (String) [in]

specifies the key to delete (within HKEY). All values within the key will be deleted, but if there are any nested subkeys, the operation will fail. To delete a multi-level tree, you must start from the lowest level and work up.

rights (Num) [in]

only applies when running in 64 bit Windows, in which case it can be used to select the registry view:

RGKEY_WOW64_32KEY &h0200 Delete key from 32 bit registry view

RGKEY_WOW64_64KEY &h0100 Delete key from 64 bit registry view

status (F,6) [out]

returns 0 for success, else an error code.


Delete Value

Added October 2008

xcall MIAMEX, MX_REGISTRY, REGOP_DELVALUE, hkey, name, status

This function deletes the value of a key.

hkey (B,4) [in]

must specify an open registry handle returned from a previous REGOP_OPEN operation (or may be one of the built-in hive handles, e.g., HKEY_CURRENT_USER, etc.) Note that to delete a key, the the RGKEY_DELETE (&h00010000) access right must have been specified in the REGOP_OPEN call. To delete a value, the RGKEY_SET_VALUE access right must have been specified in the open.

name (String) [in]

specifies the name of a value to delete.

status (F,6) [out]

returns 0 for success, else an error code.

History

2008 October, A-Shell 5.1.1127: Function added to A-Shell.


Replace Null Delimiters

This is not a function but an option which can be added to the Set, Read, and Enumerate values functions to simplify the handling of the REG_MULTI_SZ data type. Without this option, in order to parse a list of strings containing embedded null bytes, you need to overlay the string variable on an unformatted variable and then use substring referencing to locate the null bytes and access the substrings between the null bytes. When the REGOP_DELIMS flag is added to, say, REGOP_ENUMVALS, then the embedded nulls are replaced by CHR(128) characters. Such a list of strings can then be parsed with code similar to the following (excerpted from the sample program REGPTR) which lists the individual bin names available for a printer.

! enumerate next value . . .

xcall MIAMEX, MX_REGISTRY, REGOP_ENUMVALS + REGOP_DELIMS, HKEYNEW, SUBKEY, INDEX, TYPE, V$, STATUS

! if no error, and value is printBinNames and of REG_MULTI_SZ type, parse it out

If STATUS=0 and SUBKEY="printBinNames" and TYPE=REG_MULTI_SZ then

X = 1

Y = 1

do while Y > 0

Y = instr(X,V$,chr(128))

if Y > 0 THEN

BIN$ = V$[X,Y-1]

X = Y + 1

Print "BIN Name = ";BIN$

endif

Loop

endif


MIAMEX 141: Set Parent Control

Updated February 2014; see History

See History.

xcall MIAMEX, MX_AUTOPARENT, ctrlid

MX_AUTOPARENT allows you to set the default parent control, to apply to subsequent TPRINT/DPRINT and Tab(-1,9) and Tab(-1,10) commands.

Although you can accomplish the same result using the AUI_CONTROL functions and specifying the parent control explicitly, the MX_AUTOPARENT function greatly simplifies dialog coding by allowing you to use the much simpler TPRINT, DPRINT, and Tab(-1,9-10) commands. This is particularly true if SET AUTOTPRINT is used to interpret existing PRINT statements as if they were TPRINT statements.

MX_AUTOPARENT can be used to set the parent to a group box (rather than a dialog), but in this case, only the TPRINT and DPRINT commands are affected.

You should clear the auto parent setting when no longer needed, by calling the routine with ctrlid set to 0. It will also be cleared automatically at the start of a new RUN program.

See the Tab(-10,x) Function Listing for an equivalent Print Tab command (AG_AUTOPARENT).

History

2014 February, A-Shell 6.1.1375: MX_AUTOPARENT TAB(-1,0) now confined to deleting just the children of the auto-parent dialog. Note that the auto-parent dialog setting is normally cleared at the start of each new program, so this change will typically not affect XY=0 but is designed mainly to make it easier to execute existing RUN programs within a dialog. See new AMOS.SBR +8 flag added in 1374.0 for a related feature.

2014 February, A-Shell 6.1.1374: Add support for current and new auto parent. See two Update Notes below.

2004 December, A-Shell 4.9.909: Routine added to A-Shell

Update Note: 6.1.1374 Update A

MX_AUTOPARENT now supports an option to return the current auto parent. New syntax:

xcall MX_AUTOPARENT, newctlid {,oldctlid}

To retrieve the current setting without changing it, specify a literal null string for newctlid, e.g.

xcall MX_AUTOPARENT, "", oldctlid

In the ATE environment, the feature requires that both the server and client be at least at edit 1374. Otherwise, the oldctlid will be returned as -99.

Update Note: 6.1.1374 Update B

AG_AUTOPARENT now returns the current auto parent, in numeric form, as well as the new one.

? tab(-10,AG_AUTOPARENT);newctlid$,1;chr(127);

input "",newctlid,oldctlid

Note that the newctlid$ specified by the application may be alphanumeric, while both the returned newctlid and oldctlid will be numeric.

Older ATE clients will only return the newctlid value, thus if you are depending on it, you should either verify the ATE edit level, or use the MX_AUTOPARENT version, which will return -99 if either the server or client doesn't support it.

Older programs unaware of the new feature shouldn't be affected, since the return value has always been numeric. The value of "n1,n2" is the same as the value of "n1".


MIAMEX 143: Get/set INFLD Default TYPEs

Updated October 2009

xcall MIAMEX, MX_INFDEF, opcode, defcodes

Retrieves or sets the INFLD default TYPE codes. These may be initially set by the SBR=INFDEF statement in the miame.ini, and may also be updated or queried by the SET INFDEF command.

opcode (Num) [in]

is 0 to retrieve the current SBR=INFDEF: codes into defcodes, and 1 to make the contents of defcodes be the new default INFLD codes.

defcodes (String) [in]

receives or supplies default INFLD TYPE codes, based on opcode.


MIAMEX 144: Get/set DEBUG Control Variable

xcall MIAMEX, MX_DEBUG, opcode, dbgflg

MX_DEBUG queries or sets the DEBUG control variable.

Parameters

opcode [in, numeric]

Operation: 0=retrieve the current value of the system variable DEBUG (into the ordinary variable DBGFLG); 1=set it.

dbgflg [in/out, numeric]

For opcode 0, returns the current value of the DEBUG control variable. For opcode 1, supplies the new value you want to set.

Comments

The DEBUG control variable is useful for embedding debugging code into applications that can be enabled or disabled without modifying the programs. Other ways to modify the variable are via the SET DEBUG command or by compiling with the /DEBUG compile switch. Ways to use the variable within a program include:

IF DEBUG THEN …

IF DEBUG > N THEN …

DEBUG.OPEN ! open debug message window (if DEBUG variable set)

DEBUG.PRINT msg ! output msg to debug window (if DEBUG variable set)

DEBUG.PAUSE msg ! output msg and wait (if DEBUG variable set)

DEBUG.CLOSE ! close debug message window (if DEBUG variable set)

See the Event Tracing for more information on the debug message window.


MIAMEX 146: Get Last Line Number

xcall MIAMEX, MX_LASTLNO, lineno

MX_LASTLNO allows you to find out the last line number executed in the current program. This is similar to the err(1) function in an error trap except it does not require that an error occur.

History

2005 May, A-Shell 4.9.931: Routine added to A-Shell


MIAMEX 147: Count Lines in File

xcall MIAMEX, MX_FLINES, channel, lines {,linelen, slinelen}

MX_FLINES allows you to quickly count the number of lines in a sequential file, and also determine the length of the longest line either with or without trailing spaces.

Parameters

channel (Num) [in]

must be set to the file channel number of a file open for sequential input.

lines (Num) [out]

returns the number of lines in the file. A negative number indicates an error (-1 means the file channel was invalid, -x indicates that system error x occurred while reading the file.)

linelen (Num) [out] optional

returns the length of the longest line in the file (including trailing spaces plus one for the trailing terminator).

slinelen (Num) [out] optional

returns the length of the longest line in the file excluding any trailing unprintable characters (such as spaces, tabs, CR, LF, etc.)

The file is left open, with the file cursor set to the beginning of the file.

History

2005 May, A-Shell 4.9.931: Routine added to A-Shell


MIAMEX 148: Calculate String Length or Height

xcall MIAMEX, MX_GDICALC, opcode, handle, status {,params}

(Windows/ATE) MX_GDICALC performs various calculations on the length and/or height of a string as it will appear when printed. In the case of a rectangle, it will also break the string into two parts, the first of which will fit within the rectangle, the remainder of which will be printed in another space or on the next page.

Parameters

opcode (Num) [in]

Symbol | Value | Description
MXGDI_OPENPTR | 1 | Open a printer device context
MXGDI_SETFONT | 2 | Choose font
MXGDI_CALCRECT | 3 | Calculate rectangular text metrics
MXGDI_CALCLEN | 4 | Calculate string length
MXGDI_CLOSEPTR | 5 | Close printer context. This must be done BEFORE printing to it. Syntax: xcall MIAMEX, MX_GDICALC, MXGDI_CLOSEPTR, handle, status
MXGDI_CALCRECTX | 6 | Calculate rectangular XTEXT metrics
Definition file: ashell.def

handle (B,4) [in/out]

The handle variable is returned by the open operation (opcode 1) and must be specified to all the others.

status (F,6) [out]

This will be returned from each operation, with 0=success. All others are errors, with the most typical being:

MX_GDICALC Status Codes

See the sample program MMOGDI.BP and the updated sample text file TSTGDI.TXT in the EXLIB for examples of using MX_GDICALC and /TEXTRECTANGLE.

History

2011 August, A-Shell 5.1.1229: Several bug fixes and documentation revisions.

2008 August, A-Shell 5.1.1121: Support added for the font width parameter.

2005 May, A-Shell 4.9.932: Routine added to A-Shell.


Open

xcall MIAMEX, MX_GDICALC, MXGDI_OPENPTR, handle, status, printer, mapmode {,length, width}

Establishes a printer context, returning a handle to it which must be passed to all the other MX_GDICALC operations.

Parameter | Type | I/O | Description
handle | B,4 | in/out | Name to be used for other MX_GDICALC operations.
status | F,6 | out | MX_GDICALC Status Codes.
printer | String | in | Any form of printer name allowed by SPOOL.SBR—e.g. a null string for the A-Shell or Windows default; a printer init file name, a printer share name, or a printer local driver name.
mapmode | String | in | One of the map modes allowed in the GDI //SETMAPMODE statement (LOENGLISH, HIENGLISH, LOMETRIC, HIMETRIC, TEXT, TWIPS, DECIPOINTS).
length, width | Num | out | If specified, the page length/width (in the specified map mode units) will be returned here.


Choose font

xcall MIAMEX, MX_GDICALC, MXGDI_SETFONT, handle, status, pointsz, {,face, pitchfam, charset, weight, style, rotation, width}

Establishes the font to be used for the various CALCxxx operations to follow. All of the parameters below are the same as those used by the GDI printing directive SETFONT.

Parameter | Type | I/O | Description
handle | B,4 | in | Device context handle (from MXGDI_OPEN)
status | F,6 | out | MX_GDICALC Status Codes.
pointsz | Num | in | Font height in tenths of points.
face | String | in | Font face name. If not specified, the Windows default font face for the specified printer will be used.
pitchfam | Num | in | Font pitch and family characteristics. If not specified, will be determined by the natural characteristics of the font face.
charset | Num | in | Character set indicator. If not specified, the default character set for the font determined by the other parameters will be used.
weight | Num | in | Symbolic code for the desired weight of the font. If not specified, the default weight is used.
style | Num | in | Flags for italic (+1), underline (+2), and strikeout (+4)
rotation | Num | in | Rotation in degrees; positive for clockwise.
width | Num | in | Font character width specification. Normally the font width is a function of the height and the font style, but you can squeeze or stretch it using this option. Units, if positive, are the same as that for height (tenths of points); if negative, indicates the number of characters that will fit on a line across the page (not the rectangle). Mainly applicable only for fixed pitch fonts.


Calculate rectangular text metrics

xcall MIAMEX, MX_GDICALC, MXGDI_CALCRECT, handle, status, lft, top, rght, btm, memo, height, overflow {,flags}

This operation calculates how much text will fit in a specified rectangle, based on the current printer context and font.

Parameter | Type | I/O | Description
handle | B,4 | in | Device context handle (from MXGDI_OPEN)
status | F,6 | out | MX_GDICALC Status Codes.
lft,top, rght,btm | Num | in | Coordinates of the rectangle, in the units specified by mapmode when the printer device context was established.
memo | String | in/out | On input, specifies the text we want to output within the rectangle. On return, it contains the amount of the original text that actually fits in the rectangle.
height | Num | out | If memo fits entirely within the rectangle, height returns the rectangle height actually required (which may be less than the full rectangle height). Otherwise, it will return the height of the rectangle.
overflow | String | out | Returns the trailing portion of memo which does not fit within the rectangle. If it all fits, then a null string is returned here. Note that this operation supports a dynamic string (S,0).
flags | Num | in | Returns the size of the rectangle necessary to print the specified memo text completely.

Comments

The vertical spacing used for the calculation is the natural vertical spacing for the current font and printer device context. To make sure you get the same spacing when actually printing, use the GDI printing directive //RESETLPP after the //SETFONT and before the //TEXTRECTANGLE. The vertical spacing is not automatically reset by //SETFONT.

If memo must be wrapped to multiple lines to fit within the rectangle, standard word-wrapping logic will be used to avoid breaking lines mid-word. Embedded CRLFs are also respected.

You can use this operation iteratively (changing the font size incrementally each time) to determine the optimum font size for the specified memo text to fit within the rectangle.

A test program, GDICALC.BP, is available in the EXLIB [908,37] to illustrate this kind of logic.

Note that MXGDI_CALCRECT assumes vertical spacing optimum for the font, i.e. as if a //RESETLPP command had been executed after the //SETFONT. If you don't do this in the actual GDI print file, the spacing for the print operation may not match that used for the calculations.

Subtopics

flags


flags

The optional flags parameter returns the size of the rectangle necessary to print the specified memo text completely, rather than returning the portion of the string that will fit.

In this case, the rght and btm parameters are also returned, indicating the adjusted rectangle dimensions required for printing the memo string. For single line memos (TRF_SINGLELINE set, or TRF_WORDBREAK not set and no CRLFs in the line), the width of the rectangle will be adjusted to fit the text. Otherwise, if TRF_WORDBREAK is specified, it will preserve the width of the rectangle, breaking the lines as needed to fit within that width, and adjusting the height of the rectangle.

Formatting options for flags are chosen from the TRF_xxx flags used by //TEXTRECTANGLE (reprinted below), with the mandatory inclusion of the TRF_CALCRECT bit.

Flag | Value | Meaning
TRF_TOP | &h00000000 | top justification
TRF_LEFT | &h00000000 | left justification
TRF_HCENTER | &h00000001 | horizontal centering
TRF_RIGHT | &h00000002 | right justification
TRF_VCENTER | &h00000004 | vertical centering
TRF_BOTTOM | &h00000008 | bottom justification
TRF_WORDBREAK | &h00000010 | wrap the text onto multiple lines
TRF_SINGLELINE | &h00000020 | output text as a single line
TRF_EXPANDTABS | &h00000040 | expand tabs (8 spaces each)
TRF_NOCLIP | &h00000100 | no clipping
TRF_EXTERNALLEADING | &h00000200 | incl. ext. leading in spacing
TRF_CALCRECT | &h00000400 | calc only (use with MX_GDICALC)
TRF_PATH_ELLIPSIS | &h00004000 | path ellipsis
TRF_END_ELLIPSIS | &h00008000 | end ellipsis
TRF_WORD_ELLIPSIS | &h00040000 | word ellipsis
Definition file: ashell.def


Calculate string length

xcall MIAMEX, MX_GDICALC, MXGDI_CALCLEN, handle, status, memo, length

The MXGDI_CALCLEN operation is similar to MXGDI_CALCRECT, except that it just determines how long the string will be when printed—i.e. does not consider the possibility of wrapping it to multiple lines.

Parameter | Type | I/O | Description
handle | B,4 | in | Device context handle (from MXGDI_OPEN)
status | F,6 | out | MX_GDICALC Status Codes.
memo | String | in | Text string to consider. Should not contain any CRLF characters.
length | Num | out | Returns the length (i.e. width) required to print memo text in the current font and device context, in the mapmode units specified in the MXGDI_OPEN operation.


Calculate rectangular XTEXT metrics

xcall MIAMEX, MX_GDICALC, MXGDI_CALCRECTX, handle, status, lft, top, rght, btm, file, height, offset

This is used to calculated the XTEXT metrics required for use with the GDI print command //XTEXT, and is essentially the same as the existing MXGDI_CALCRECT (opcode 3) except:

• The memo argument in MXGDI_CALCRECT is replaced here by file, which specifies the filespec of the text file to analyze.

• The overflow argument in MXGDI_CALCRECT is replaced here by offset, which indicates the offset within the file. On input, it is the starting offset (default 0). On output, it will be 0 if the entire file fits within the specified rectangle. Otherwise, it will be the offset to the first character that did not fit (which can then be passed to a subsequent MX_GDICALC call).

• Note that unlike MXGDI_CALCRECT, where the font and other spacing factors must be set in advance (via MX_GDICALC opcode 2), with XTEXT printing, the font and other layout parameters are set within the text file (particularly in the case of RTF files).

The MMOGDI sample program in [908,37] of the EXLIB illustrates the use of //XTEXT and MX_GDICALC, MXGDI_CALCRECTX

This function also works in ATE. As with XTEXT.SBR, a file resident on the server will be transferred to ATECACHEDIR on PC. Since the use of MXGDI_CALCRECTX implies that this will happen multiple times per file printed, you might want to optimize the operation, if you are doing it on a lot of files, by pre-transferring the files to the ATECACHEDIR and then referencing the filespec as "%ATECACHEDIR%\xxxxxx.yyy".


MIAMEX 149: Get/set A-Shell GUI Settings

Updated 2010 August

Get or set values:

xcall MIAMEX, MX_WINSETTINGS, opcode, id, value

Save settings file:

xcall MIAMEX, MX_WINSETTINGS, opcode, file, status

Load settings file:

xcall MIAMEX, MX_WINSETTINGS, opcode, file, file2

(ATE/Windows) MX_WINSETTINGS is used to get or set a number of options associated with the Misc Settings and Dialog Sizing dialogs. Set opcode to 0 to retrieve a value or 1 to set it. The ID codes and associated range of values are shown below. Note that the AWS_xxx symbols have been added to ashell.def.

Parameters

opcode (Num) [in]

0 to retrieve a value, 1 to set a value (first syntax above); 2 to save the current values to disk (second syntax above); 3 to load a new set of values from disk (third syntax above)

When used with id 0, returns a comma-delimited string of all the available values. This is much faster than retrieving each value one at a time over ATE, where there could be a several ms latency for each command/response turnaround. Note that the comma-delimited string will have a place for each setting by ID value, from 1 to the maximum ID.

id (Num) [in]

Identifies the item for which the corresponding value will be set or retrieved. The choices for id are listed in the Symbol column in the following table.

value (Num or String) [in/out]

Specifies the value to set (if opcode=1) or returns the value being retrieved (if opcode=0). The data type should correspond to the type of the associated item. Most items are numeric integers, except for the font name values. For items that correspond to on/off options (checkboxes in the Misc. Settings Dialog), 1=on (checked), 0=off (unchecked).

file (String) [in]

For opcodes 2 and 3, file specifies the full or partial filespec of the settings file to save to or load from. If null, the current default filespec is used.

file2 (String) [out]

For opcode 3, file2 returns the fully qualified settings file name (possibly useful if file left blank or partial, or if the file referenced by file was not present and a different settings file from the search order was specified.) See the File > Save dialog for information about the search order for settings files.

status (Num) [out]

For opcode 2, returns 0 if the save operation was a success, -15 if ATE fails to respond in a reasonable time.

ID Values

Symbol | Value | Type | Description
AWS_LEADING | 1 | Numeric | Leading (pixels between rows)
AWS_LEADCLR | 2 | Numeric | Leading color fill (color number or -1,-2) AWS_LEADCLR_AUTO (-1) AWS_LEADCLR_PASSIVE (-2)
AWS_FONTSCALE | 3 | Numeric | Font scale factor
AWS_MINMAXMARGIN | 4 | Numeric | Minimum margin when maximized
AWS_FIXEDPITCHEDIT | 5 | Numeric | Use fixed pitch in edit boxes (1=on, 0=off)
AWS_WININFCLR | 6 | Numeric | Use std Windows colors in edit boxes (1=on, 0=off)
AWS_EDITLEADING | 7 | Numeric | Extend edit boxes into leading area (1=on, 0=off)
AWS_CBEDITMATCH | 8 | Numeric | Set edit boxes to combo height (1=on, 0=off)
AWS_DLGGRIDBASIS | 9 | Numeric | Dialog size based on... AWS_DLGGRIDBASIS_FONTSIZE (0) AWS_DLGGRIDBASIS_WINDOWSIZE (1) AWS_DLGGRIDBASIS_PROGCTL (2)
AWS_DLGGRIDHEIGHT | 10 | Numeric | Dialog grid height (% of font size)
AWS_DLGGRIDWIDTH | 11 | Numeric | Dialog grid width (% of font size)
AWS_BEEPCODE | 12 | Numeric | Default beep sound with char(7): AWS_BEEPCODE_DEFAULT (0) AWS_BEEPCODE_HAND (16) AWS_BEEPCODE_QUESTION (32) AWS_BEEPCODE_EXCLAM (48) AWS_BEEPCODE_ASTERISK (64)
AWS_DLGFONTSCALE | 13 | Numeric | ALTPOS dialog font scale
AWS_DLGCAPTINC | 14 | Numeric | Include caption in dialog height (1=on, 0=off)
AWS_WININFBGC | 15 | Numeric | RGB background color for active edits
AWS_FONTFACE | 16 | String | A-Shell fixed pitch font
AWS_GUI_FONTFACE | 17 | String | A-Shell GUI font (blank for Windows default)
AWS_CHARSET | 20 | Numeric | Sets and retrieves the current display character set. Valid choices are 0 for ANSI and 255 for OEM. Note that the character set is usually established in the miame.ini (default is OEM) with the FONT=fontname,charset command. Once set, changing fonts doesn't usually change the character set.
AWS_XTR_FONTFACE | 21 | String | XTREE default font
Definition file: ashell.def

Examples

To change the default beep code to the system "asterisk" sound:

xcall MIAMEX, MX_WINSETTINGS, 1, AWS_BEEPCODE, AWS_BEEPCODE_ASTERISK

To re-load the settings from the current settings file (returning the full filespec of that file in FSPEC2$):

xcall MIAMEX, MX_WINSETTINGS, 3, "", FSPEC2$

To save the current (possibly updated) settings to the specified file:

xcall MIAMEX, MX_WINSETTINGS, 2, "%MIAME%\new.ash"", status

Notes

All of the options listed above, other than beepcode, may be set via the dialogs directly. In the case of the beepcode, the command changes the code that is used when a chr(7) is output, but you can still determine what waveform is associated with that code in the Windows Control panel Sounds applet.

Also note even though the beepcode may not be seen or edited in the dialogs, it is still saved and retrieved along with the other settings (File > Save).

History

2010 July, A-Shell 5.1.1188: Added AWS_XTR_FONTFACE.

2005 September, A-Shell 4.9.940: Added routine to A-Shell.


MIAMEX 153: Set/release Keyboard Hold

Updated May 2013

xcall MIAMEX, MX_RELEASEKBD {,opcode, text}

opcode (Num) [in]xe "MX_RELEASEKBD"

opcode | Description
0 or omitted | causes the keyboard hold to be released, provided it hasn't been locked (see AG_HOLDKBD)
1 | causes the keyboard hold to be set, and optionally passes the contents of text to ATE to be reprocessed as type-ahead.
2 | clears the keyboard hold, even if it has been locked.

History

2013 May, A-Shell 6.1.1352: Opcode 2 added

2005 November, A-Shell 4.9.946: Introduced a new and improved internal protocol for communications between the application and GUI front-end. One aspect of this new protocol involved setting and releasing keyboard holds so that keyboard input and GUI command responses did not get mixed together. MIAMEX 153 is used to control that keyboard hold. The application programmer will, under normal circumstances, never need this command, since A-Shell should take care of it automatically. It is nonetheless documented and made available for programmer use in case of some as-yet-unforeseen situation.


MIAMEX 154: Set 3D Tab Attributes

Updated June 2012

xcall MIAMEX, MX_DEFTABXYZ, sts, Z, fgc, bgc, ptype, fontattr, fontscale, fontface, , flags}

MX_DEFTABXYZ 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$.

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.

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.

Z (Integer, 1-19)

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 color. You may also specify RGB values.

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 text 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 cannot 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 DPRINT or EPRINT styles.

Beginning with A-Shell build 1175 of February 2010, valid ptype codes include the following:

Value | Meaning
T[ | like TL but shrinks control to just fit the text
T] | like T[ but right justified
D[ | like DL but shrinks control to just fit the text
D] | like DR but right justified

fontattr, fontscale, fontface

font attributes, scale factor, and font name, as in the AUI_CONTROL call.

flags (Num) [in]

may specify zero or more of the following options:

Flag | Value | Description
TBZF_AUTONUMKBD | &h0001 | TBZF_AUTONUMKBD will automatically assign a click string equal to the numeric value at the start of the string. Requires that ptype be set to one of the GUI options (tprint
TBZF_AUTOCR | &h0002 | TBZF_AUTOCR may be combined with TBZF_AUTONUMKBD to append a chr(13) to the numeric click string
TBZF_AUTOFKY100 | &h0004 | TBZF_AUTOFKY100 is similar to TBZF_AUTONUMKBD except that instead of sending the numeric digits as the click string
TBZF_HIDENUM | &h0008 | TBZF_HIDENUM may be added to any of the above to strip off the leading number before displaying the text. For example
TBZF_LINKTOLBL | &h0010 | Causes the control (created via Tab(x,y,z)) to be assigned the same click string as the control (presumably the label) immediately to the left of the newly created control. As an example, if you used Z=1 for labels (with the TBZF_AUTOFKY100 bit set), and Z=2 for data fields (with the TBZF_LINKTOLBL bit set), the following would result in both labels and data fields sending EXITCODE -1## (## matches the label numeric prefix) on click: ? tab(4,10,1);"1. Name"; ? tab(5,10,1)'"2. Address:"; ... ? tab(4,40,2);NAME$ ? tab(5,10,1);ADDR$ ...
Definition file: ashell.def

Comments

If the default maximum 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.

Once the 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.

See Also

Three-D Print Tab

History

2012 June, A-Shell 6.0.1251: Added flags argument


MIAMEX 156: Return Instance Number

xcall MIAMEX, MX_INSTNUM

(Windows) MX_INSTRUM returns your "instance number." This is the count of how many A-Shell/Windows sessions are running on your PC.

History

2006 January, A-Shell 4.9.948: Routine added to A-Shell


MIAMEX 157: Find Window

xcall MIAMEX, MX_FINDWINDOW, handle, title, {class}

(Windows) MX_FINDWINDOW is used to search for a window with the specified window title and/or class and/or handle. If both class and title are blank and handle is non-zero, then it searches for the window by its window handle, returning the title and class. If both class and title are blank and handle is zero, then it returns the handle of the A-Shell window (the current modal dialog, if there is one, else the main A-Shell window).

Parameters

handle (B,4 or F) [out]

returns the window handle if the window is found (or zero if not found).

title (String) [in/out]

can be loaded with the window title (as shown on the title bar) of the window to search for.

class (String) [in/out]

can be loaded with the window class to search for. If both class and title are both non-blank, it will only locate a window matching both.

History

2009 September, A-Shell 5.1.1159: Modified to support returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized.

2006 January, A-Shell 4.9.948: Routine added to A-Shell.


MIAMEX 160: Convert hex or octal to decimal

XCALL MIAMEX, MX_GTOCT, hexoct, dec

hexoct (String) [in]

Hex or octal value to convert. Radix must match the current hex/octal mode setting; see MX_GETHEX and MX_SETHEX. In hex mode is set, the hexoct string may optionally contain prefix of "0x", "0X", or "&h". The first two are widely used hex prefixes, while the latter is the hex prefix used in A-Shell BASIC.

dec (Num) [out]

Returns the result of the conversion of hexoct to decimal.

Comments

Hex/octal conversions to/from decimal are normally performed using the wrapper functions Fn'Dec2Hex$() and Fn'Hex2Dec() in the sosfunc: directory [907,10] of the SOSLIB.

See Also

• MX_OCVT


MIAMEX 161: Get File Channel Info

Added August 2015

xcall MIAMEX, MX_FILECHINFO, ch, status, fileinfo

MX_FILECHINFO (161) returns information about an open file based on the file channel. It is similar to FILNAM.SBR but provides much more information.

Parameters

ch (Num) [in]

file channel

status (Num) [out]

returns > 0 if the file channel was located, else 0

fileinfo (ST_FILE_METADATA) [out]

returns info about the file

ST_FILE_METADAT is defined in ashinc:ashell.sdf as:

defstruct ST_FILE_METADATA ! [103] File metadata returned by MX_FILECHINFO

map2 SPEC,s,160 ! file spec, as specified in OPEN

map2 TYPE,b,1 ! see FILETYPE_xxx

map2 DRIVER,b,1 ! internal implementation code (see FILEDVR_xxx)

map2 MODE,b,2 ! see FILEMODE_xxx

map2 HOOKID,b,4 ! file hook id

map2 HOOKFLAGS,b,4 ! file hook flags

map2 HOOKEVENTS,b,4 ! file hook events

map2 RANDOM'ISAM ! fields for random and ISAM files

map3 RECSIZ,b,4 ! record size (according to open; true size for ISAM)

map3 BLKFCT,b,2 ! 0=spanblocks

map3 RECCNT,b,4 ! # records (does not apply to ISAMA)

map3 ISAMA ! ISAM-A only

map4 INDEX,b,2 ! selected index #

map4 ISFIND,i,2 ! result of last FIND # - see ISFIND_xxx

map4 ISLOCK,b,4 ! current locked recno

map4 LASTRECNUM,b,4 ! last rec #

map2 SEQ ! fields for sequential files

map3 SPOS,f,8 ! stream pos (0=start, -1=eof)

map3 ISEQ ! input files only

map4 CSVDELIM,s,2 ! CSV delimiter

map3 OSEQ ! output files only

map4 OPOS,b,4 ! output column position

map4 LINENO,b,4 ! line # for cur pg - same as .LINENO(ch)

map4 PAGENO,B,4 ! page # - same as .PAGENO(ch)

endstruct

Comments

If you call the function in a version of A-Shell less than 6.1.1416, you may not get an error status, but the contents of the structure will be empty.

History

2015 August, A-Shell 6.1.1415: Function added to A-Shell


MIAMEX 163: Change Memory Module Flags

xcall MIAMEX, MX_SETMEMFLAGS, idx, flags

MX_SETMEMFLAGS is used to change the flags for a memory module.

Parameters

idx (Num) [in]

should be set to 0 to reference the memory module for the currently running program or subroutine, or else it can specify the module previous located in a call to MX_USRMAP.

flags (Num) [in]

are the new flags (overriding the previous ones). If you just want to turn on or off a particular flag but leave existing flags alone, you should first retrieve the existing flags using the MX_USRMAP call.

Comments

If you want to use this call within an SBX to cause the SBX to be deleted from memory on exit (instead of being retained as part of the normal caching scheme), then set FLAGS = USRMEM_INUSE (1). If you do not have that flag set, the module could be deleted by a subsequent memory operation even while the program is running, which would be bad.

History

2006 August, A-Shell 4.9.963: Routine added to A-Shell


MIAMEX 164: Display Color Selection Dialog

xcall MIAMEX, MX_CHOOSECOLOR, rgb, status

MX_CHOOSECOLOR displays the color selection dialog and return the selected RGB value.

Parameters

rgb (B,4 or F,6) [in/out]

The RGB color value. On input, it determines the default color selected in the dialog; on output it returns the newly selected color.

status (F) [out]

is 0 for OK, or else indicates an error. Executing this function in a non-GUI environment should return -1.

History

2006 August, A-Shell 4.9.964: Routine added to A-Shell.


MIAMEX 165: Display Font Selection Dialog

xcall MIAMEX, MX_CHOOSEFONT, font$, status

MX_CHOOSEFONT displays the font selection dialog and return the selected font name.

Parameters

font$ (String, 32+) [in/out]

name of font. On input, it determines the default font selected in the dialog; on output it returns the newly selected font.

status (F) [out]

is 0 for OK, or else indicates an error. Executing this function in a non-GUI environment should return -1.

History

2006 August, A-Shell 4.9.964: Routine added to A-Shell


MIAMEX 167: Verify File Information

xcall MIAMEX, MX_VERINODE, status, ch1 {,ch2...,chn}

(UNIX) MX_VERINODE is used for verifying at runtime that a set of open files matches the directory entries for those files.

Parameters

status

returns zero if all the specified channels are valid; else it returns less than zero for a system error or else the channel number of the first file in the list that doesn't match its directory entry.

Background

Under UNIX, it is possible to use the mv command to rename a file even if it is in use. This is because mv is thought of as merely a directory operation, whereas file operations all use the inode rather than the name entry in the directory. Since renaming a file doesn't change its inode, it doesn't affect files that are currently operating on the inode. Once the file is renamed, you can then create or copy a new file whose name matches the original name. That still doesn't affect processes with the file open, since the new file will have a different inode and thus isn't really in conflict with any existing processes using the old file. However, that could cause problems for the application if two sets of users are operating on different copies of the file, thinking that they are the same copy.

MX_VERINODE can be used to make sure that the open file(s) still match the directory entries for those files. Note that it only works under UNIX (Windows doesn't use inodes and this situation wouldn't arise there), and it only currently works for random and ISAM-A (DISAM) files.

History

2006 October, A-Shell 4.9.968: Routine added to A-Shell


MIAMEX 169: Set/Overrride User Name

xcall MIAMEX, MX_SETUSRNAM, usrnam$

MX_SETUSRNAM overrides the user name using the syntax:

Normally the user name is retrieved from the operating system when needed. In most cases, that is best. However, there are two cases where it might not be:

• If, for some unfathomable reason you allow all users to login to the operating system with a common user login name, then displaying or retrieving that name in utilities such as SYSTAT (or the ashlog.log) isn't very useful. Usually, the excuse for allowing users to share an operating system login name is that you have a separate login process for the application. If this is the case, then you can now use MX_SETUSRNAM so that the application user name replaces the original operating system login name in SYSTAT and other A-Shell purposes.

• In the case of ATSD, you don't have any control over the operating system login name on the server, although as of this edit, that is now being over-ridden automatically by the username used to initiate the ATE client.

Notes

Over-riding the user name does not fool the operating system. It only affects A-Shell routines that would otherwise retrieve or use the login name.

To reset the user name (back to the original), you can xcall MX_SETUSRNAM with USRNAM$ argument of "".


MIAMEX 170: Select Windows Folder

Updated February 2011

xcall MIAMEX, MX_BROWSEFOLDER, folder, rootID, title, flags

Displays a standard Windows dialog allowing you to browse for and select a folder or other non-file object (such as a computer or device). This operation can only take place on a GUI-enabled client, either ATE or some form of A-Shell/Windows.

Note that if the initial path or directory is in the form of a drive letter and colon with no trailing slash (e.g. "C:"), MX_BROWSEFOLDER automatically appends "\" to avoid confusion. (Such ambiguous specs are otherwise likely to be misinterpreted by A-Shell and/or Windows.)

Parameters

folder (String) [in/out]

returns the selected folder (or null if user cancelled). On input specifies the default folder. Note even when the RootID parameter is specified, this default folder specification must be absolute (i.e. not relative to the RootID). But it must specify a folder on or below that RootID folder.

rootID (Num) [in]

specifies a root folder, above which the user would not be able to navigate, using the standard CSIDL_xxx identifiers.

title (String) [in]

specifies the title message which appears in the dialog box. There is room for 2 or 3 lines of text, which will be auto-wrapped as needed.

flags (Num)

Flag | Value | Description
BIF_RETURNONLYFSDIRS | &h0001 | Return only file system folders
BIF_DONTGOBELOWDOMAIN | &h0002 | Don't include network folders below the domain level
BIF_RETURNFSANCESTORS | &h0008 | Only return file system ancestors
BIF_EDITBOX | &h0010 | Include an edit control in the dialog to allow user to type a path
BIF_VALIDATE | &h0020 | Don't allow user to type an invalid name in the edit box
BIF_NEWDIALOGSTYLE | &h0040 | New style of dialog; offers several enhancements over original style (resizing, drag/drop, new folder button, delete, etc.)
BIF_USENEWUI | &h0050 | Combination of BIF_NEWDIALOGSTYLE and BIF_EDITBOX
BIF_BROWSEINCLUDEURLS | &h0080 | Allow display of URLs (requires BIF_USERNEWUI + BIF_BROWSEINCLUDEFILES)
BIF_UAHINT | &h0100 | With BIF_NEWDIALOGSTYLE and not BIF_EDITBOX, displays a standard hint to the user in place of the edit box.
BIF_NONEWFOLDERBUTTON | &h0200 | Eliminates the "New Folder" button
BIF_KBDLOCKLATETARGETS | &h0400 | Don't traverse target as shortcut
BIF_BROWSEFORCOMPUTER | &h1000 | Only allow selection of computers
BIF_BROWSEFORPRINTER | &h2000 | Only allow selection of printers. Automatically sets the RootID to CSIDL_PRINTERS unless RootID is already non-zero.
BIF_BROWSEINCLUDEFILES | &h4000 | Dialog displays files as well as folders
BIF_SHAREABLE | &h8000 | Dialog can display shareable resources on remote systems
Definition file: ashell.def

See Also

• Tab(-10,x) Function Listing for an equivalent Print Tab command (AG_BROWSEFOLDER).

• MX_GETOFD (browse for an select files)

• The MIAMEX.BP sample program in [908,30] of the EXLIB for an example of this function.

History

2009 October, A-Shell 5.1.1164: Append "\" when needed.

2008 April, A-Shell 5.1.1107: Routine added to A-Shell.


MIAMEX 171: Retrieve Directory Path

Updated and reviewed July 2011

xcall MIAMEX, MX_GETSHELLPATH, csidl, folder {,clisvr}

MX_GETSHELLPATH is used for retrieving the actual directory path for a specified Windows directory ID using the CSIDL_xxx values.

Parameters

csidl (Num) [in]

numeric ID of the logical directory, using its standard CSIDL_xxx identifiers.

folder (String) [out]

returns the physical directory path name corresponding to csidl.

clisvr (String) [in]

may be set to "S" (for server), or "L" (for local, which is the same as server in this context); anything else is treated as meaning "client". The option only has significance in the ATSD environment where the possibility exists of performing the function relative to the ATSD server or the client. In all other cases, the parameter is ignored and the operation is performed relative to the client, or returns an empty string if an applicable client is not present.

See Also

• MX_BROWSEFOLDER.

History

2011 July, A-Shell 5.1.1226: Add clisvr parameter.

2008 April, A-Shell 5.1.1107: Routine added to A-Shell.


MIAMEX 172: Password Encryption

Update May 2014; see History

xcall MIAMEX, MX_PWCRYPT, pwin, pwout, {mode}, {seed}, {key}

MX_PWCRYPT is used for for password encryption. It is useful for use in GDI files to avoid revealing SMTP passwords.

Modes 1 and 2

You specify pwin, the clear text version of password, and it returns pwout, the encrypted version. Note that this is a relatively simplistic password encryption mechanism known to A-Shell and ATE, which is recognized by the fact that the first character will be a chr(2). If you have a need to decrypt them, contact MicroSabio for details. We did not publish the decryption scheme because doing so would compromise what limited security the routine offers.

The optional mode argument allows you to create the original 7-bit style password encryption used by earlier versions of ATE, in addition to the newer 8-bit style. The two types of encrypted passwords can be distinguished by the first byte: chr(1) indicates type 1 (7 bit), while chr(2) indicates type 2 (8 bit).

Mode 3

Encryption mode 3 provides a stronger alternative to modes 1 and 2 for passwords and other short strings up to 44 characters in length. The encrypted strings are a convenient and uniform 68 MIME characters long, plus an ASCII 3 identifying prefix, making them easy to insert into both fixed-length data fields and text files (print files, configuration files, etc.) Based on a blowfish-class, 256-bit, seed-generated key incorporating both randomized "salt" and "pepper", it is strong enough to eliminate the need to hide them from public view.

In most of the places where A-Shell currently accepts encrypted passwords—e.g. //PDFX files, EMAILX configuration files, FTPDLX.SBR, etc—you can now specify a mode-3 encrypted password.

Also note:

• Due to the randomized salt and pepper, successive encryptions of the same password, using the same seed and key, will still generate entirely different encryption strings.

• To generate a mode 3 encryption string for //PDFX.Email.SMTP.Password, specify the SMTP.Username value as the seed and omit the key parameter. Also make sure that the SMTP.Username always appears in the print file prior to the SMTP.Password.

• Similarly, for a mode 3 encrypted password compatible with FTP2.SBR, use the FTP user name as the seed.

• For EMAILX, use the SMTP username as the seed; requires EMAILX.SBR 5.1.128.

Parameters

pwin (String) [in]

The password to encrypt or decrypt. In the case of encrypt, it should be no more than 44 characters. For decrypt, it should contain the prefix byte indicating the encrypt mode followed by the encrypted string, null terminated.

pwout (String) [out]

The encrypted or decrypted result. For encryption, the first byte will be chr(1) for mode 1, chr(2) for mode 2, or chr(3) for mode 3. (This allows generalized decryption logic to know which scheme to use.) For modes 1 and 2, the remainder of the string will equal the length of the PWIN parameter. There may be embedded control characters, but no embedded nulls.

For mode 3 encryption, the remainder of the string will consist of 68 MIME characters, regardless of the length of the CLRPW string. Accounting for the prefix and trailing null, you should allow 70 characters for storage.

mode (Num) [in]

Indicates the operation and encryption mode. For encryption, specify the desired mode (1, 2 or 3). For decryption, specify 0. Note, however, that to protect the security of encrypted strings which may be publicly visible in text files, decryption is not supported in the XCALL, except for mode 3 when you supply your own key, for which see below. If not specified, encryption method 2 will be used.

seed (String, 64) [in] (applies to mode 3 only)

Affects the way the encryption key is generated. For passwords, you may want to specify the user name as the SEED, making it that much more difficult for anyone to reverse engineer the key or otherwise break the encryption. May be blank.

key (x,32) [in] (applies to mode 3 only)

The base key used for the encryption or decryption. Note that it is not the actual encryption key; instead, it is used along with SEED and other factors to generate the actual key. It may be omitted or set to all nulls when encrypting in order to use the standard A-Shell encryption key scheme, which can be decrypted internally by A-Shell using internal defaults, allowing it to be used in most places where a password is required; see Comments below.

Note however, that while A-Shell internally knows how to construct the key needed for decryption, to protect the security of such encrypted strings, the automatic decryption capability is not exposed in the XCALL interface. If you want to use MX_PWCRYPT for encrypting and decrypting passwords within your application, you will need to use mode 3 and supply your own explicit key for both operations.

Note also that key is an unformatted 32 byte (256 bit) field, possibly containing nulls. You should use some kind of randomized algorithm to fill the 32 bytes with random values distributed across the bit space, rather than using a simple string like "rosebud".

See Also

• CRYPTO.SBR

History

2014 May, A-Shell 6.1.1385: Add mode 3.

2010 February, A-Shell 5.1.1175: Maximum length of passwords increased from 24 to 128.

2008 November, A-Shell 5.1.1130: New type parameter allows for selection of either 7- or 8-bit encryption.

2008 April, A-Shell 5.1.1124: Routine added to A-Shell.


MIAMEX 173: Create Shortcut

Updated September 2014

xcall MIAMEX, MX_SHORTCUT, target, lnkspec {, descr, workdir, icon, iconidx, status}

MX_SHORTCUT creates a shortcut, on the desktop or in any other folder.

target (String) [in]

should be set to the object or command line that the shortcut links to. Any %ENV% vars will be pre-resolved, i.e. at the time the link is created (rather than when it is clicked on). Examples:

TARGET = """%MIAME%\bin\ashw32.exe"" -i ""%MIAMEFILE% abc"""

TARGET = "http://www.microsabio.com"

TARGET = """c:\company shared folders\readme.txt"""

Note: as shown above in the first and third example, you must supply literal quotes as needed to enclose any path compoents of the target command line that may contain embedded spaces. (In the first example, we don't know if %MIAME% or %MIAMEFILE% will contain embedded spaces, so we quote them to be safe.)

lnkspec (String) [in]

should be set the full filespec of the shortcut itself. The default extension is ".lnk"; any other extension may fail to be recognized by the Explorer as a shortcut (or "Shell Link"). lnkspec does not require literal quoting even if contains embedded spaces. Example:

LNKSPEC = "C:\vm\miame\test shortcut.lnk"

Note that the filename (minus the .lnk extension and directory) will appear under the icon when in icon view, i.e. "test shortcut" in the above example.

To put the icon on the user's desktop, you can use the %USERPROFILE% environment variable, e.g.:

LNKSPEC = "%USERPROFILE%\Desktop\check this out.lnk"

For the common or "all users" desktop, use "%ALLUSERSPROFILE% instead of %USERPROFILE%, but beware that the operation may be blocked by a variety of security restrictions, and will require elevation under Vista.

See Comments, below.

descr (String) [in]

may specify a description to be embedded within the shortcut properties.

workdir (String) [in]

may specify the starting working directory for the process when the target is launched. It does not require quoting.

icon (String) [in]

may specify a separate file from which the display icon should be taken. It does not require quoting. If not specified, then the first icon of the executable associated with the target will be used. (If you want to user another icon from that executable, you must specify the module name again here.)

iconidx (Num) [in]

may specify the icon index (0,1,2,...) of the icon within the file (default is 0, the first icon). Ignored unless icon is not blank.

status (F) [out]

the return status. 0=ok. Positive numbers are Windows system error codes. (See MX_ERRNOMSG to display text). -1 indicates no GUI support available (requires Windows or ATE), and -15 indicates that ATE did not respond..

Comments

Note that any %ENV% environment variables will be resolved relative to the computer on which this function is invoked. In the case of ATE, that would be the server, whereas you probably want it to be relative to the client desktop. To solve that, you'll have to use the AG_GETENV command separately (preferably via MX_AGWRAPPER) to resolve client-specific environment variables, such as %USERPROFILE%, and then pass the resolved value.

Example

The following would work on either local A-Shell Windows or ATE to create a shortcut on the client desktop, called "test shortcut" which executes the specified ATE launch command. Note for simplicity we are assuming here that the directory c:\ate contains an installation of ATE. To be more general you would need to use additional inquiry commands to determine the environment and the installed location of ATE, if applicable.

program shortcut,1.0(100) ! create shortcut

++include ashinc:ashell.def

map1 misc

map2 cmd$,s,260

map2 icon$,s,260

map2 status,f

map2 lnkspec$,s,260

icon$ = "ashell1_t.ico" ! borderless A-Shell icon

cmd$ = "c:\ate\bin\ashw32.exe -i c:\ate\miame.ini -g "+icon$+" -atecfg ?"

icon$ = "c:\ate\icons\" + icon$

! note: for ATE, we have to first resolve any client-side env vars,

! in this case, %USERPROFILE%...

! (extra step is harmless in local Windows case)

xcall MIAMEX, MX_AGWRAPPER, AG_GETENV, "%USERPROFILE%,1",lnkspec$

! put the shortcut on the users's desktop

lnkspec$ += "\Desktop\test shortcut.lnk"

? "Creating shortcut ";lnkspec$

xcall MIAMEX, MX_SHORTCUT, cmd$, lnkspec$, &

"Description of shortcut", "c:\ate", icon$, 0, status

? "Status: ";status

end

History

2014 September: Added "Comments" and "Example"

2008 August, A-Shell 5.1.1127: Routine added to A-Shell


MIAMEX 174: String Compare

Added January 2009

xcall MIAMEX, MX_STRCMP, s1, s2, flags, result

MX_STRCMP compares two strings in various ways.

Parameters

s1, s2 (String) [in]

are the strings to compare. Only the first 256 characters are considered.

flags (Num) [in]

may be set to one or more of the following:

Symbol | Value | Meaning
STRCMPF_LDF | &h01 | Use LDF collating sequence
STRCMPF_NAT | &h02 | Use "natural" compare (see "natural sort" above)
STRCMPF_FOLD | &h04 | Case insensitive comparison
Definition file: ashell.def

result (Signed num) [out]

Value | Meaning
<0 | s1 < s2
>0 | s1 > s2
0 | s1 = s2

Comments

With flags=0, you should get nearly the same results as in the standard BASIC string comparison, except that BASIC string comparison ignores trailing blanks, while MX_STRCMP only ignores them if the "natural" flag is set.

The standard BASIC string comparison does not take into account the LDF collating sequence, so for example it will treat accented characters as sorting above the non-accented equivalent.

Unless you modify the LDF accordingly, the standard LDF collating sequences do not change the order of the ASCII characters 1-127, so even with the LDF option, lower case characters are treated as being greater than upper case.

You can check the status of the collating sequences in your LDF file by using DUMP xxxxxx.LDF (the lower collating sequence starts at offset CE in the first block, and the upper collating sequence starts at offset CC in the second block). Or, you can use the updates GTLANG.BAS sample program included in the EXLIB.

History

2009 January, A-Shell 5.1.1136: Routine added to A-Shell


MIAMEX 176: Check PC Network State

Added March 2009

xcall MIAMEX, MX_CHKPCNET, status, flags {,clisvr}

MX_CHKPCNET checks the network state of the local PC (for A-Shell/Windows) or the ATE client:

See the Tab(-10,x) Function Listing for an equivalent Print Tab command (AG_CHKPCNET).

status (Num) [out]

will return 1 if the PC is connected to the Internet, and 0 if it is not. -1 indicates that the function is not supported (not Windows, ATE not present, or ATE PC version too old), and -15 indicates that ATE did not respond.

Note that since older versions of A-Shell would not have this function supported, you may want to pre-set status to something like -99 so you don't confuse a non-updated status with a real one (or, use MX_GETVER to check the A-Shell version before calling the function).

Notes also for ATE: if A-Shell on the server is 1138.3 or higher, but the ATE PC is not, the function returns STATUS = -1.

flags (Num) [out]

returns flags which can be interpreted as following:

Symbol | Value | Meaning
INTERNET_CONNECTION_CONFIGURED | &h0040 | local system has a valid connection to the Internet, but it might not be connected.
INTERNET_CONNECTION_OFFLINE | &h0020 | local system is in offline mode
INTERNET_RAS_INSTALLED | &h0010 |
INTERNET_CONNECTION_PROXY | &h0004 | local system uses a proxy server
INTERNET_CONNECTION_LAN | &h0002 | local system uses a LAN to connect
INTERNET_CONNECTION_MODEM | &h0001 | local system uses a modem to connect

clisvr (String, 1) [in]

may be set to "S" (for server), or "L" (for local, which is the same as server in this context); anything else is treated as meaning "client". The option only has significance in the ATSD environment where the possibility exists of performing the function relative to the ATSD server or the client. In all other cases, the parameter is ignored and the operation is performed relative to the client, or returns an empty string if an applicable client is not present.

History

2011 July, A-Shell 5.1.1226: Add clisvr parameter.

2009 February, A-Shell 5.1.1139: Routine added to A-Shell.


MIAMEX 177: Wrap ATE Command

Update January/July 2015; see History

xcall MIAMEX, MX_AGWRAPPER, agcmd, parms, response {,timeout)

MX_AGWRAPPER serves as a convenient wrapper for "raw" ATE commands that are otherwise invoked via a sequence like:

? TAB(-10,agcmd);parms;chr(127);

input "",response

Aside from simplifying the syntax, MX_AGWRAPPER provides some intelligence to deal with the problem of typeahead that may be "in the pipe" at the time the command was issued and thus get mixed into the response.

Parameters

agcmd (Num) [in]

The value of the TAB(-10,x) command to be issued via the wrapper. Normally specified via one of the AG_xxx symbols defined in the ashinc:ashell.def file (e.g. AG_XFUNCS).

parms (String) [in]

The list of parameters that would normally follow the AG_xxx command, up to but not including the terminating chr(127). Consult the specifications for the AG_xxx command in question.

response (String) [out]

Returns the string response which normally would otherwise end up in the keyboard buffer where it would need to be retrieved via an INPUT statement.

timeout (Num) [in]

Timeout in milliseconds (0 for infinite), after which the operation will give up waiting for the response and will return with a null response. For commands that are normally quick to respond (e.g. AG_DATETIME), the default timeout is 7500 ms. For certain commands which are known to potentially take a long time to complete (e.g. AG_XFUNC, AG_XFUNCS, AG_FTP, etc.) the default timeout is set to 0 (infinite). You can disable the timeout entirely by setting it to -1 (see Comments, below).

Example

This example illustrates using MX_AGWRAPPER to issue the AG_OPTIONS command (to query the ATE client's option flags). First, the traditional approach:

? tab(-10,AG_OPTIONS);"0";chr(127);

input "",OPT1,OPT2

And here is the MX_AGWRAPPER version:

xcall MIAMEX, MX_AGWRAPPER, AG_OPTIONS, "0", RESPONSE$

X = instr(1,RESPONSE$,",")

OPT1 = RESPONSE$[1,X-1]

OPT2 = RESPONSE$[X+1,-1]

Note that in this case, the RESPONSE$ variable would be set to a pair of comma-separated numbers (e.g. "123452,34123"), so we need to parse it out, resulting in more code than in the traditional version. (It is of course more convenient when the response is a single string value requiring no additional parsing.) In either case, the main benefit is to eliminate the potentially troublesome INPUT operation. For example, if the client fails to respond for some reason, or sends just one value instead of two, the INPUT statement will wait forever (possibly displaying a "?"), while the MX_AGWRAPPER call will gracefully timeout. (In the above example, the timeout would default to 7500 ms. We could have specified a shorter timeout, but since it would only matter in the rare case where the client was not responding as expected, it makes more sense to error on the conservative side in order to allow for some unexpected network delay, than to time out prematurely.)

Comments

There isn't anything to be gained by using the MX_AGWRAPPER function to issue a command that does not receive a response (e.g. AG_MINTITLE). But if you do, set timeout to -1 to disable the wait for response. Otherwise it will wait for the default timeout (7.5 seconds) to expire.

Note that many AG_xxx commands already have direct MX_xxx equivalents. The general purpose MX_AGWRAPPER function is mainly of interest when there is no MX_xxx version of the AG_xxx command, or where the MX_xxx version works only on the server side when you really want it to work on the client side.

History

2015 January, A-Shell 6.1.1399: the wrapper routine now handles certain ZTERM legacy commands (AG_FTP, AG_SHLEXEC and AG_WINEXEC) more robustly than before. These commands differ from the standard ATE commands for which MX_AGWRAPPER was designed because they only return a single character, rather than a string with a CR terminator. Previously these worked fine in the case of success, because the successful code of chr(13) matched the response termination character expected by AG_MXWRAPPER. But in the case of failure, the chr(3) response would either abort the program or would be ignored. Now the single character error response (chr(3)) is returned in the MX_AGWRAPPER response parameter, as you would normally expect when using MX_AGWRAPPER.

2009 June, A-Shell 5.1.1159: Routine added to A-Shell


MIAMEX 178: Establish File Hooks

Modified February 2015; see History

xcall MIAMEX, MX_FILEHOOK, opcode, status, file {,fid, handler, events, flags, enabled}

The file hook mechanism allows you to establish file "hooks" on specific files and file events. The "hook" is an SBX which is called automatically by A-Shell when the specified event occurs on the file. The SBX may then output auditing information, check for anomalies, enforce rules, export data, essentially whatever it likes.

To establish a hook on a file:

++include ashinc:ashell.def

++include ashinc:hook.def

Note that MX_FILEHOOK operations work with old ISAM files, at least for the standard file operations (OPEN, READ, WRITE, CLOSE) on the IDA file. There is no point in hooking the IDX file, as the ISAM statements themselves have no hook processing.

See the following topic Hook SBX Specification.

Parameters

opcode (Num) [in]

may be one of the following (defined in hook.def ):

Symbol | Value | Meaning
HOOKOP_DISABLE | 0 | disable one (or all) hooks
HOOKUP_ENABLE | 1 | re-enable one (or all) hooks
HOOKUP_ADD | 2 | add a new hook
HOOKOP_DEL | 3 | delete a hook
HOOKOP_APPEVENT | 6 | call the hook to process an app-defined event
HOOKOP_QRY | 7 | query a file hook by its fileid or filespec. If found, the status will be >= 0 and all of the remaining fields will be returned. See EXLIB sample/utility program QRYHOOKS.BP[908,50] for example of querying the file hook table.
Definition File: HOOK.DEF

status (Signed Num) [out]

returns status code:

Value | Meaning
>=0 | success
-1 | unable to allocate memory for hook table
-2 | illegal fspec (must be AMOS-style)
-3 | invalid handler syntax
-4 | fspec not found (opcode 0,1,2,6)
-5 | fid not found (opcode 0,1,2,6)
-6 | opcode not yet implemented
-7 | illegal opcode

file (String) [in]

is the specification of the file whose operations are to be hooked. Only AMOS-compatible filespecs are supported. Note that with opcode 0, 1 and 3, file may be "*" to perform the operation on all the hooks in the hook table.

fid (Num) [in]

a unique integer identifier for the file, which will be used in any output files to reference the file (more compact than outputting the file spec each time.)

handler (String) [in]

depends on opcode. For opcode 2 (add), it must specify the handler for the hook, using the following syntax:

SBX:xxxxxx

where xxxxxx is the name of an SBX file, which will be called to process the hook. See the following topic, Hook SBX Specification, for further details. Note that additional handler types (and corresponding syntax), such as a text file, FIFO, or TCP connection, may be defined later.

For opcode 6 (HOOKOP_APPEVENT), the handler parameter may be used to pass an arbitrary string to the hook routine. Typically this may be used to include a message in the hook log file, such as "posting run complete".

events (B,4) [in]

a bit-field of events to hook, from the following (defined in hook.def):

Symbol | Value | Meaning
HFE_PRE_OPEN | &h00000001 | prior to open
HFE_POST_OPEN | &h00000002 | after open
HFE_PRE_CLOSE | &h00000004 | prior to close
HFE_POST_CLOSE | &h00000008 | after close
HFE_PRE_READ | &h00000010 | prior to read or get (any)
HFE_POST_READ | &h00000020 | after read or get (any)
HFE_PRE_READL | &h00000040 | prior to readl or getl
HFE_POST_READL | &h00000080 | after readl or getl
HFE_PRE_WRITE | &h00000100 | prior to write (or update'record)
HFE_POST_WRITE | &h00000200 | after write (or update'record)
HFE_PRE_WRITEL | &h00000400 | prior to writel (or create'record)
HFE_POST_WRITEL | &h00000800 | after writel (or create'record)
HFE_PRE_ALLOC | &h00002000 | prior to allocate
HFE_POST_ALLOC | &h00004000 | after allocate
HFE_PRE_KILL | &h00008000 | prior to kill
HFE_POST_KILL | &h00010000 | after kill
HFE_PRE_SORT | &h00020000 | prior to sort
HFE_POST_SORT | &h00040000 | after sort
HFE_ISAM_ADD | &h00080000 | after ISAM 5 (add); see History
HFE_ISAM_DEL | &h00100000 | after ISAM 6 (delete); see History
HFE_APP_EVENT1 | &h10000000 | custom application event
Definition File: HOOK.DEF

flags (B,4) [in]

a bit-field of flags which are passed to the hook routine (as a clue to how the hook should operate), and/or which are used by A-Shell to modify the operation of the hook (from hook.def):

Symbol | Value | Meaning
HFF_PROG | &h00000001 | include program name
HFF_SBX | &h00000002 | include sbx name
HFF_DATA | &h00000004 | include copy of data just written (POST_WRITE only)
HFF_DATA_WAS | &h00000008 | include copy of data as previously read or written, for comparison with data now being written (POST_WRITE only)
HFF_RECNO | &h00000010 | include recno
HFF_TIME | &h00000020 | include time
HFF_DATE | &h00000040 | include date
HFF_USER | &h00000080 | include user name
HFF_PID | &h00000100 | include process id
HFF_AUTO_DEL | &h00001000 | auto delete hook on prog exit
HFF_DATA_WAS_NA | &h00010000 | there is no "was" data available to pass to the hook routine in response to the HFF_DATA_WAS flag
HFF_DATA_CHG_ONLY | &h00020000 | may be used in conjunction with HFE_POST_WRITE to suppress calling the hook function after the write if the record data hasn't changed.
Definition File: HOOK.DEF

enabled (Num) [out]

returns zero or one to indicate if the hook is disabled or enabled.

History

2015 February, A-Shell 5.1.1402: Added events HFE_ISAM_ADD and HFE_ISAM_DEL. Note that unlike most of the other file hooks, these don't come in PRE- and POST-flavors. For the ADD hook, the record data supplied to the hook routine (rec parameter) will contain the key rather than the record data. Since ISAM adds are followed by a WRITE statement, you can hook that to get the contents of the record itself. For the DEL hook, the record data of the record being deleted is supplied to the hook routine in the pre'rec parameter. The rec parameter should be ignored. The sample hook program FHOOKTST3.BP and hook subroutine FHOOK1.SBX in [908,50] of the EXLIB have been updated to illustrate both hooks.

2011 June, A-Shell 5.1.1221: Added flag HFF_DATA_CHG_ONLY to suppress calling the hook function after the write if the record data hasn't changed.

2010 December, A-Shell 5.1.1197: File hook refinement: When there is no "was" data available to pass to the hook routine (in response to the HFF_DATA_WAS flag), A-Shell now sets a new flag, HFF_DATA_WAS_NA (&h00010000) in the flags field in the hook environment structure passed to the hook routine. This allows the hook routine to distinguish between an empty prior record and unknown prior record contents. The prior contents of the record can only be supplied to the hook routine if the last record # read is the same record # being written. ASHINC:HOOK.DEF has been updated with the new flag, and the sample hook routine FHOOK1.BP (SBX) has been updated to show testing the flag.

2010 January, A-Shell 5.1.1174: Routine added to A-Shell

Subtopics

Hook SBX Specification


Hook SBX Specification

Updated November 2016

The SBX you specify to handle the hook will be called automatically by A-Shell for the specified events, as follows:

xcall <NAME>, sts, envelope, rec, pre'rec

Parameters

sts (Num) [in]

returns 0 for ok. Any odd value returned from a HFE_PRE_xxx event will cause A-Shell to skip the event. This allows you to completely replace the file operation originally programmed, with one of your own.

envelope (ST_HOOK_ENV structure) [in]

a structure containing the following information (defined in hook.def):

Field | Type | Meaning
event | b,4 | event code (see HPE_xxxx flags)
flags | b,4 | event processing flags (see HFF_xxx)
fileid | b,4 | unique file id #
recno | f,8 | rec #. Note that this will always be zero-based, regardless of the actual FILEBASE setting in either the hook SBX or in the main program.
pid | b,4 | process id
recsiz | b,4 | record size
mode | b,4 | mode (depends on event)
prog | s,16 | program name
sbx | s,16 | sbx name (if appl)
user | s,24 | user name
chan | b,4 | actual file channel; might not match fileid
location | b,4 | location counter
lineno | b,2 | last line number

rec (String or x) [in]

contains data relative to the event. For the HFE_POST_READx and HFE_xxxx_WRITEx events, it will contain the record data which was just read or which is to be (or was just) written. For the OPEN, ALLOC and KILL events, it will contain the filespec (in native format). For the APPEVENT event, it will contain the contents of the HANDLER$ parameter passed to the MX_FILEHOOK call. For other events, it may be undefined.

pre'rec (X) [in]

used only with the HFE_POST_WRITE event, when the HFF_DATA_WAS flag is set, in which case it will contain the previous contents of the record (at the time of the last read or write operation on the file). Warning: this mechanism only works when no other records in the same file were accessed since the last read or write of this record. If other accesses have occurred, the contents of pre'rec will be empty.

Comments

A sample hook (FSHOOK1) and sample program (FHOOKTST1) can be found in [908,50] of the EXLIB .

Comments

2016 November, A-Shell 6.3.1538: Add envelope fields chan, location and lineno. These are mostly motivated by the desired to use the hook mechanism for application forensics that for more traditional purposes (export, data audit), i.e. they allow the hook return to more information context in which the file operation occurred. The new fields do not break compatibility with existing hook routines, nor do hook routines using the expanded structure lose their backwards compatibility; the new fields just won't be available. See ASHINC:HOOK.DEF for the updated structure and related symbol defintions.


MIAMEX 179: Send Inter-process AG_xxx

Reviewed July 2010

xcall MIAMEX, MX_AGINTERPROC, hwnd, agcmd, msg, status

MX_AGINTERPROC provides for sending AG commands between instances of A-Shell/Windows.

Parameters

hwnd (B,4) [in]

is the target window handle (use MX_FINDWINDOW to get it)

agcmd (Num) [in]

is a value in the range of 1-99 corresponding to the AG_xxx commands.

msg (String) [in]

is the text string normally following the AG_xxx command (must be terminated with chr(127)!!!

status (signed numeric) [out]

returns a status code indicating the success of the operation:

Status | Meaning
1 | OK (target received and processed msg)
0 | No response from target
-1 | Target received msg but rejected it as invalid
-2 | Missing trailing chr(127) on message
-3 | Target HWND not found

History

2010 July, A-Shell 5.1.1187: Routine added to A-Shell


MIAMEX 180: Get/Set Inactivity Timeout

Added August 2010

xcall MIAMEX, MX_IATIMEOUT, opcode, timesecs

MX_IATIMEOUT allows querying / setting the inactivity timeout.

Parameters

opcode (Num) [in]

Specifies whether to get (0) or set (1) the timeout.

timesecs (Num) [in, out]

Timeout value in seconds. If opcode=0, the current timeout setting (or zero if disabled) is returned here. Otherwise the value passed in timesecs is used to reconfigure the current inactivity timer.

Comments

Note that unlike the case in the miame.ini IATIMEOUT parameter, which uses units of minutes, MX_IATIMEOUT function uses units of seconds.

History

2010 August, 1191: Routine added to A-Shell


MIAMEX 181: Get/Set CSV Delimiter

Added May 2010

xcall MIAMEX, MX_CSVDELIM, opcode, delim

MX_CSVDELIM allows the CSV delimiter to be set or retrieved.

Parameters

opcode (Num) [in]

0 to retrieve, 1 to set

delim (String, 1) [in/out]

the delimiter retrieved (opcode 0) or to be set (opcode 1)

When set, the specified delimiter overrides the one normally used by the WRITECD, WRITETD, and INPUT CSV statements.

To restore the default behavior, in which the delimiter is determined by the most prevalent of the four typical delimiter characters—comma, semicolon, colon, and tab—in the first line of the file, set the delim to "" (null).

History

2011 May, A-Shell 5.1.215: Routine added to A-Shell


MIAMEX 182: Trigger BASIC Error

Added December 2012

xcall MIAMEX, MX_SETERR, errnum {,chan}

MX_SETERR triggers a BASIC error. It may be useful for testing/debugging error handling routines, as well as for using the error trapping mechanism as a way of passing coded signals (i.e. virtual error codes) from within an arbitrarily nested function/procedure up to the main error trap.

Parameters

errnum (Num) [in]

the BASIC error to trigger; sets err(0)

chan (Num) [in]

channel number; sets err(2)

History

2012 December, A-Shell 6.1.1329: Routine added to A-Shell


MIAMEX 183: ATE File Transfer

Documentation (only) updated May 2016

xcall MIAMEX, MX_ATEFILEXFR , hostfile, pcfile, status

MX_ATEFILEXFR provides file client-to-server transfer capability for the ATE/ATSD environment, where such transfers are otherwise inconvenient due to the typical lack of an FTP service. It uses the keyboard channel to send the raw data from the client to the server, independent of routers, firewalls, etc. A-Shell 6.1.1357 or later is required on both the server and the ATE client.

The status parameter returns the number of bytes output to hostfile. Negative numbers constitute system error codes, or one of these:

Code | Description
-1### | BASIC error ###
-99 | platform error (only supported on ATSD/ATE)
-98 | invalid options
-97 | unable to allocate memory
-96 | timeout while waiting for data
-95 | ATE client or A-Shell/Windows version too old
-94 | File transferred but hash doesn't match original
-1 | pcfile not found
0 | No transfer because hostfile already matches pcfile

Comments

For server-to-client file transfers, see ATEAPX.SBX in [907,33] of the SOSLIB.

See Also

• ATEGFK.SBX in [907,33] of the SOSLIB which acts as a wrapper to MX_ATEFILEXFR and extends the capability to ATE/UNIX environments.

History

2013 July, A-Shell 6.1.1357: Routine added to A-Shell


MIAMEX 184: Clear Input Buffer

Added January 2015

xcall MIAMEX, MX_CLRINBUF, {flags}, {buffer}

MX_CLRINBUF provides a simple way to eliminate all type-ahead from both the server and client input buffers.

Parameters

flags (Num) [in]

Specifies the sum of:

+1) leave kbd locked

+2) set ATE master kbd hold. Same as TAB(-10,AG_HOLDKBD);"2";chr(127).

buffer (String) [out]

string buffer which will return the characters that were cleared from the local input buffer.

Comments

In a standalone Windows or text environment, this just provides another alternative to existing techniques for clearing the input buffer, including TINKEY, GETKEY(0), and INFLD (type "0"). But in an ATE/GUI environment, it provides the additional feature of clearing any input characters which are currently buffered on the ATE client. Those can sometimes create problems when they accumulate silently on the client and then get released to the host unexpectedly.

Note that to minimize the chance of missing input characters currently in transit from the client to the server, it sends an AG_ACK request (with a five second time limit).

Compatibility: requires 6.0.1400.0+ on the server; works with any ATE version. However, for earlier ATE versions, some of the advanced features are unavailable and thus it may not work much better than the existing alternatives mentioned above.

History

2015 January, A-Shell 6.1.1400: Routine added to A-Shell


MIAMEX 185: Get/Set MALLOCLIMIT

Added February 2016

xcall MIAMEX, MX_MALLOCLIMIT, op, limit

Parameters

op (Num) [in]

0 to get the limit and 1 to set it

buffer (B,4 or F) [out]

returns the current limit (op=0) or supplies the new limit (op=1). Units are bytes—not kilo-, mega-, or giga-bytes. Maximum practical limit is 2GB-1 (2147483647).

History

2016 February, A-Shell 6.2.1424: Routine added to A-Shell


MIAMEX 186: Get PDFX File Spec

Added April 2016

xcall MIAMEX, MX_LASTPRTFIL, fspec

This function returns the file spec of the last file written by the PDFX printer driver.

Parameters

fspec (String) [out]

return the filespec

Currently this only works for PDFX5+, where it solves the problem of finding out the actual name of the PDF file which otherwise may be unknowable due to auto-numbering strategies in the driver, or due to the operator using the Save As dialog to rename the file. The feature may be expanded in the future to support other similar printing situations.

History

2016 February, A-Shell 6.3.1509: Routine added to A-Shell


MIAMEX 187: Bind TCP Socket to File Channel

Added October 2016

xcall MIAMEX, MX_FILESOCK, ch, socket, status

This function binds a TCP socket to a sequential file channel so that PRINT #CH and/or INPUT #CH transfers data over the socket rather than to/from the file.

Parameters

ch (Num) [in]

must be a file channel (> 0) open for sequential input or output. Typically you would open the file using the .NULL filespec as described in the previous edit note.

socket (Num) [in]

must be a valid socket opened via TCPX.SBR.

status (signed Num) [out]

returns 0 for success, else error.

If ch was open for output, then after the successful completion of the MX_FILESOCK call, PRINT #CH statements will output to the socket instead of the file. Similarly, if ch was open for input, then INPUT #ch statements will read from the socket.

Note that while sockets are bidirectional, sequential file channels are not, so if you want to both input and output to the socket this way, you'll need to open two file channels and bind them both to the same socket with two separate MX_FILESOCK calls.

Once the file channel is bound to the socket, closing the file channel will also close the socket.

To simplify the operation of opening the file and socket and binding the two together, a pair of functions has been added to the SOSFUNC: library:

Fn'FileSock'Out(ch, socket, server$)

Fn'FileSock'In(ch, socket, server$)

See the fnfilesock.bsi source code in the [907,10] directory of the SOSLIB for details, including a sample/test routine.

History

2016 September, A-Shell 6.3.1524: Routine added to A-Shell


MIAMEX 188: Control WEBCACHE

Added October 2016

xcall MIAMEX, MX_WEBCACHE, 0, status

xcall MIAMEX, MX_WEBCACHE, 1, status

xcall MIAMEX, MX_WEBCACHE, 2, status, url

xcall MIAMEX, MX_WEBCACHE, 3, status, url

xcall MIAMEX, MX_WEBCACHE, 4, status, url, localfile

xcall MIAMEX, MX_WEBCACHE, 5, status {,wildspec}

MX_WEBCACHE provides operations related to A-Shell's web cache feature.

Parameters

opcode (Num) [in]

Determines operation as described below.

status (signed int) [in/out]

Sets or returns options, or returns status codes shown under option 4 below.

url$ (String) [in]

Specifies a web directory for ocodes 2 and 3, and a fully qualified file URL for opcode 4. Currently the only URL schemes supported are http:// and https://. An optional :port may be appended to the end. Examples:

http://www.mysite.com/webrepo

http://www.mysite.com/webrepo/myfile.run:10080

https://www.mysite.com/my web repository

Opcodes

Opcode 0 retrieves the current webcache options in status. Status flags (defined in ashell.def) :

Symbol | Value | Description
WCDF_ENABLED | &h00000001 | web cache enabled (else disabled)
WCDF_PROG | &h00000002 | download/cache programs (RUN,LIT,SBX)
WCDF_OPENI | &h00000004 | download/cache files on open for input
WCDF_LOOKUP | &h00000008 | download/cache any file on LOOKUP or SIZE.SBR
WCDF_DLL | &h00000010 | download DLLs to bin or webcache
WCFG_ALL | &h000000FE | all flags except WCDF_ENABLE

Opcode 1 sets the webcache options to the value status.

Opcode 2 and 3 retrieve and set webcache url (web directory), respectively. Status will return 0 for success.

Opcode 4 performs a manual download from the specified url$ to the specified localfile$. If the url$ is just a file.ext and the webcache url directory has been previously set, then the two are combined to form the complete source url. If localfile$ is "", the source file.ext is used. If localfile$ does not contain a directory, then the local webcache directory (%MIAME%\webcache) is used. Returned Status will equal the # of bytes downloaded if successful, else an error code:

Status | Meaning
-1 | Unsupported URL scheme (e.g. not http:// or https://)
-2 | Specified URL does not contain filename (Opcode 2)
-3 | URL too long
-4 | Unable to connect to host web server
-5 | Error sending HTTP GET command to server
-6 | Error in local webcache directory\file spec
-7 | Response from web server missing header terminator
-8 | Response from web server not recognizable
-9 | Transmission problem receiving header
-### | HTTP response error code (converted to negative)

Opcode 5 clears the local webcache directory. If the wildspec$ parameter is specified and non-blank, only those files matching the wildspec$ will be cleared; otherwise all of the files in the cache will be cleared. Returned status will equal the number of files removed from the cache.

History

2016 October, A-Shell 6.3.1529 and 1531: WEBCACHE function added to A-Shell. The module includes a basic description, the SET.LIT options for WEBCACHE, new functions WEBRUN.LIT, MX_WEBCACHE.SBR, and ? tab(-10,AG_WEBCACHE).


MIAMEX 189: Get Call Stack Info

Added November 2016

xcall MIAMEX, MX_CALLSTACK, maxdepth, csarray(1) {, program}

MX_CALLSTACK returns information about the call stack. The motivation here is to allow application routines to identify the context in which they were called. For example, the file hook subroutine, or an error trapping routine, might want to identify not just the location where the file operation or error occurred, but if that location was within a callable routine, the routine(s) that called it.

Parameters

maxdepth (Num) [in/out]

should be set to the number of elements in the csarray(), i.e. the maximum number of stack levels—working backwards from the current stack frame context—to retrieve. On return, it will be set to the number of levels in the current stack. If greater than the number you originally specified, it indicates that not all of the levels were returned.

csarray(1) (array of ST_CALLSTACK) [out]

the first element of an array of structures defined in ashinc:CALLSTACK.DEF as follows:

defstruct ST_CALLSTACK

map2 calltype,b,2 ! type of call (see CSTF_xxx)

map2 src'lno,b,2 ! line # at or prior to call

map2 src'loc,b,4 ! location counter at call

map2 dst'loc,b,4 ! target location (for call, fn, proc)

map2 dst'name,s,52 ! name of sbx or AMOS command line

endstruct

Typically csarray() would be defined via:

dimx callstack(MAX_CALLSTACK), ST_CALLSTACK

MAX_CALLSTACK should be set to the maximum number of levels you want to retrieve.

program (String) [out]

optionally returns the main program at the top of the callstack.

Example

++include ashinc:ashell.def

++include ashinc:callstack.bsi

define MAX_CALLSTACK = 10

map1 misc

map2 program$,s,10

map2 stackdepth,i,2

dimx callstack(MAX_CALLSTACK), ST_CALLSTACK

stackdepth = MAX_CALLSTACK ! max # levels we can handle

xcall MIAMEX, MX_CALLSTACK, stackdepth, callstack(1), program$

for i = 1 to stackdepth min MAX_CALLSTACK

? Fn'Call'Stack'Descr$(callstack(i))

next i

The Fn'Call'Stack'Descr$() function referenced above is in the SOSLIB module ashinc:CALLSTACK.BSI. It creates a one line description of a call (gosub, procedure, function, xcall, amos statement, etc.) from one location/context to another. An example showing a context six levels deep looks like this:

from loc 3B7 call proc() @3DF

from loc 38C fn'() @393

from loc 32B call proc() @331

from loc 4F1 xcall callstack1

from loc 47C fn'() @483

from loc 323 call proc() @41A

Notes

• In the above example, the program had no line numbers, so they weren't listed in the output.

• To match up the location counter values to source code lines, see the LSX file created by the compiler /L switch.

• The entry in the array (shown at the top) describes the level that called the code that executed the MX_CALLBACK function. So in the above case, the current code is within a procedure that starts at location 3DF (hex) and was called from location 3B7. Location 3B7 is within a function that starts at location 393, which in turn was called from location 38C, etc.

History

2016 November, A-Shell 6.3.1538: Function added to A-Shell.


MSBOXX

xcall MSBOXX, strow, stcol, endrow, endcol, boxcod {, boxsts, boxclr}

MSBOXX.SBR is nearly equivalent to the version under AMOS (developed by MicroSabio as part of the TRACKER package), except that it does not support the boxmap and boxctl parameters of the AMOS version. For complete details, you should consult the TRACKER User's Guide. Here, however, is a brief summary:

Parameters

strow, stcol, endrow, endcol

specify the coordinates of the upper left and lower right corner of the box to be drawn. It is important to note that if a border is applicable, it is drawn OUTSIDE of the coordinates specified for the box. (Thus the interior, or usable part of the box is the same size whether or not the border option is specified.)

boxcod

specifies one or more options (added together). These are generally referenced symbolically via the MSBOXX.BSI include file.

Symbol | Value | Meaning
BOX'ERA | &h000001 | Clear interior of the box
BOX'BDR | &h000002 | Draw border around the box
BOX'SVA | &h000004 | Save area used by box (to be restored later)
BOX'RSA | &h000008 | Restore area (previously saved)
BOX'COF | &h000010 | Leave cursor off on exit
BOX'REV | &h000020 | (Not supported under A-Shell)
BOX'FAO | &h000040 | Field attributes on/off (at edge of box)
BOX'CHK | &h000080 | Return BOXSTS=0 if save/restore supported
BOX'PSA | &h000100 | Pop saved area without displaying it
BOX'MAP | &h000400 | (Not supported under A-Shell)
BOX'PRT | &h000800 | (Not supported under A-Shell)
BOX'ATR | &h001000 | Save/restore screen context
BOX'HLI | &h002000 | Draw horizontal line (set strow = endrow)
BOX'VLI | &h004000 | Draw vertical line (set stcol = endcol)
BOX'DBL | &h008000 | Draw double line border around box
BOX'SBU | &h010000 | Scroll box up one line
BOX'SBD | &h020000 | Scroll box down one line
BOX'SRF | &h040000 | Draw line with serifs
BOX'WIN | &h080000 | Display pop-up window; see Comments below
BOX_PAR | &h100000 | See note in History, below
Definition File: MSBOXX.DEF

Hex-Decimal Values

boxsts

optionally returns a code indicating if the operation succeeded. 0 indicates success.

boxclr

optionally defines the set of colors to use for the parts of the box:

MAP1 BOXCLR

MAP2 BRDR'FG,B,1 ! Border foreground

MAP2 BRDR'BG,B,1 ! Border background

MAP2 IBOX'FG,B,1 ! Interior foreground

MAP2 IBOX'BG,B,1 ! Interior background

Comments

Since TRACKER is built-in to A-Shell, you can always count on the ability to save and restore screen areas with MSBOXX.SBR. You can also perform all of these box drawing and save/restore operations using individual TAB(x,y) commands, but with considerably more effort.

History

2011 April, A-Shell 5.1.1210: New flag BOX_PAR may be used with BOX_WIN and BOX_SVA/BOX_RSA to automatically make the pop-up panel act as the parent to any controls (including TPRINT statements) created until the box is removed (with BOX_RSA+BOX_WIN+BOX_PAR). You could have done this yourself using MX_AUTOPARENT except that MSBOXX does not return an identifier for the panel; the BOX_PAR option overcomes that issue and automatically issues the necessary MX_AUTOPARENT calls.

Note that with BOX_WIN, the box/panel is a GUI control, and thus you cannot output plain text on top of it; use TPRINT, DPRINT, AUI_CONTROL, and other GUI control generation statements instead of PRINT. Furthermore, with BOX_PAR, since the panel acts like a parent, the cursor position of controls and text to be placed on it must be adjusted to be relative to the box/panel rather than the screen. (The overall effect is similar to using a regular dialog box.)

2011 April, 5.1.1210: BOX_SVA with the BOX_WIN option now saves underlying controls, as well as text, and BOX_RSA + BOX_WIN will restore them. This allows BOX_WIN panels to effectively overlay areas containing either plain text or GUI controls, or both.

2004 April, A-Shell 4.9.884: The operation of the MSBOXX opcode BOX'WIN (to create a GUI-style raised panel box) has been improved to no longer require that the border option be selected, and more importantly, to work over ATE. If selected in a non-GUI environment, the option is just ignored (so you should combine it with whatever other box options you would otherwise use, including BOX'SVA, BOX'RSA, BOX'ERA, etc.)

Note that one of the advantages of BOX'WIN for pop-up boxes is that being a true control, it can overlay other controls, and other controls can overlay it, without the complications that arise when trying to save and restore text boxes in a mixed GUI environment. However, if you do use BOX'WIN, you should only use GUI-style static text and other controls to write within the box.

2004 February, A-Shell 4.9.863: (Windows) A new opcode option has been added to MSBOXX.SBR to display a GUI-style pop-up window: 524288. This has been added to MSBOXX.BSI as BOX'WIN. When specified, and using the GUI version of the driver, it causes the pop-up box to be created using a static text control with the MBF'FRAME option and the standard "button face" background color (generally gray). The "frame" is much thinner than the normal MSBOXX border, allowing the rows and columns which are normally taken by the border to be used for text if so desired. This style of box is the only kind that can overlap other controls (without causing the underlying controls to have to be hidden). However, if you use this style of box, you should only print within it using TPRINT, DPRINT, or AUI_CONTROL. Any other kind of output will "print through" to the underlying screen layer and not be removed when the box is removed.


MSGBOX

Updated January 2017

xcall MSGBOX, msg, title, btnflag, iconflag
{, miscflags, rtncde
{, mxflags, timeout, timein, url, iconspec,
btn1, btn2, btn3, btn4, btn5,
tip1, tip2, tip3, tip4, tip5,
fontface, fontscale, fgc, bgc}}

Note that in the syntax shown above, spaces and line breaks have no meaning—i.e., they do not and should not exist in the actual program. They are used here strictly as visual aides to illustate the structure of the commands.

MSGBOX.SBR displays a message in a popup dialog, with a variety of standard or customized response button options. Depending on the environment and parameter options, one of four implementations may be used:

• Standard Windows Message Box. Used in GUI environments prior to A-Shell 6.3.1543 or when no extended options are requested.

• Enhanced A-Shell Message Box using a dialog built with the AUI_CONTROL API. Used in A-Shell 6.3.1543 and later GUI environments when the mxflags parameter is specified.

• INMEMO free-form menu. This is used in plain text environments or when forced with the MBX_FRCTXT flag.

• HTML. In CGI mode, the message is simply sent to the browser in HTML format as the CGI response.

Parameters

msg (String) [in]

Specifies the message to display. The width of the message box will be adjusted (within certain reasonable limits) to the size of the message, which will them be wrapped as needed. You can also force your own line breaks and blank lines by inserting CHR$(13) characters.

title (String) [in]

Specifies the title that will appear in the title bar of the message box.

btnflag (Num) [in]

Select one of the following values to specify the set of response buttons that will appear on the message box:

Symbol | Value | Description
MBTN_OK | &h0000 | OK button only, or customized buttons; see comments.
MBTN_OK_CANCEL | &h0001 | OK and CANCEL buttons
MBTN_ABORT_RETRY_IGNORE | &h0002 | ABORT, RETRY, and IGNORE buttons
MBTN_YES_NO_CANCEL | &h0003 | YES, NO, and CANCEL buttons
MBTN_YES_NO | &h0004 | YES and NO buttons
MBTN_RETRY_CANCEL | &h0005 | RETRY and CANCEL buttons
MBTN_HELP | &h4000 | Add a HELP button
MBTN_CANCEL_TRY_CONTINUE | &h0006 | See note in History, below
Definition File: ashell.def

Hex-Decimal Values

iconflag (Num) [in]

Select one of the following to specify the standard Windows icon that appears in the message box (in a GUI environment). 0 specifies no icon. See iconspec to specify a custom icon.

Symbol | Value | Description
MBICON_STOP | &h0010 | Stop (Red X)
MBICON_QUESTION | &h0020 | Question (?)
MBICON_EXCLAMATION | &h0030 | Exclamation (!)
MBICON_ICON | &h0040 | Information (i)
Definition File: ashell.def

Hex-Decimal Values

miscflags (Num) [in]

Combine zero or more of the following to specify misc options:

Symbol | Value | Description
MBMISC_DFLT2 | &h0100 | Make the second button be the default. (Normally the first button will be the default button.)
MBMISC_DFLT3 | &h0200 | Make the third button be the default.
MBMISC_DFLT4 | &h0300 | Make the fourth button be the default
MBMISC_DFLT5 | &h0400 | Make the fifth button be the default
MBMISC_SYSMODAL | &h1000 | System modal. Suspends all Windows applications until the dialog box is responded to. (Windows only)
MBMISC_TASKMODAL | &h2000 | Task modal. Suspends the A-Shell session until the dialog box is responded to. (Windows only)
MBMISC_TOPMOST | &h8000 | Force message dialog to remain on top until closed. This prevents a problem where it can get hidden by other windows, even though it has the focus, making the other windows appear to be dead.
Definition File: ashell.def

Hex-Decimal Values

rtncde (Num) [out]

Returns a code indicating what button was pushed to respond to the message, from the list below:

Symbol | Value | Description
MBRC_OK | 1 | OK button
MBRC_CANCEL | 2 | CANCEL button
MBRC_ABORT | 3 | ABORT button
MBRC_RETRY | 4 | RETRY button
MBRC_IGNORE | 5 | IGNORE button
MBRC_YES | 6 | YES button
MBRC_NO | 7 | NO button
MBRC_CLOSE | 8 | Dialog closed; see notes below
MBRC_HELP | 9 | HELP button
MBRC_TRYAGAIN | 10 | TRY AGAIN button
MBRC_CONTINUE | 11 | CONTINUE button
MBRC_CTRLC | 12 | Control-C; see notes below
<no symbol> | 101 | First custom button; see mxflags MBX_RCBTNO
 | 102 | Second " " " "
 | 103 | Third " " " "
 | 104 | Fourth " " " "
 | 105 | Fifth " " " "
Definition File: ashell.def

A return code of 8 indicates that the message box was closed without clicking on one of the button choices (either the X button in the corner of the dialog under Windows/ATE or the Escape key under UNIX/text mode). Note, however, that at least under Windows, the internal message box logic may try to translate the close option to one of the existing buttons if it makes logical sense. For example, closing an OK/CANCEL dialog may return as if CANCEL clicked.

The MBRC_xxx values are associated with standard buttons sets as specified by the MBTN_xxx values in btnflag while the values 101-105 are used for custom button sets; see mxflags MBX_RCBTNO flag and Comments below. Note that Control-C will set the Control-C flag (triggering BASIC error 1) if Control-C is enabled; otherwise it will return MBRC_CTRLC. Also note that for the standard Windows Message Box, Control-C while the box is displayed may be ignored (acting instead as the Windows Copy command); but if the Control and C keys are down when the message box is created or destroyed, it will be detected and processed, providing a way out of situations where an error message box is being displayed in an endless loop. Hold down the Control and C buttons with one hand and dismiss the message box using the mouse with the other hand.

mxflags (Num) [in]

flags related to extended options:

Symbol | Value | Description
MBX_RCBTNO | &h10000000 | return 101-105 for buttons 1-5
MBX_FRCTXT | &h20000000 | force plain text version
MBX_TI1 | &h00100000 | time-in delay on button 1
MBX_TI2 | &h00200000 | time-in delay on button 2
MBX_TI3 | &h00400000 | time-in delay on button 3
MBX_TI4 | &h00800000 | time-in delay on button 4
MBX_TI5 | &h01000000 | time-in delay on button 5

timeout (Num) [in]

if not zero, sets the timeout (in seconds) on the default button, at which point the button is auto-clicked. Except in the case of icon buttons, the button will show the countdown progress.

timein (Num) [in]

used in conjunction with the MBX_TIx flags (see mxflags) to specify a time (in seconds) before which one or more buttons are unable to be clicked (i.e. disabled). This is useful when you want to make sure the message box stays on the screen for at least a certain number of seconds, either so that the user can read the message, or perhaps to prevent the possibility of accidentally clicking a button before understanding the consequences.

url (String) [in]

optionally specified a clickable hyperlink that appears beneath the message text and above the buttons. The visible text may be the same as the target url, or you may use HTML format to display something other than the actual link, e.g.

http://www.microsabio.com

<a href=http://www.microsabio.com>MicroSabio Home Page</a>

<a href="http://www.microsabio.com">MicroSabio Home Page</a>

The third example shows the proper HTML format—i.e., with the url field quoted. Note that to embed quotes within a quoted string in BASIC you have to use double-double quotes (""). The second example, without the extra quotes is supported for convenience.

iconspec (String) [in]

optionally specifies an icon (native Windows filespec or iconname::icondll, e.g. "warning:ashico1") to be used instead of the standard one based on the iconflag value, which will be ignored if iconspec is non-null. If neither an iconflag no an iconspec is specified, the message box will have no icon. Note the standard icons specified via the iconflag parameter do not change size with fontscale, but custom icons (specified via iconspec) do scale.

btn1 - btn5 (String,32) [in]

optional text or icon to display for up to 5 buttons—assuming you want to override the default button text corresponding to the btnflag parameter. Although you can mix text buttons and icon buttons, it probably works (or looks) best if you stick to one or the other. For icons, you can use the native Windows filespec of the .ico file or the iconname::icondll format for an icon within an icon library (like ashico1.dll). Note the 32 byte limit on the length of each field; for ico filespecs, to fit within 32 characters you may need to drop the directory from the path and either put the icon in the current directory or in the default A-Shell icon search path—e.g. the cache, permcache, or icons subdirectories.

tip1 - tip5 (String) [in]

optional tool tips for up to 5 buttons.

fontface (String) [in]

optional font to use

fontscale (Num) [in]

optional font scale adjustment in percent. 0 is treated the same as 100 percent. In modern high-res environments, you may find that increasing the font size makes for a more readable message. Note that the font scale does not affect the title bar, but it does affect nearly everything else in the message box. See note under iconspec.

fgc (Num) [in]

optional RGB value to use for the message text.

bgc (Num) [in]

optional RGB value to use for the background of the message.

Examples

Standard Abort/Retry/Ignore message box in both GUI and plain text versions:

xcall MSGBOX, "Best man tried on ring, can't get it off!", "Wedding Crisis", 2, &h0030, 0, rtncde

Enhanced version with custom buttons, hyperlink colors...

msg$ = "Obamacare repealed - how do you want to pay? (Click link below to complain)"

title$ = "Emergency Room Cashier Encounter"

link$ = "<a href=""http://www.whitehouse.gov"">White House</a>"

icon$ = "first_aid::ashico1"

btn1$ = "Cash" : btn2$ = "Medicare" : btn3$ = "Private Ins" : btn4$ = "" : btn5$ = ""

tip1$ = "If you got it" : tip2$ = "Ages 65+ only" : tip3$ = "If you can afford it"

font$ = ""

fontscale = 150

bgc = &hddddff ! pink background

xcall MSGBOX, msg$, title$, 0, 0, 0, rtncde, 0, 0, 0, link$, icon$, btn1$, btn2$, btn3$, btn4$, btn5$, tip1$, tip2$, tip3$, tip4$, tip5$, font$, fontscale, fgc, bgc

Enhanced version with icon buttons...

title$ = "Music Player"

msg$ = "Current selection: "+chr(13)+chr(13) "I've been working on the A-Shell..."

icon$ = "music::ashico1"

link$ = ""

btn1$ = "media_beginning::ashico1" : btn2$ = "media_rewind::ashico1" : btn3$ = "media_play::ashico1"

btn4$ = "media_fast_forward::ashico1" : btn5$ = "media_end::ashico1"

tip1$ = "beginning" : tip2$ = "rewind" : tip3$ = "play" : tip4$ = "fast forward" : tip5$ = "end"

font$ = "Comic Sans MS"

fontscale = 200

xcall MSGBOX, msg$, title$, 0, 0, 0, rtncde, 0, 0, 0, link$, icon$, btn1$, btn2$, btn3$, btn4$, btn5$, tip1$, tip2$, tip3$, tip4$, tip5$, font$, fontscale

Comments

Standard vs custom buttons: the original version of the message box offered several standard sets of buttons (OK, YES/NO, etc) as specified by the btnflag parameter, and returned a code unique to each button's meaning, rather than its position. So MBRC_CANCEL means the same regardless of whether the CANCEL button was in the 2nd or 3rd position. The enhanced version allows you to specify an arbitrary set of up to 5 buttons, and gives you the choice of treating those as substitutes for the standard button labels, still using the MBRC_xxx rtncde values, or as totally arbitrary buttons (identified by button position in rtncde values 101-105), based on the mxflag MBX_RCBTNO flag. For example, if you set btnflag to MBTN_YES_NO, but specify btn1="Good" and btn2="Bad", unless you set the MBX_RCBTNO flag, the "Good" button will act as the YES button (returning MBRC_YES) and the "Bad" button will act as NO (returning MBRC_NO). This might make sense in some cases, but in general it will probably be best to explicitly set the MBX_RCBTNO flag to return the button number (101 thru 105) when using customized labels. There are two cases where the MBX_RCBTNO flag will be implicitly set. The first occurs when the number of custom buttons defined is more than the number in the standard set as specified by btnflag. In that case, the additional buttons will always return the position code (101-105). The second occurs when btnflag is set to zero and more than one custom button label is defined (i.e. when btn2 is non empty). Although btnflag value zero is equivalent to MBTN_OK, it seems clear that if two or more custom buttons are defined, the intended meaning of btnflag zero is not MBTN_OK but "custom buttons only". This allows you to leave both btnflag and mxflag at zero with a set of custom buttons while avoiding the confusion of the first button returning MBRC_OK while the other buttons return values 102 thru 105.

Aside from the features documented above, an advantage of the enhanced message box is that although it forces you to respond to the message box before returning to the application (i.e. it is task modal), it allows you to access the A-Shell menu bar, for example, to use the Print Screen utility.

See Also

• AG_MESSAGEBOXSTD

History

2017 January, A-Shell 6.3.1543: Major enhancements and internal rewriting. Add support for up to five buttons, customizeable button labels or icons, tool tips, time delay, time out, optional hyperlink field, colors, fonts, etc.

2011 August, A-Shell 5.1.1231: Right-click on the box now reveals a context menu option to print the screen (if the BAS:APRNTSCRN.CFG is configured for print screen).

2011 April, A-Shell 5.1.1210: MBTN_CANCEL_TRY_CONTINUE produces the buttons "Cancel", "Try Again", and "Continue", and returns two new status values MBRC_TRYAGAIN (10) and MBRC_CONTINUE (11). This is actually just an alternate style to the older ABORT/RETRY/IGNORE message box (with ABORT being replaced by CANCEL, RETRY being replaced by TRY AGAIN, and IGNORE being replaced by CONTINUE). The new variation has been used in Windows since W2000, in preference to the older style.

Actually, no change to MSGBOX was necessary to support this new style - it was just a matter of defining symbols for the new codes in ashell.def. The only internal change is that if you specify the new style but are not running in GUI mode, it continues to display in the old style, while behaving compatibly with the new style.

2011 April, A-Shell 5.1.1210: MSGBOX.SBR now checks if the Ctrl and C keys are down, both on entrance and exit. If so, and CTRLC is enabled for the job, error 1 is triggered. Otherwise, it returns the new return status code 12 (MBRC_CTRLC). This should help alleviate a frustrating situation where a program was putting up error message boxes too fast to allow the Ctrl+C keyboard status to be detected between the MSGBOX calls (and Ctrl+C is not recognized as an abort by the standard Windows message box itself).

2009 November, A-Shell 5.1.1164: MBMISC_DEFLT2 and MBMISC_DEFLT3 flags (to select the default button) are now supported in text mode. (Previously text mode always selected the first button.) Also, the Windows version now uses the LDF to get the button labels (the UNIX version has done this for a long time).

2006 March, A-Shell 4.9.953: The text version of MSGBOX.SBR now gets button text from LDF.

2006 Jan, A-Shell 4.9.950: MSGBOX.SBR is now implemented as an internal subroutine (effectively replacing MSGBOX.SBX). There should be no other change in the behavior. If, for some reason, you want to keep using the MSGBOX.SBX, then rename it to something else (e.g. MSGBXX.SBX) and then create an ALIAS:

ALIAS=MSGBOX:MSGBXX

That way, when your application does call MSGBOX, the ALIAS will convert this to MSGBXX, which will find the SBX.


MSGLOG

xcall MSGLOG, text, code, status

MSGLOG.SBR is equivalent to the version under AMOS, except for the format of the OPR:SYSLOG.SYS file. Under AMOS, the file is binary coded and requires SYSLOG.LIT to format and display it. Under A-Shell, the file is a simple text file which can be printed or displayed directly.


NFIND

xcall NFIND, string, stpos, endpos, char, pos

NFIND.SBR is similar to the BASIC INSTR() function, except with more sophistication.

Parameters

string (String) [in]

string to be searched

stpos (Num) [in]

starting position (first byte is number 1)

endpos [in]

ending position to search in the string. Must be greater than or equal to stpos or the result will always be zero. If larger than the length of the string, it will be treated as equal to the length.

char (Str,1) [in]

the character to search for, with two special wildcards: "%" matches any non-space in the substring, and "/" matches non-numeric, non-alphabetic character.

pos (Num) [out]

Returns the position of the matched character, or zero if there is no match within the specified substring.

See Also

• INSTR()

• .INSTRR()


NOECHO

xcall NOECHO {,channel}

As under AMOS, NOECHO.SBR may be used to disable terminal echo within a program. It is usually used in conjunction with GET or some other subroutine for terminal input, such as MicroSabio’s INFLD in order to (a) allow character input, and (b) disable echo. Under A-Shell, NOECHO.SBR does not affect the true state of the terminal, but merely changes the internal operation of A-Shell itself. So, for example, if HOSTEX is used to execute a host command, that command will function in the same way whether or not the NOECHO subroutine had been used.

Under UNIX, a serial port may be opened for input, and then the NOECHO subroutine called with that channel specified, for example:

open #1,"/dev/tty1",input

xcall NOECHO,1

In this case, the true host mode of the port will be changed. Echo will be disabled, cooked mode processing will be disabled and so on, enabling all characters to be received unaltered from the port with the GET routine. This is particularly useful for communicating with external equipment such as modems, time record devices and so on.

If a port’s mode is changed in this way, then it should be reset with NOECHO.SBR before closing the channel. Failure to do this will leave the port in its altered state even when A-Shell is exited.


NUMCHK

xcall NUMCHK, string {,len, rc}

NUMCHK.SBR checks a string to see if it contains valid numeric characters only, and possibly that it is of a certain length.

Parameters

string (String) [in/out]

string to be searched. string is stripped of leading and trailing spaces and tabs and returned that way, regardless of whether valid.

len (Num) [in]

if specified, stripped string length must match.

rc (F,6) [out]

optional return value specifying okay (0), or that string contains invalid characters or is not of len length (-1). Note that NUMCHK may be passed to the XFUNC() function, in which case rc is not really relevant since the function itself returns the same value.

History

2006 August, A-Shell 4.9.963: Add rountine to A-Shell.


ODTIM

xcall ODTIM, stringfmt, odate, otime, flags

ODTIM.SBR performs the reverse function of IDTIM.SBR, i.e. it converts an internal format date and/or time to a string format. Its formatting options are much more extensive, however, than the formats allowed by IDTIM.

Parameters

stringfmt (String) [out]

the formated date/time string is returned here.

odate (Num) [in]

should contain the internal (aka "separated" – see IDTIM for details) date to be formatted. 0 is taken to mean the current date.

otime (Num) [in]

should contain the internal time to be formatted, with 0 indicating the current time.

flags (Num) [in]

must specify a sum of desired formatting options from the following table:

Value | Meaning
&h0000001 | Omit date from output (ignore all other date related flags)
&h0000002 | Output the day of the week
&h0000004 | Use the full name of the day of the week; else use the first three characters
&h0000008 | Output the month as a number (1-12) and ignore flag &h0010.
&h0000010 | Output the full name of the month; else use the first character abbreviation
&h0000020 | Output four digit year; else two digit year
&h0000040 | Output the month first, then the day; else the day first, then the month
&h0000080 | If &h0100 not specified, use spaces to separate the parts of the date, as in 17 Jul 2013. If &h0100 is also specified (i.e. &h0080 + &h0100) then use separator character defined in the language definition file (LDF).
&h0000100 | If &h0080 not specified, use slashes to separate the parts of the date, as in 7/17/03. If &h0080 is also specified, use LDF separator character (see above).
&h0000200 | Omit time from output (ignore all other time related flags)
&h0000400 | Omit seconds from the time output
&h0000800 | Use 12 hour time format with AM/PM; else use 24 hour format
&h0001000 | Do not output a separator between the hours and minutes (also see &h0020000)
&h0002000 | Use colon as the time separator; else use the character defined in the LDF
&h0004000 | Suppress leading zeroes from numeric portion of date.
&h0020000 | Do not output a separator between the minutes and the seconds
&h0400000 | Do not output date punctuation
&h0800000 | Do not output the day
&h1000000 | Do not output the month
&h2000000 | Do not output the year

Hex-Decimal Values

Comments

If flags is set to 0, the output will appear like this: 17-Jul-03 13:15:58. The special flags value –1 overrides the bit settings in the table and outputs a complete time and date string in the format: Monday, July 17, 2013 01:15:58 PM (with appropriate adjustments based on the language definition file).


PCKLST

Updated and reviewed July 2011

xcall PCKLST, row, col, answer, array, maxcnt, prompt, exitcode {,strow, endrow, flags, file, mmoclr}

PCKLST.SBR displays a list of items in a box (aka a "pick list"), optionally waiting for the user to select one. Besides simplifying this common user interface element, it can operate in either text or GUI modes, making the decision at runtime based on external factors, and with a good deal of compatibility between them.

In GUI mode, PCKLST acts as an alias for a simple selection XTREE, while in text mode it acts as a wrapper for the vertical menu mode of INMEMO.

Developers committed to the GUI environment should consider PCKLST deprecated and just use XTREE directly, while those interested in both text and GUI (or text only) should use PCKLST.

Parameters

row, col (Num)

If XTF_XYXY is not specified in flags, these are the locations where the ordinary field input would have taken place. The pick list box is drawn around the position where the field was or would have been (to give it the flavor of a drop-down box). If XTF_XYXY flag is specified, these are interpreted as the top left character position of the box (i.e. starting row, starting col).

answer (Num)

On exit, answer is set to the Row number of the selection (first row is numbered 1). On input, answer specifies the default position of the selection bar. Range is limited to 0-65535.

array (String array or Raw )

is an array of strings containing the choices for the pick list. The end of the array is marked by the first null entry or maxcnt. Note that the array element size must be large enough to accommodate at least one trailing null on each element. Any text in an array element following a backslash will be treated as "hidden text", meaning that it will not be displayed (nor used in determining the box display width). See note in History, below.

maxcnt (Num)

is the maximum number of elements in the array.

prompt (String)

If XTF_COLDFX is not specified in flags, contains the string to display in the top border of the box as a title or prompt. If the string contains an embedded CHR$(13), the remainder of the string will go on the bottom border of the box. See the documentation on XTF_COLDFX for details on the interpretation of this parameter when XTF_COLDFX is specified.

exitcode (Signed Num)

will return a code indicating how the pick list was exited, with 0 indicating the normal exit via the Enter key, and 1 indicating Escape. See the flags parameter below for enabling other exit keys.

strow, endrow (Num)

if specified, determine the top and bottom display position of the box. Otherwise the box is likely to extend both above and below the row specified by the row parameter, according to some kind of primitive internal heuristics. (Set to 0 as a placeholder if needed for subsequent parameters.)

If the XTF_XYXY bit is set in the flags parameter, strow and endrow are reinterpreted as the ending row and ending column (bottom right corner) of the box, whose top left corner will be set by row and col. This is the more traditional method for specifying the coordinates of a box, as used by XTREE.

flags (Num; two element array of B,4)

may be used to specify zero or more options from the tables below. See XTREE Flags for details on mapping this parameter. Note that while this parameter is generally compatible between PCKLST and XTREE, many of the XTREE flags are ignored by PCKLST. To simplify, the tables below list only the flags that are recognized by PCKLST, or for which the interpretation differs between PCKLST and XTREE. The XTF_xxx symbols are defined in ASHINC:xtree.def.

Symbol | Value | Description
XTF_FKEY | &h00000001 | Allow F1-F16 (returning Exitcodes -1 through –16)
XTF_LEFT | &h00000002 | Enable Left arrow (Exitcode -40)
XTF_RIGHT | &h00000004 | Enable Right arrow (Exitcode –41)
XTF_UP | &h00000008 | Enable Ctrl+Up Arrow on first row (Exitcode -42)
XTF_TAB | &h00000020 | Enable Tab (Exitcode -44), and Shift+Tab (Exitcode -35)
XTF_HOME | &h00000040 | Enable Home key (Exitcode –45)
XTF_END | &h00000080 | Enable End key (Exitcode –46)
XTF_NOAS | &h00000100 | Disable auto-shrink of box height to match amount of data. (This flag is ignored by XTREE since it does not support auto-shrink.)
XTF_MODELESS | &h00000200 | Leave list box on the screen after exit from the subroutine.
XTF_TIMOUT | &h00000400 | For the PCKLST (text mode) only, sets a 200 second timeout—i.e., acts as if user had hit Escape. For XTREE, ignored; use XTR'TIMEOUT instead.
XTF_FST | &h00000800 | Fast selection mode. In PCKLST, this means menu items can be selected by entering the minimum number of characters to uniquely identify the item. (Without the XTF_FST flag, Enter would be required to complete the selection.) For XTREE, this means that a single click (completes the selection operation, rather than requiring a double-click or a click followed by Enter).
XTF_XYXY | &h00002000 | Interpret the 1st and 2nd parameters (row, col) as starting row, starting col, and the 8th and 9th parameters (strow, endrow) as ending row, ending col. Mandatory for XTREE, optional for PCKLST.
XTF_COLDFX | &h00040000 | Indicates that the prompt parameter is actually an XTREE advanced Coldef syntax specification, rather than simply a title string.
XTF_NOSEL | &h00100000 | Exit immediately, rather than waiting for the user to make a selection. (This only makes sense in conjunction with XTF_MODELESS; also see xtrctl XTR'OPCODE)
XTF_DEL | &h00400000 | Enable Del exit (Exitcode –47)
XTF_CTRLC | &h01000000 | Causes Ctrl+C to set Exitcode 10 (as in INFLD) instead of 1.

Symbol | Value | Description
XTF2_PGUPDN | &h00000040 | Enable PgUp/PgDn (exitcodes 4, 6).
XTF2_DOWN | &h00000080 | Enable Ctrl+Down on last row (exitcode -43).
XTF2_SAVRES | &h00008000 | Causes PCKLST to save the screen area.

Hex-Decimal Values

file (String)

specifies a sequential file to be used instead of the Array parameter. When non-null, the interpretation of Array, Maxcnt, and Answer parameters changes as follows. Array becomes an ordinary string which is used to pass in the default selection (text) and to get back the item chosen by the user. Answer and Maxcnt are then ignored (with the actual contents of the file being examined to determine Maxcnt and the maximum width).

mmoclr

may be used to specify a set of colors for the various parts of the pick list display. It is equivalent to the

INIX

Documentation added May 2016

xcall INIX, inifile, opcode, section, item {, value, dftvalue}

INIX.SBX reads/writes from standard "INI" files, which are ordinary text files, typically with a .INI or .CFG extension, which are made up of one or more groups (sections) of item=value pairs as follows: xe "INIX.SBR"

[section]

item1=value

item2=value

etc.

Because these files can be edited in a standard text editor, and because comment lines beginning with a semicolon may be inserted anywhere, the format is both easy to use and self-documenting. There is no particular limit to the number of items or sections, but each item name within a section must be unique.

Source, samples and related functions can be found in SOSLIB:[907,26].

Parameters

inifile (String) [in]

File spec of the INI file.

opcode (Num) [in]

Operation to perform:

Value | Meaning
0 | Read single item=value pair
1 | Write single item=value pair
2 | Delete single item=value pair
3 | Delete complete section

In addition, you may add either or both of the following options in the ATE environment:

Value | Meaning
+16 | redirect the operation to the ATE client
+32 | first sync INIX.SBX from the server to the ATE client

section (String) [in]

Name of section; without the brackets, case sensitive

item (String) [in]

Name of item to read or write; case sensitive

value (String) [in/out]

For the read operation, the value is returned here. Note that if the item is not found within the specified section, the default value will be returned here, assuming the dftvalue parameter was specified. For the write operation, this will be the value to write.

dftvalue (String) [in]

For the read operation, supplies the default value of the item if the item is not defined

Comments

When writing, if the file does not exist, it will be created, and if the specified section does not exist, the section and item will be added to the end of the file. For example:

xcall INIX, "foo.ini", 1, "Favorites", "Beatle", "Ringo"

If the foo.ini file didn't previously exist, then after the above call, it would exist and contain:

[Favorites]

Beatle=Ringo

If we then wrote another item using ...

xcall INIX, "foo.ini", 1, "Favorites", "Position", "On Top"

... the file would be updated to contain:

[Favorites]

Beatle=Ringo

Position=On Top

Note that neither the order of the sections nor the order of the items is significant.

If we then retrieve three values from the file with the following ...

xcall INIX, "foo.ini", 0, "Favorites", "Beatle", fabguy$, "Paul"

xcall INIX, "foo.ini", 0, "preferences", "Position", pos$, "upside down"

xcall INIX, "foo.ini", 0, "Favorites", "Musician", player$, "Leadbelly"

The results would be:

? fabguy$ ! "Ringo"; (default "Paul" ignored)

? pos$ ! "upside down" (no such section "preferences"; use default)

? player$ ! "Leadbelly" (no such item "Musician"; use default)

Attempting to read from a non-existent INI file is equivalent to attempting to retrieve non-existent items; you get back the default value specified in each read operation, or "" if no default specified.

Despite the lack of order or indexing, INIX is quite efficient, particularly at reading, since the file gets cached in memory on the first access. Updates to the file do require the entire file to be rewritten, but this is still reasonably efficient, particularly if the total file size is "reasonable" (say, under 32K or so), and if read operations outnumber writes, as they usually do with these kinds of configuration files.

INIX.SBX was initially created and contributed to the SOSLIB by Steve Evans. It has since been adopted as a standard A-Shell routine, and is used extensively by many A-Shell modules. The source is available in [907,26] of the SOSLIB repository.

INMEMO parameter of the same name, which is not surprising, since PCKLST.SBR is actually just a front-end to the vertical menu mode of INMEMO.SBR. The format of MMOCLR is:

MAP1 MMOCLR

MAP2 BFCLR,B,1,-1 ! Border Foreground

MAP2 BBCLR,B,1,-1 ! Border Background

MAP2 TFCLR,B,1,-1 ! Text Foreground

MAP2 TBCLR,B,1,-1 ! Text Background

MAP2 AFCLR,B,1,-1 ! Arrow Foreground

MAP2 ABCLR,B,1,-1 ! Arrow Background

MAP2 PFCLR,B,1,-1 ! Prompt Foreground

MAP2 PBCLR,B,1,-1 ! Prompt Background

MAP2 WFCLR,B,1,-1 ! Warnings & messages Foreground

MAP2 WBCLR,B,1,-1 ! Warnings & messages Background

MAP2 SFCLR,B,1,-1 ! Orig. Status line Foreground

MAP2 SBCLR,B,1,-1 ! Orig. Status line Background

MAP2 RFCLR,B,1,-1 ! Inactive selection bar - see Comments

MAP2 RBCLR,B,1,-1 ! Inactive selection bar - see Comments

The individual fields within MMOCLR are shown above initialized to -1, which is what you must do to get default colors, since color 0 is black. (Specifying MMOCLR with all the fields un-initialized will result in a not-very-interesting black on black display.)

Comments

If XTF_XYXY not specified, the width of the box will be determined by considering the maximum length of the top and bottom prompts and the data items (not counting any hidden text). If XTF_XYXY is specified, then the coordinates of the box are explicitly determined by the row,col (upper left) and strow,endrow (interpreted as lower right row/col) parameters.

Rather than setting colors in individual calls to PCKLST, it would be easier to set them globally in the LIB:INI:CLR file. See Configuration for more details.

When the XTF_COLDFX flag is specified, the prompt parameter is assumed to be in the format of an XTREE advanced Coldef syntax definition with a single column. From this string, the ctitle field is extracted and used for the top title. (cpos is ignored and assumed to be 1; cwidth must be greater than or equal to the actual width of the elements of array; cformat is ignored.) The main advantage of using this alternate form is to make it easier for a program that operates in both text and GUI modes to take advantage of the features of XTREE without breaking PCKLST compatibility. PCKLST will ignore all of the Advanced Coldef Options that it doesn't understand, but there is one that it does: SelChgExit=###. For example:

prompt = "1~20~Selections~S~SelChgExit=155~~"

The above example would set the title to "Selections", and tell PCKLST to exit with exitcode -155 whenever the selection changes.

Inactive selection bar colors: Normally, when you exit from PCKLST, the bar indicating the selected item remains displayed, exactly as when the menu was active. This is typically desirable, or doesn't matter, but there are some situations where it is useful to provide some visual indication that the list (and selection process) are no longer active. XTREE handles this by changing the standard selection bar (dark blue) to light gray. PCKLST provides you an option to redisplay the selection bar in a different color scheme, by setting the RFCLR and RBCLR fields of the mmoclr structure to the desired colors. If left at the default values of -1, the selection bar is left as-is.

See the sample program PCKMNU.BP in [908,21] of the EXLIB for an example of a two-level menu program using PCKLST which operates in either text or GUI mode.

PCKLST supports a maximum of 32K rows.

Example

The following screens are from a single menu implementation, using two side-by-side PCKLST controls, as it appears in text and GUI modes. See PCKLST.BP[908,21] in the SOSLIB for the actual program.

Background and Additional Notes

Originally, PCKLST was created to provide a simplified way of accessing INMEMO's menu mode with the idea of upgrading a functionally equivalent INFLD operation to be more user friendly. In other words, rather than call INFLD to have the user type one of the allowed options, the program could call PCKLST to perform the same function—input a field—but in a way that allows the user to easily see the choices and select one without actually typing it. For example:

Screen save/restore was built in to PCKLST, so there was no need to worry about the parts of the screen that would be temporarily covered by the pick list (making it easier to upgrade a screen designed to allow only a single line for the input field).

With the advent of GUI capabilities in A-Shell, a more powerful Windows list/selection control (XTREE) was implemented, but with the same parameter interface. This allows A-Shell to redirect calls to PCKLST to the XTREE if the environment supports GUI and the feature is enabled in the miame.ini (via SBR=PCKLST_GUI). Over time, XTREE grew to support so many extended capabilities unrelated to PCKLST that it is now difficult to recognize the parts of XTREE that are compatible with, or even related to PCKLST. So we've tried to keep it simple for PCKLST developers by keeping separate documentation, while trying to note the areas of particular similarity or difference between the two routines.

History

2011 June, A-Shell 5.1.1221 and 1220:

• XTF2_SAVRES causes PCKLST to save the screen area.

• XTROP_DELETE operation to clear the screen area used by the list is now supported.

• XTREE-style title justification codes ("| ","< ","> ") are now supported for the top title.

• The XTF_NOSEL flag bit is now supported.

• The SelChgExit=### advanced coldef option is now supported.

• RFCLR, RBCLR now affect inactive selection bar.

• The prompt parameter can now use the XTREE advanced Coldef syntax.

2004 March, A-Shell 4.9.871: PCKLST now allows the array argument to be passed as an unformatted variable, which gives you more flexibility in creating variable sized pick lists. Previously, for the array mode, you had to specify the first element, i.e. ARRAY(1), so that it the subroutine could determine the size of the array elements. Now, you can pass an unformatted variable which the array is overlaid upon, and PCKLST will determine the element size by looking at the spacing between the first and second elements in the array. For example:

MAP1 ARRAYX

MAP2 ARRAY(50),S,13

xcall PCKLST,ROW,COL,ANSWER,ARRAYX,MAXCNT,PROMPT, &

EXITCODE,STROW,ENDROW,FLAGS,"",MMOCLR

In order for this to work, there must be at least one trailing null terminating the ARRAY(1) element. Note that by using the overlay feature, you could support several array layouts with the same XCALL PCKLST, i.e.:

MAP1 ARRAYX2,@ARRAYX

MAP2 ARRAY2(10),S,60

MAP1 ARRAYX3,@ARRAYX

MAP2 ARRAY3(80),S,8

etc.


PLYJOB

xcall PLYJOB, jobno, job'stats

PLYJOB.SBR is similar to GETJTB in that it returns most of the information related to your job in a single operation. The main reason it is included in addition to GETJTB.SBR is for PolyTrack programmers who may already be using the routine, and for anyone who may be using the MicroSabio routine JOBPAR.SBR (which is basically the same thing and can be aliased to PLYJOB using the alias facility in miame.ini). PLYJOB.SBR does have one feature that GETJTB.SBR does not: the ability to retrieve information about a job other than the current one. The amount of information that can be retrieved in this way is limited to job name, program name, ppn, and username, but that is still very useful in situations where you want to match a job number up with a job name.

Parameters

jobno (2-byte binary) [in/out]

If zero, information is returned about the current job, otherwise about the job whose number is specified.

job'stats

mapped as follows:

MAP1 JOB'TABLE ! 87 byte area

MAP2 LOG'DEV,s,3 ! Device name

MAP2 LOG'LUN,s,3 ! Logical unit

MAP2 PROJECT,s,3 ! Project number (p,pn)

MAP2 PROGRMR,s,3 ! Programmer number

MAP2 PARTITION,s,6 ! Job name

MAP2 PROG'ID,s,6 ! Program name

MAP2 TERM'NAME,s,6 ! Trmdef name

MAP2 TERM'DRVR,s,6 ! Terminal driver

MAP2 INTERFACE,s,6 ! IDV name

MAP2 JOB'NBR,s,3 ! Job number

MAP2 JOB'TYPE,b,2 ! Job type flags

MAP2 CMDFIL,b,2 ! Nonzero=command file

MAP2 JOBPPN,b,2 ! P,PN as binary

MAP2 JOBEXP,b,1 ! Job experience

MAP2 JOBLVL,b,1 ! Job level

MAP2 JOBUID,s,3 ! Numeric portion of username

MAP2 JOBUSN,s,20 ! Job user name

MAP2 JOBCPU,b,4 ! CPU time

MAP2 JOBDSR,b,4 ! Disk reads

MAP2 JOBDSW,b,4 ! Disk writes

MAP2 JOBATT,s,6 ! Parent job name

MAP2 JOBSTS,b,2 ! Job status

MAP2 TRKVER,s,3 ! Tracker version [22C]

Several of the fields above are only applicable under the AMOS version of PLYJOB, including JOBCPU, JOBDSR, JOBDSW, JOBATT, JOBEXP, and JOBLVL.


PRTCHK

xcall PRTCHK, printer, rtncde

Under AMOS, PRTCHK.SBR may be used both to check for the existence of a printer, and to check whether a particular file is being printed. The A-Shell implementation contains only the first function, due to the limitations of either the spooling systems, or the interfaces to those spooling systems, of the operating systems on which it runs.

Parameters

printer (String) [in]

A-Shell spooler name to check

rtncde (F or String) [in/out]

For type F, returns zero if the printer is found, else one. For type S, returns "F" if the printer is found. To be certain of the result, you should preset the variable to some other value first. Note that "found" means only confirmation of the logical existence of the spooler—i.e. the routine tests whether a corresponding printer init file (DSK0:printer.INI[1,4] or DSK0:printer.PQI[1,7]) exists.

Apparently some versions of PRTCHK.SBR work the opposite way, returning 1 if the printer is found and 0 if it is not. To get this behavior, add SBR=PRTCHK1 to the miame.ini file. This option only applies when rtncde is a floating point variable.


PUTBYT

xcall PUTBYT, channel, buffer, bytes

PUTBYT.SBR writes raw bytes to a sequential output file.

Parameters

channel (Num) [in]

is the channel number of the file, which must be open for output or append.

buffer (Raw) [in]

supplies the data to be written.

bytes (Num) [in]

specifies the number of bytes to write (which must be less than or equal to the size of buffer).

Comments

xcall PUTBYT, channel, buffer, bytes

is equivalent to

PRINT #channel, buffer[1,bytes];

See Also

• GETBYT

History

2006 February, A-Shell 4.9.950: PUTBYT.SBR now supports channel 0 to output to the terminal device. This can be useful (mainly under UNIX) if you need to output raw binary data to the terminal and want to be sure there is no filtering and do not want it to corrupt the screen map. Otherwise, typically you get Tab expansion (unless OPTIONS=RAWTABS), and CR is always prepended to line LF characters.


REGEX

Updated March 2017; see History

Pre-compiling only:

xcall REGEX, pattern, patno

General use:

xcall REGEX, pattern, status, subject {,flags, stpos, match { ,subcnt, submatch1, ... submatchn}}

xcall REGEX, pattern, status, subject ,flags, stpos, match ,subcnt, submatch(n)

REGEX.SBR provides a detailed XCALL interface to A-Shell's regular expression processor. Other interfaces to the same processor are provided in the INSTR() function and INFLD.

The first general syntax shown above is the traditional form, which uses individual submatch variables to receive the submatch results. The second, introduced in A-Shell 5.1.1210 of March 2011, uses an array to receive the submatch results.

Parameters

pattern (String) [in]

Regular expression, without the Perl-style leading/trailing slash. To specify a pre-compiled pattern, set pattern= chr$(1) thru chr$(20) for the 20 precompiled patterns. Note that when using the same pattern string consecutively, explicit pre-compiling is superfluous; all pattern strings get internally pre-compiled, and whenever the current pattern string is the same as the previous one, the previously pre-compiled pattern is used automatically. Explicit pre-compilation only makes sense when you are repetitively using more than one pattern string in alternation.

status (F or I) [out]

Value | Returned status values
>0 | Matching success (starting position of match)
-101 to -199 | Pattern Complilation Errors
-99 | Too few parameters
-98 | Unable to load PCRE library (PCRE3.DLL under Windows)
-97 | Unable to allocate memory for library
-96 | Unable to link to pcre_compil2 or pcre_exit function in lib
-95 | Invalid pre-compiled pattern number (1-20)
-94 | No such precompiled pattern (not previously compiled)
-93 | Error outputting to dynamic variable (out of memory?)
-2 to -25 | Matching Errors

patno (F or I) [in/out]

For precompiling, on input must be set to an integer 1-20 (for the 20 numbered precompiled patterns). On output, will still be set to the same value for success, or <=0 on error; see status codes above. See note under pattern regarding pre-compilation.

subject (String) [in]

Subject string to test against the pattern.

flags (F or B,4) [in]

A bitmap of option flags whose symbols are defined in ASHINC:regex.def. See Options Flags. Note that you can use Perl-style internal option settings within a pattern to change options that would otherwise require using the flags parameter.

stpos (Num) [in]

Optional starting position in subject, base 1. If not specified or zero, treated same as 1 (i.e. start at beginning of subject).

match (String) [out]

Returns the string within the subject that was matched. On errors, it may return the text of the error description.

subcnt (Num) [in/out]

For the array syntax (where the subexpression matches are returned into an array instead of individual parameters), you must set subcnt to the number of elements in the array, starting from the element supplied in the parameter. In other words, if you pass submatch(1), then set subcnt to the total number of elements in the submatch() array; if you pass submatch(2), set subcnt to one less than the total.

For the non-array syntax, subcnt is ignored on input; the maximum number of possible matches is limited instead by the number of submatch1 .. submatchn parameters passed.

For either syntax, on return, subcnt will be set to the number of sub-expression matches in the subject, even if it exceeds the number of submatch parameters passed or the specified size of the submatch(n) array. Therefore, when processing the returned sub-expression matches, care must be taken that you don't get fooled by the return value of subcnt into trying to access more submatch parameters than were available to the routine or especially more array elements than exist. For example:

subcnt = .extent(submatch()) ! limit matches to extent of array

xcall REGEX, pattern, status, subject, flags, match, subcnt, submatch(1)

if status > 0 then ! on success...

for i = 1 to (subcnt min .extent(submatch())) ! process sub-matches (up to limit)

...

submatch1 ... submatchn (String) [out]

These return subexpression matches (up to the number specified by subcnt, up to a maximum number of 100 (increased from 20 in A-Shell 5.1.1210). Note that null matches are quite possible; that is, subcnt may return N, but of those N, some of them, and not necessarily only the ones at the end, may be empty.

submatch(n) (String array) [out]

A single starting element in a string array, e.g. submatch(1), may be used in place of several individual submatchn parameters. The array must have a fixed number of elements, but its elements can be dynamic strings (e.g. map1 submatch(50),s,0). This is particularly useful where you are dealing with many expressions and thus don't know at the time of writing the code how many or how large they might be.

Note: Since the xcall interface does not pass information about the entire array, in order to use the array syntax, you must set subcnt to the number of elements in the array (see subcnt above), AND you must also set the PCREX_SUBMATCH_ARRAY (&h40000000) flag in the flags parameter. If the flag is not set, REGEX will treat your submatch(1) parameter as a single variable (as in the first syntax).

History

2017 March, A-Shell 6.4.1546: remove 1024 byte limit on subject string length.

2011 March, A-Shell 5.1.1210: Allow an array in place of individual sub-match parameters. Increase number of allowed sub-matches from 20 to 100. Revise and review documentation.

2008 April, A-Shell 5.1.1108: Re-vamped, re-organized and re-documented.

2007 Nov, A-Shell 5.1.1100: Add routine to A-Shell


Pattern Complilation Errors

Value | Description
-101 | \ at end of pattern
-102 | \c at end of pattern
-103 | unrecognized character follows \
-104 | numbers out of order in {} quantifier
-105 | number too big in {} quantifier
-106 | missing terminating ] for character class
-107 | invalid escape sequence in character class
-108 | range out of order in character class
-109 | nothing to repeat
-110 | [this code is not in use]
-111 | internal error: unexpected repeat
-112 | unrecognized character after (?
-113 | POSIX named classes are supported only within a class
-114 | missing )
-115 | reference to non-existent subpattern
-116 | erroffset passed as NULL
-117 | unknown option bit(s) set
-118 | missing ) after comment
-119 | [this code is not in use]
-120 | regular expression too large
-121 | failed to get memory
-122 | unmatched parentheses
-123 | internal error: code overflow
-124 | unrecognized character after (?<
-125 | lookbehind assertion is not fixed length
-126 | malformed number or name after (?(
-127 | conditional group contains more than two branches
-128 | assertion expected after (?(
-129 | (?R or (?[+-]digits must be followed by )
-130 | unknown POSIX class name
-131 | POSIX collating elements are not supported
-132 | this version of PCRE is not compiled with PCRE_UTF8 support
-133 | [this code is not in use]
-134 | character value in \x{...} sequence is too large
-135 | invalid condition (?(0)
-136 | \C not allowed in lookbehind assertion
-137 | PCRE does not support \L, \l, \N, \U, or \u
-138 | number after (?C is > 255
-139 | closing ) for (?C expected
-140 | recursive call could loop indefinitely
-141 | unrecognized character after (?P
-142 | syntax error in subpattern name (missing terminator)
-143 | two named subpatterns have the same name
-144 | invalid UTF-8 string
-145 | support for \P, \p, and \X has not been compiled
-146 | malformed \P or \p sequence
-147 | unknown property name after \P or \p
-148 | subpattern name is too long (maximum 32 characters)
-149 | too many named subpatterns (maximum 10,000)
-150 | [this code is not in use]
-151 | octal value is greater than \377 (not in UTF-8 mode)
-152 | internal error: overran compiling workspace
-153 | internal error: previously-checked referenced subpattern not found
-154 | DEFINE group contains more than one branch
-155 | repeating a DEFINE group is not allowed
-156 | inconsistent NEWLINE options
-157 | \g is not followed by a braced name or an optionally braced non-zero number
-158 | (?+ or (?- or (?(+ or (?(- must be followed by a non-zero number


Matching Errors

Updated and Reviewed March 2011

Value | Description
-2 | (Internal error) ovector was NULL and ovecsize was not zero.
-3 | An unrecognized bit was set in the options argument.
-4 | PCRE stores a 4-byte "magic number" at the start of the compiled code, to catch the case when it is passed a junk pointer and to detect when a pattern that was compiled in an environment of one endianness is run in an environment with the other endianness. This is the error that PCRE gives when the magic number is not present.
-5 | While running the pattern match, an unknown item was encountered in the compiled pattern. This error could be caused by a bug in PCRE or by overwriting of the compiled pattern.
-6 | If a pattern contains back references, but the ovector that is passed to pcre_exec() is not big enough to remember the referenced substrings, PCRE gets a block of memory at the start of matching to use for this purpose. If the call via pcre_malloc() fails, this error is given. The memory is automatically freed at the end of matching.
-7 | This error is used by the pcre_copy_substring(), pcre_get_substring(), and pcre_get_substring_list() functions. It is never returned by pcre_exec().
-8 | The backtracking limit, as specified by the match_limit field in a pcre_extra structure (or defaulted) was reached. See the description above.
-9 | This error is never generated by pcre_exec() itself. It is provided for use by callout functions that want to yield a distinctive error code. See the pcrecallout documentation for details.
-10 | A string that contains an invalid UTF-8 byte sequence was passed as a subject.
-11 | The UTF-8 byte sequence that was passed as a subject was valid, but the value of startoffset did not point to the beginning of a UTF-8 character.
-12 | The subject string did not match, but it did match partially. See the pcrepartial documentation for details of partial matching.
-13 | The PCRE_PARTIAL option was used with a compiled pattern containing items that are not supported for partial matching. See the pcrepartial documentation for details of partial matching.
-14 | An unexpected internal error has occurred. This error could be caused by a bug in PCRE or by overwriting of the compiled pattern.
-15 | This error is given if the value of the ovecsize argument is negative.
-21 | The internal recursion depth limit has been exceeded. This has been set internally to 2500 for Windows and 10000 for UNIX, which in theory is about as much as we could expect to handle before running the risk of a stack overflow and segmentation fault. If you are hitting this limit, either your pattern/subject combination is enormously complex, or, more likely, your pattern is inefficiently designed to cause more recursion that is necessary.
-23 | An invalid combination of PCRE_NEWLINE_xxx options was given.


Options Flags

Updated and Reviewed March 2011

Symbol | Value | Description
PCRE_CASELESS | &h0001 | If this bit is set, letters in the pattern match both upper and lower case letters. It is equivalent to Perl's /i option, and it can be changed within a pattern by a (?i) option setting. In UTF-8 mode, PCRE always understands the concept of case for characters whose values are less than 128, so caseless matching is always possible. For characters with higher values, the concept of case is supported if PCRE is compiled with Unicode property support, but not otherwise. If you want to use caseless matching for characters 128 and above, you must ensure that PCRE is compiled with Unicode property support as well as with UTF-8 support.
PCRE_MULTILINE | &h0002 | By default, PCRE treats the subject string as consisting of a single line of characters (even if it actually contains newlines). The "start of line" metacharacter (^) matches only at the start of the string, while the "end of line" metacharacter ($) matches only at the end of the string, or before a terminating newline (unless PCRE_DOLLAR_ENDONLY is set). This is the same as Perl.
PCRE_DOTALL | &h0004 | If this bit is set, a dot metacharater in the pattern matches all characters, including those that indicate newline. Without it, a dot does not match when the current position is at a newline. This option is equivalent to Perl's /s option, and it can be changed within a pattern by a (?s) option setting. A negative class such as [^a] always matches newline characters, independent of the setting of this option.
PCRE_EXTENDED | &h0008 | If this bit is set, whitespace data characters in the pattern are totally ignored except when escaped or inside a character class. Whitespace does not include the VT character (code 11). In addition, characters between an unescaped # outside a character class and the next newline, inclusive, are also ignored. This is equivalent to Perl's /x option, and it can be changed within a pattern by a (?x) option setting. This option makes it possible to include comments inside complicated patterns. Note, however, that this applies only to data characters. Whitespace characters may never appear within special character sequences in a pattern, for example within the sequence (?( which introduces a conditional subpattern.
PCRE_ANCHORED | &h0010 | If this bit is set, the pattern is forced to be "anchored", that is, it is constrained to match only at the first matching point in the string that is being searched (the "subject string"). This effect can also be achieved by appropriate constructs in the pattern itself, which is the only way to do it in Perl.
PCRE_DOLLAR_ ENDONLY | &h0020 | If this bit is set, a dollar metacharacter in the pattern matches only at the end of the subject string. Without this option, a dollar also matches immediately before a newline at the end of the string (but not before any other newlines). The PCRE_DOLLAR_ENDONLY option is ignored if PCRE_MULTILINE is set. There is no equivalent to this option in Perl, and no way to set it within a pattern.
PCRE_UNGREEDY | &h0200 | This option inverts the "greediness" of the quantifiers so that they are not greedy by default, but become greedy if followed by "?". It is not compatible with Perl. It can also be set by a (?U) option setting within the pattern.
PCREX_SUBMATCH_ ARRAY | &h400000000 | This is not a standard PCRE flag (hence the prefix PCREX_). It is used to indicate that you are passing a single element of an array of subcnt elements to receive the subexpression matches, rather than just a single variable (which could receive only one sub-match).
PCREX_PRECOMPILE | &h80000000 | Another non-standard flag. It is used with the INSTR() function to indicate that you only want to precompile the pattern; see INSTR() for more details.


Background and General Information

Updated and Reviewed March 2011

There are various implementations and flavors of "regular expressions", including POSIX and Perl. We've chosen to go with the Perl flavor, because it is generally considered better—more features, more predictable, faster—and seems to be more popular—with Java, Python and .NET for example using similar or derived implementations. The specific implementation we are using is called PCRE (Perl-Compatible Regular Expression); see the website for more details. Under Windows, it is housed in PCRE3.DLL, which is now included with the standard A-Shell distribution and loaded dynamically the first time you access a regular expression function. For the dynamic linked versions of A-Shell/Linux, there are RPMs named PCRE-#.## where #.## is the current version. Most likely you have one installed already, but if not, you can easily locate and install the current version. The "generic" (static-linked) version of A-Shell/Linux includes the library within the executable module. As of this moment, the AIX version is not yet ready, but will be included in the A-Shell executable, as it is with the generic Linux version.

For details on the syntax of regular expressions, see the Perl Regular Expression documentation or any number of web sites which offer tutorials and examples.

The two most common uses of regular expressions are to extend the power and flexibility of string searches, and to check for valid syntax in a string. Another possible use is for parsing and extracting specific portions of strings, using the capture group mechanism to return the subexpression matches of interest.

The main downside of regular expressions is that they are rather cryptic and can become so complex as to consume massive computing resources (although that is generally not an issue for common usage). As an example, a simple (incomplete) regular expression to match a valid email address word-delimited within a larger string, is:

"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b"

A more complete expression for validating email addresses (based on RFC 2822) is:

"(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|""(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*"")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])"

While it may be doubtful that many users would be able to conjure up such an expression during an ad-hoc search, application developers may build up a collection of useful regular expressions (often you can just copy them from helpful websites devoted to the subject) that can be used for common search or validation purposes.

Regular expression processing internally consists of two separate operations:

• compiling the expression (checking for syntax errors)

• using the expression to match against subject string(s).

Because the operation of compiling the expression can be as CPU intensive as matching it against subject strings, both REGEX.SBR and INSTR() support means of reusing previously compiled expressions. In the default case, if the current pattern matches the previously used one, then the previous compilation will be used automatically. This strategy works well when applying a single expression repetitively against many subject strings (as when searching for a pattern in a text file). But it doesn't work so well if you are searching through a file or database and comparing each line/record against more than one regular expression. To maximize efficiency in such cases, as well as for cases where you have a collection of common patterns used throughout your application, you can precompile and store up to 20 patterns, which can then be used on demand without having to re-compile them.

Note: the original implementation of REGEX.SBR in 5.1.1100 treated a null pattern string as referring to the previously compiled pattern. This mechanism has been dropped, since it is somewhat confusing to implement at the application level, and also introduces the problem of having to specifically check for null patterns. The new implementation just compares the current pattern to the last one (for non-precompiled patterns) to determine when recompilation can be avoided). Null patterns return 0 (failed match) in all cases.

See the sample programs in [908,46] of the EXLIB.

See Substring search right-to-left on the A-Shell Forum for an example of using REGEX to split a path spec into the directory and filename.


License Notes

REGEX.SBR uses the Open Source Perl-Compatible Regular Expression (PCRE) library. Some form of this is typically already installed on most UNIX systems, or can be acquired from http://www.pcre.org/. For Windows, it requires PCRE.DLL, which is included with A-Shell 5.1. For details on the syntax of regular expressions, see the Perl Regular Expression documentation.

PCRE is covered under the BSD license, which requires the following notes be included in the documentation included with A-Shell:

Written by: Philip Hazel

Email local part: ph10

Email domain: cam.ac.uk

University of Cambridge Computing Service, Cambridge, England.

Copyright (c) 1997-2008 University of Cambridge

All rights reserved.

This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.


RENAME

xcall RENAME, oldname, newname, status

RENAME.SBR (aka RENAM) provides the means to programmatically rename files. It will fail if oldname does not exist, or if newname does. Both oldname and newname support either AMOS or native operating system filenames, and also support the use of embedded environment variables (e.g. %MIAME%).

Parameters

oldname (String) [in]

current file name

newname (String) [in]

name to which the file is being changed

status (F,6) [out]

0 if successful, other if not

History

2015 July, A-Shell 6.1.1414: Under Windows, XCALL RENAME will now overwrite an existing destination file. It was never documented what it should do here, but this matches the way it has always worked under UNIX.

The motivation for the change now is that it has been determined that Windows file sharing networks can sometimes yield false positives—i.e. they report that the destination file exists when it doesn't—causing applications to fail unexpectedly and returning an error in the STATUS parameter of XCALL RENAME.

Note that this does not affect RENAME.LIT, nor does it affect the MX_COPYFILE function, which can also be used to rename a file, but which offers an explicit option of whether to replace an existing file.

2007 November, A-Shell 5.0.997: errors are now logged to the ashlog.log file. In addition, if the SYSERR TRACE is active, they will be displayed on the screen. This is helpful in recognizing and tracking down mysterious Windows rename errors.

2006 June, A-Shell 5.0.958: Function now properly handles the renaming of files without extensions and does not append .DAT to the new file name.


RXPCHK

xcall RXPCHK, string {,rc}

RXPCHK.SBR checks a string to determine if it contains unprintable chararacters, which are defined as those whose ASCII values are less than 32 or are between 127 and 160 inclusive.

Parameters

string (String) [in]

string to check. string is stripped of leading and trailing spaces and tabs and returned that way, regardless of whether valid.

rc (F,6) [out]

optional return value specifying okay (0) or the position of the first unprintable character in string. Note that RXPCHK may be passed to the XFUNC() function, in which case rc is not really relevant since the function itself returns the same value.

History

2006 August, A-Shell 5.0.953: Routine added to A-Shell.


RXTERM

xcall RXTERM, exitcode

RXTERM.SBR (Windows only) looks in the type-ahead buffer to see if a function key or Ctrl+C character has been entered, and if so, returns the INFLD-compatible exitcode. This can be useful to short-circuit some program actions and provide immediate response to a function key command.


SBXINP

xcall SBXINP, label, opcode, row, col, xmax, entry, inftype, setdef, maxchars, clickcode, tooltip, parentid, exitcode, defpt, timer, cmdflg, maxpt, infldid, labelid, changeflag

SBXINP.SBX is a wrapper for INFLD. Its biggest single advantage over INFLD is that allows you to associate (and align) a label with an INFLD control, rather than having to handle the label and the edit control in separate operations. This routine was originally developed by Firmaware and is now included as part of the standard subroutine collection.

or, as an xfunc$ function:

map1 inp'result

map2 result'exitcode,s,4

map2 result'values,s,5000

map2 result'id,s,4

map2 result'changed,s,1

inp'result = xfunc$("sbxinp",label,opcode,…)

Source, samples and related functions can be found in SOSLIB:[907,37].

Parameters

label (String) [in]

Controls many of the extended capabilities of SBXINP (relative to INFLD). See the subtopic Label for full information.

opcode (Num) [in]

Determines the operation (edit, display, etc.) according to the following table:

Symbol | Value | Description
SXI_EDT | 1 | Preload field contents and edit the field. (Ignores label)
SXI_DSP | 2 | Display only (create the label; create the edit control to display the data but do not put the focus on it).
SXI_DSPEDT | 3 | Display and edit. Combination of SXI_EDT and SXI_DSP.
SXI_DISABLE | 20 | Add this to disable the field.
SXI_STATIC | 30 | Add this to display field as a static text control.

row (Num) [in]

Row where the field is displayed and edited. (In the case of multi-line fields, this is the top row.)

col (Num) [in]

Starting column of the field (not the label).

xmax (Num) [in]

Determines the width (in current grid units) of the control used to display and edit the field. (Same as INFLD xmax parameter.) If maxchars not specified, then xmax also determines the maximum number of characters that may be entered into the field.

entry (Any type) [in/out]

Field contents. For opcode values except 0, the initial value of entry is preloaded into the field, for display and to establish the initial or default value. On exit, returns the updated field contents. Note that unlike INFLD which requires entry to be a string, SBXINP allows you to pass a numeric data type for fields containing numeric data.

inftype (String) [in]

Same as INFLD type parameter, except that unless inftype starts with a "+", whatever you specify will be added to the following default codes: A]134569kWhsg|G|E

If inftype starts with a "+", then there is no default. The "+" is discarded and inftype is used for the INFLD type string.

There are two special cases: "D>" specifies a Date Picker, and "t" specifies a Time Picker.

setdef (String) [in]

Same as INFLD setdef parameter, except with the following extensions:

To specify a minimum number of allowed characters, append ">#" to the end of setdef, where # is the number.

Set setdef to "@" to cause the field to be validated (by VALIDA.SBX) for valid email format.

maxchars (Num) [in]

Same as INFLD maxchars parameter. If not specified or 0, the maximum number of allowed characters will be equal to the value of the xmax parameter. Setting maxchars larger than xmax allows the field to scroll horizontally (accepting more characters than can be displayed at once). Setting maxchars less than xmax just means that the field will "look" bigger than necessary for the number of allowed characters. Note that the units of xmax are grid units, whereas the units of maxchars are characters. Since characters may requires more or less space than the current grid unit, even when maxchars = xmax, you might have either horizontal scrolling or hit the maxchars limit before filling the display space of the field.

clickcode (Floating point or signed integer) [in]

Specifies the exitcode value to be generated by clicking on this field when the field is not active. Note that this number should be positive even though click exitcodes are generally negative. (Setting clickcode to 400 will cause the field to generate exitcode -400 when clicked.)

tooltip (String) [in]

Text of the tooltip to associate with the field.

parentid (String or Num) [in]

ID of the parent control (tab, groupbox, dialog). If 0, it is assumed to be the current dialog. If it is a non-empty, non-numeric string, it identifies the parent control by its ID name, rather than its number. Also see infldid parameter (which gets combined with this to create the full INFLD parentid parameter).

exitcode (Floating point or signed integer) [in/out]

Same as INFLD exitcode parameter, except that it has significance on input as well as output. If the incoming exitcode matches clickcode, then the routine assumes that you must have activated the field by clicking on it (which may cause different initial or default field behavior than otherwise.)

Special exitcode values: ??

defpt (Num) [in]

Number of display lines for multi-line fields, or the default decimal point position for numeric fields. (Same as INFLD defpt).

timer (Num) [in/out]

Same as INFLD timer.

cmdflg (Num) [in]

Same as INFLD cmdflg.

maxpt (Num) [in]

Same as INFLD maxpt.

infldid (String or Num) [in/out]

Optional ID to assign to, or to retrieve from the INFLD control. (This is combined with the parentid parameter above before being passed to INFLD as its parentid parameter.) If the parameter is specified but is empty, or numeric, then it will return the numeric control ID which is auto-assigned to the INFLD control.

labelid (String or Num) [in/out]

Optional ID to assign to, or retrieve from, the label control associated with the INFLD control. If a non-empty string name passed, then that is the name that will be assigned to the label control. If an empty string or a numeric parameter is passed, the auto-assigned numeric ID of the control will be returned here.

changeflag (String) [out]

Set to "1" if the field contents are changed.


Label

If label is a simple text string, a static (but clickable) text label is created two columns on the left of the start of the INFLD field (i.e. the right edge of the button is two columns less than col). The left edge of the button is determined by the length of the label string contents.

You may fine tune the size of the label control by using the format "<###<text" or "<###>text". In the former case, the label will be left aligned starting at column ###. In the latter case, the text within the button will still be right aligned, but the left column of the label control will be ###.

To display the label above the field, use the format "^text". This will left align the label with the left edge of the field (as determined by col), with the top of the label 700 millirows above the top of the edit field. To override the standard 700 millirow spacing, use the format "^<####>text" where #### is the number of millirows desired.

You can also adjust the default font size used for the label by adding %###% to specify ###% scaling, i.e. "%120%Name:" will scale the label "Name" at 120% of normal. (If any of the column previous adjustment parameters are included, the %###% must be first.

Inserting a pipe character in front of the text string (e.g. "|text") causes the label to become a button rather than a static text control.

In the case of checkboxes, the first two positions of label are used to specify the alignment options:

Value | Alignment
|| | Text on the left, left aligned.
|> | Text on the right, left aligned.
>| | Text on the left, right aligned.
>> | Text on the right, right aligned.


SCRSTS

Added October 2008

xcall SCRSTS, opcode {params}

The parameter syntax varies with the opcode:

xcall SCRSTS, SCROP_INIT, srow, scol, erow, ecol{, parentid, sflags, title, closecmd, coldef, xt'kbdstr, xt'flags, ctlid}

xcall SCRSTS, SCROP_ADD, msgfmt, arg1, ... argN

xcall SCRSTS, SCROP_TMADD, msgfmt, arg1, ... argN

xcall SCRSTS,SCROP_SCROLL {,msg, exitcode}

xcall SCRSTS,SCROP_CLR

xcall SCRSTS,SCROP_DEL

SCRSTS outputs a status message to a window, scrolling previous messages up. Three variations are supported, depending on flags and environment: .

· Text mode using INMEMO

· GUI mode using multi-line INFLD control

· GUI mode using XTREE

Some examples using SCRSTS.SBX are provided below. Source, additional samples and related functions can be found in SOSLIB:[907,20].

Parameters

opcode (Num) [in]

specifies the operation using one of the options from the following table:

Symbol | Value | Description
SCROP_INIT | 0 | Initialize (create) the control.
SCROP_ADD | 1 | Add a message.
SCROP_CLR | 2 | Clear all the messages.
SCROP_DEL | 3 | Delete the control.
SCROP_SCROLL | 4 | Explicitly scroll the control contents; needed only in text mode.
SCROP_TMADD | 5 | Add a message with an automatic timestamp.
Definition file: SCRSTS.DEF

srow,scol,erow,ecol (Num) [in]

specify coordinates of the rectangle in normal or milli-units

sflags

takes MBF_xxxxx flags (from ashell.bsi); the only ones of interest so far are MBF_DIALOG and MBF_MODELESS, which, together cause the scrolling status control to be placed inside its own modeless dialog window (ignored in text mode). Also, MBF_LISTBOX causes GUI version to use XTREE instead of INFLD, eliminating the scrolling limit

title

title string to display in the dialog; ignored unless sflags contains the MBF_DIALOG option.

closecmd

if MBF_KBD and MBF_SYSMENU flags included in sflags, then closecmd determines what happens when X clicked (if "", then dialog is closed internally; else string is sent in place of the normal ESC) (Virtual click codes supported)

coldef

can be a legal XTREE advanced column definition, if MBF_LISTBOX (The default is "1~512~ ~S~~") WARNING: if you define any columns, it is up to you to pass subsequent MSG strings formatted to be compatible with the definition). Also note that if the header fields are all blank, the header row will be removed entirely.

xt'kbdstr

if MBF_KBD and MBF_LISTBOX defined, clicking on the control will send this string (which applications would typically responsd to by calling SCROP_SCROLL).

xt'flags

optional XTREE flags (if MBF_LISTBOX)

xt'ctlno

B,2 optionally returns XTREE control ID (XTR'CTLNO) or INFLD AUI ID

When the XTREE option is requested (see Using XTREE with SCRSTS), three additional optional parameters can be passed to the SCROP_INIT call

xt'kbdstr (String,10)

sets the XTR'KBDSTR member of the XTRCTL structure, so that clicking on the status control sends the specified string. This can be useful if you want to allow the user to manipulate the status window, such as to sort, select, etc. (This probably only makes sense in conjunction with a coldef that defines relevant features such as columns, popup menus, etc.) The application would normally call the SCROP_SCROLL opcode to in response to receiving the XT'KBDSTR.

xt'flags

may be used to specify additional XTREE flags, such as perhaps XTF_MSEL, XTF_SORT, etc.

ctlid

will return the XTREE control number (XTR'CTLNO), or in the case of INFLD, the AUI control id. This would only be of interest in sophisticated situations where you wanted to bypass SCRSTS.SBX and operate on the control directly using XTREE.SBR or INFLD.SBR.

These parameters apply only to the SCROP_ADD and SCROP_TMADD:

msgfmt (String) [in]

The message to output. May contain zero or more of the following special field markers, some of which are supplied by the next parameter in sequence (see arg1,...argN and Examples below):

%d | decimal value | (from arg1,...argN)
%s | string value | (from arg1,...argN)
%x | hex value | (from arg1,...argN)
%u | user name |
%m | machine name |
%p | program name |
%v | program version |

arg1,...argN (various types) [in]

These arguments are plugged into the %d, %s, and %x field markers from msgfmt

These parameters apply only to the SCROP_ADD and SCROP_TMADD:

msg (String) [in]

A string message to add to the bottom of the list. For text mode, the list is scrolled up one line to first to make room. For GUI mode, the scroll operation is automatic and thus this opcode is typically not used, although when it is used, it has the effect of suspending the application and putting the focus on the list control (allowing the operator to perform any operations supported internally by the control itself). To exit back to the application the user must issue some kind of exitcode (such as ESC); see exitcode.

exitcode (signed int) [out]

When specified in GUI mode, the standard XTREE exitcode value will be returned here, indicating how the user exited from the state of having the focus on the message list.

Examples

Display/add a message to the window:

xcall SCRSTS, SCROP_ADD, msgfmt {,arg1,...argN}

Clear the message window:

xcall SCRSTS, SCROP_CLR

Delete the message window (restore area in text mode)

xcall SCRSTS, SCROP_DEL

(If message window created inside its own dialog, dialog will be automatically deleted)

Allow user to scroll/activate the window.

xcall SCRSTS, SCROP_SCROLL {,msg{,exitcode}

Extended Example

The following example, from the actual AshLPD utility, illustrates the variation of SCRSTS based on XTREE, and includes the relatively advanced feature of using XTREE foreground row colors to code the various types of messages.

The initialization code for this image is:

! Columns 1-8 are the hh:mm:ss; 10 is the color code

COLDEF = "0~0~ ~H~RGBfg=200,200,220,D~" ! D = Debug

COLDEF = COLDEF + "RGBfg=250,100,0,E~" ! E = Error (Red Orange)

COLDEF = COLDEF + "RGBfg=255,0,0,F~" ! F = Fatal (Red)

COLDEF = COLDEF + "RGBfg=0,0,204,I~" ! I = Info (Blue)

COLDEF = COLDEF + "RGBfg=100,100,180,L~" ! L = Low level info (gray)

COLDEF = COLDEF + "RGBfg=0,0,0,P~" ! P = Printing msg (black)

COLDEF = COLDEF + "RGBfg=210,0,210,W~~" ! W = Warning (yellow)

COLDEF = COLDEF + "1~8~ ~S~~10~1~ ~Hc~~11~120~ ~S~~" ! column layout of msgs

xcall SCRSTS,SCROP_INIT,3,5,20,75,0,SFLAGS,"","",COLDEF

Messages are added with calls such as the following one. (Note that the color code letter, "I" in this case, indicating Info (Blue), is just sandwiched at the start of the message (matching the coldef layout set up above).

xcall SCRSTS,SCROP_TMADD,"IPerforming housekeeping..."

xcall SCRSTS, SCROP_TMADD, "I Archive for %d day(s), age cutoff = %d seconds", CFG'ARCHIVE, cutoff

Comments

The name (SCROLL) is slightly misleading because in GUI mode, you could scroll without this, but it is necessary in text mode, and in XTREE mode it activates the control allowing other features (such as sorting, selecting, etc. to take place). If exitcode is specified, returns exitcode, if any.

Stores data between calls using memory module SCRSTS.MEM (meaning that currently there can be only one of them active per A-Shell instance.)

Note that in text mode, if the height is >= 3, we use a border (which occupies 2 of the allowed rows). Otherwise no border. Also, on opcode 0, we save the area, and restore it on opcode 3.

The SCROP_SCROLL operation now supports the return of an exitcode:

xcall SCRSTS, SCROP_SCROLL, msg, exitcode

Since the SCROP_SCROLL opcode actually puts the focus on the status control, the exitcode will be that which you would have gotten from XTREE, INFLD, or INMEMO, depending on the environment. This would probably be most useful if you defined a PopupMenu, which returned interesting exitcodes.

The EXLIB sample program REGPTR[908,29] has been updated to illustrate some of the new capabilities of SCRSTS.

Using XTREE with SCRSTS

SCRSTS.SBX 1.3(108), A-Shell’s scrolling status window handler, supports an option to use XTREE rather than INFLD to display the scrolling status window. To specify XTREE, you must set the MBF_LISTBOX bit in the sflags parameter when creating the scrolling status window. An optional new parameter allows you to specify an XTREE column definition string:

xcall SCRSTS, SCROP_INIT, srow, scol, erow, ecol {,parentid, sflags, title, closecmd, coldef}

The rest of the SCRSTS opcode formats are unchanged.

Although the XTREE version actually has more overhead (XTREE is a vastly more complex control than the multi-line edit control used by INFLD), here are some of the reasons why you might prefer it:

• It eliminates the 1600 char limit on the amount of text that can be left in the window. With XTREE, there is essentially no limit.

• You can access many of the advanced XTREE features, such as colors, popup menus, columns, even multiple levels. Note, however, that it is up to you to supply a text string (in the SCROP_ADD or SCROP_TMADD calls) that is formatted to match the coldef specified with the SCROP_INIT.

Also note that if any of the column header fields in coldef are not blank, then the normal column header bar will be displayed. Otherwise it will not (making it more like a typical scrolling status window).

The TSTSCR.BP[907,20] sample program has been updated to allow easy experimentation with the new version.


SEND

xcall SEND, job, string {,options, status}

SEND.SBR provides the same functionality at the programmer level that SEND.LIT does at the command prompt level.

Parameters

job [in]

may be specified as B,1 in which case it is interpreted as the target job number, or S,6 in which case it is the target job name.

If mapped as B,1 or B,2 (i.e., to specify the target via its job number), then you can set it to -1 to indicate all jobs.

If mapped as a string (i.e. to specify the target via its job name), then you can set it to "ALL" to indicate all jobs.

string (String) [in]

is the text message (one line) to send.

options [in]

may be set to 0 (normal, i.e. display the message wherever the cursor happens to be on the target terminal), 1 (top status line), or 2 (bottom status line).

status

if specified, will return 0 if the message was successfully sent.

When sending to all jobs, the return value of STATUS takes on a new meaning. With one job, a return STATUS of 0 means success. But when sending to all jobs, STATUS returns the number of jobs to which the message was sent.

Comments

Under UNIX/Linux, there are security limitations on who can send messages. See the discussion on File Ownership and Privileges and ITC for more details.

Under Windows, there are no privilege issues but there may be a delay of several seconds before the message is delivered. See the IJCFREQ system parameter in the miame.ini discussion.

History

2006 January, A-Shell 4.9.950: Enhanced to allow sending a message to all other jobs.


SERCH

xcall SERCH, ch, rec, key, stpos1, enpos1, bsend, bsmid, srcctl, srcopt, rcnost, rcnoen, stpos2, enpos2, stpos3, enpos3

SERCH.SBR is fully compatible with the AMOS version. It is used for searching index files that consist of a sorted area and an unsorted "overflow" area. (The sorted area is searched using a binary search routine, while the overflow area is searched sequentially.) At best, binary searching is nowhere near as efficient as ISAM index lookups, and this discrepancy gets rapidly worse as the size of the overflow area increases, so it is not a highly recommended indexing technique. Nevertheless it is quite common, due to its use in the old AlphaAccounting programs and concerns in the early days about the reliability of ISAM.

Parameters

ch (Num)

is the open file channel of the index file.

rec (Raw, 2048 bytes maximum)

is an unformatted area for the located index record to be returned in.

key

is the string key to search for. This can consist of up to 3 parts (corresponding to the stpos1, enpos1, stpos2, enpos2, stpos3 and enpos3 locations in the index record), all of which must be concatenated together.

stpos1, enpos1, stpos2, enpos2, stpos3, enpos3 (Num)

specify the starting and ending position of up to 3 segments of the index record which make up the key to search for.

bsend (Num)

is the number of records in the sorted portion of the file (which must begin at the first record in the file).

bsmid (F,6)

will return the record number of the located index record.

srcctl (F,6)

returns a completion code (0=found, 1=not found)

srcopt (Num)

specifies the type of search to perform:

Value | Search Type
1 | Display "Please Wait" on line 12 of the screen, perform a binary/sequential search, clear the message, and return.
2 | Perform a binary/sequential search, clear line 12 of the screen, and return
3 | Display the wait message, perform a binary/sequential search, and return
4 | Perform a binary/sequential search and return (without any display)
5 | Perform a sequential search only, starting with the record number specified by bsmid.
6 | Perform a binary/sequential search which guarantees the locating of the first of a series of identical keys. (The other binary search options do not guarantee this.)

By "binary/sequential" in the table above, we mean that it first performs a binary search on the sorted portion of the index file, and if the record is not found, it then performs a sequential search on the overflow area.

rcnost, rcnoen

mark the starting and ending positions within the record that are used to indicate a deleted record. This area must be at least 2 bytes long, and each of the bytes must contain binary zero. (You can create such a binary field by setting a variable of type F or B to zero, in which case all of the bytes of the variable will contain 0, or by setting a string variable to "".)

Comments

The speed of SERCH.SBR can be increased dramatically by using one of the techniques described in the discussion of ASFLAG. It also goes without saying that you should sort the file as needed to keep the overflow area from growing very large.

History

2010 March, A-Shell 5.1.1176: XCALL SERCH enhancement: indexes using span'blocks (including record sizes up to 2048). Previously it only supported record sizes up to 512 with traditional blocking.


SETJTB

xcall SETJTB, job-table-variable

SETJTB.SBR is the converse of GETJTB and operates on the same format structured variable. It writes back each field into the job control block (with the exception of the job number, which cannot be changed), and thus may be used to change PPNs and devices, or to change the job name.

Comments

Care must be taken when using SETJTB, as it does not perform any checking on the values within the job table variable, and it is possible to store invalid information in your job control block.

Note that the PPN is represented both in its binary and string forms in job-table-variable. The current PPN will be set to the string values only if both binary fields contain zero. (Using the string fields is preferable, since they support the full range of 000-999, while the single byte binary versions are limited to octal values 0-377.)


SIZE

Updated December 2015; see History

xcall SIZE, fspec, count {,flags}

SIZE.SBR returns the size of the specified file in bytes.

Parameters

fspec (String) [in]

is specification of the file (in AMOS or native format).

count (Num) [out]

returns the number of bytes. If the file does not exist, -1 is returned. A return value of 0 indicates that the file exists but contains no data.

flags (Num) [in]

specifies what to return in the count parameter:

Value | Data Returned
0 (default) | Number of bytes in file
1 | Number of lines in (text) file
2 | Number of non-blank lines in (text) file

History

2015 December, A-Shell 6.3.1501: Add flags. Prior to this update, the routine only returned the number of bytes in the file, as if flags=0.

2015 January, A-Shell 6.1.1400: Routine now supports files larger than 2GB when the returned parameter is any F type. Previously, it only avoided the 2GB limit for F,6.


SQL

Added February 2009

xcall SQL, opcode, cmdhdr {,parm1,…,parmN}

SQL.SBR provides direct access (query/read/write/update) to SQL databases, in particular MySQL and any database supported by an OBDC driver. The name of the routine is SQL.SBR as shown here, but the name of the option/module in A-Shell is "ASQL." Information on ASQL is in its own document, for which see the documentation page on the A-Shell web site.

History

2009 February, A-Shell 5.1.1138: Routine added to A-Shell


SORTIT

Updated (rewritten) January 2013

xcall SORTIT, array, reccnt, recsiz,
k1siz, k1pos, k1ord {,
k2siz, k2pos, k2ord,
k3siz, k3pos, k3ord,
k1typ, k2typ, k3typ,
k4siz, k4pos, k4ord,
k5siz, k5pos, k5ord,
k6siz, k6pos, k6ord,
k4typ, k5typ, k6typ}

Note that in the syntax shown above, spaces and line breaks have no meaning—i.e., they do not and should not exist in the actual program. They are used here strictly as visual aides to illustrate the structure of the commands.

SORTIT.SBR sorts an array in memory. The parameters are all analogous to those of BASORT, subject to the comments below.

Parameters

array [in/out]

Since A-Shell/BASIC does not have a natural syntax for referring to the entirety of an array, you can either specify an unformatted variable which occupies the same space as the array, or you specify the first element of the array. For example:

MAP1 XARY

MAP2 ARY(100)

MAP3 FLD1,S,10

etc.

Assuming the above layout, you could either specify the XARY variable, or ARY(1). The first choice has the advantage of allowing A-Shell to make sure that you don't accidentally specify more rows than exist. The downside is that the technique cannot be used with DIMX arrays. For example:

DIMX ARRAY(COUNT),S,WIDTH

XCALL SORTIT, ARRAY(1), COUNT, WIDTH, K1SIZ, ...

In the above case, you have no choice but to use the second method, specifying ARRAY(1) for the array parameter. Note that it may not be possible for SORTIT to verify the size of the array in this case, so IT IS CRITICAL that the passed subscript is actually (1) and that the reccnt parameter is less than or equal to the total extent of the array lest you corrupt memory and suffer all manner of humiliation and suffering. (Note that you can use the .EXTENT function to determine the physical extent of an array at runtime.)

reccnt (Num) [in]

Number of elements in the array to sort. See warning under array about making sure reccnt doesn't exceed the size of the array.

recsiz (Num) [in]

Size of each element in the array.

k?siz (Num) [in]

Size of the key (? = 1,2,3,4,5,6). For unused keys, specify 0. Note that for binary and integer keys, only 2 and 4 byte sizes are supported. For F keys, size may be 4, 6, or 8.

k?pos (Num) [in]

Position of the key within each array element (starting with 1).

k?ord (Num) [in]

Sort order: 0=ascending, 1=descending

k?typ (Num) [in]

Value | Search Type
0 | String
1 | Floating point: 4, 6 or 8 byte
2 | Binary: 2, 3, 4, 5 bytes
3 | Integer: 2 or 4 bytes
4 | Natural Sort
5 | Case insensitive natural sort

The default value is 0 (string). Also see history note 1136 below.

History

2013 January, A-Shell 6.1.1332: The routine now checks for certain parameter errors that might otherwise have caused erroneous results (at best) or corrupted memory (at worst). These would include specifying more rows to be sorted than exist in the array, or attempting to sort an array made up of dynamic string elements (which are not contiguous and thus cannot be sorted by SORTIT.SBR in its current state of development). Note that we are unable to check for the case where the array parameter is specified as an individual element other than the first one, which could lead to memory overflow even if the specified row count is within the bounds of the extent of the array.

For example, if the physical size of the array is 100, and you specify 100 rows to sort, but instead of specifying array(1) as the initial element you accidentally specify array(10), then it could end up referencing non-existent rows 101-110.

2009 January, A-Shell 5.1.1136: SORTIT now support the 3 new sort types (see BASORT), plus F4 and F8. Note, however, that SORTIT does not support B1 or I1 keys, and ignores the LDF collating sequence.


STRIP

xcall STRIP, strvar

STRIP.SBR removes trailing blanks from the specified string. Note that it does not remove Tabs or any other control characters, just spaces, and just those that are at the trailing end.

Also see TRIM, which trims both leading and trailing spaces, and has an option to remove unprintable characters as well.


STRTOK

Updated April 2010

xcall STRTOK, opcode, string, fdelim, fld1 {, rdelim, fld2, ...fldn}

STRTOK.SBR is both convenient and very efficient (compared to the equivalent logic in BASIC) for parsing string data, but may take a little practice to get used to. See the following topics for a couple of real examples of using it.

STRTOK.SBR parses the string variable according to the delimiters specified, and returns one or more fields in the fld1...fldn variables. You can call it once for each field (and change the field delimiter characters as you go), or have it return several parsed fields in one call, ending either when it hits a delimiter in the rdelim field or runs out of string or of fldx parameters.

Two examples, Almost Comma Delimited and Large Packets, Multiple Delimiters are provided.

Parameters

opcode (Num) [in/out]

should be set to 0 for the initial call, and 1 for subsequent calls using the original string. (It will be updated automatically from 0 to 1 to make this easy.) See History, below, for information on the +2 and +4 values.

string (String) [in/out]

is the string to be parsed. Must be null terminated! string will be modified by the routine, which will replace the delimiter characters with null bytes.

fdelim (String) [in]

is a list of one or more field delimiter characters.

rdelim (String) [in/out]

is a list of one or more "record" delimiter characters.

(The subroutine will terminate when it hits one of these, whereas it will keep going after each field delimiter until all the FLDx parameters are used up.) Parameter is irrelevant if you just want to get one field. Even in the case of multiple fields, you can set it to "". Note, however, that if specified, it will be returned updated with the actual last delimiter character processed (i.e. the one that terminated the xcall). This can be very useful when there are more than one possible delimiter, or when you want to determine whether you got a complete record or just ran out of FLDx parameters. If you do not care about record delimiters, then specify it as a literal "" (in which case it cannot be updated) or remember to clear it prior to each XCALL STRTOK. (Otherwise, it will get updated to match the field delimiter. The XCALL should be smart enough to ignore record delimiters that are also field delimiters, but it could nonetheless lead to confusion.)

Note that prior to Build 905.3, rdelim was assumed to be 2 or more bytes and the second byte was getting cleared, which would have clobbered the next variable if rdelim only mapped as one byte.

fld1...fldn (String) [out]

will return the parsed fields or tokens from string, according to the specified delimiters.

History

2009 October, A-Shell 5.1.1163: opcode flag +4 enables "CSV mode", which attempts to parse the source string as if it were comma separated (CSV) or Tab separated fields. This mode is similar to the existing quoted mode (+2), but with following differences:

· While +2 mode recognizes quoted sub-fields anywhere within a field, +4 (CSV) mode only considers quotes as possible delimiters if the first non-blank character in the field is a quote. Any quotes which occur mid-field are treated as data characters. A subsequent quote will only be considered as the trailing quote of the field if it is followed by a field or record delimiter.

· Leading and trailing spaces are removed from the returned field

· Pairs of adjacent double-quote characters ("") are coalesced into single ones, i.e. 6"" Banana becomes 6" Banana.

2006 November, A-Shell 4.9.971: The opcode parameter now supports a +2 flag to cause it to recognize quoted arguments. For example, consider the following string:

"DSK0:A.B[111,222]",ARG1,ARG2

If the field delimiter is a comma, normally STRTOK would parse the arguments like this:

"DSK0:A.B[111

222]"

ARG1

ARG2

By adding +2 to the opcode parameter, it will parse it like this:

DSK0:A.B[111,222]

ARG1

ARG2

Note that it removes the quotes.

2003 November, A-Shell 4.9.854: routine added to A-Shell


Almost Comma Delimited

Ordinary comma delimited data is easy to parse with INPUT CSV, but what do you do when the comma delimited file contains commented lines? A good example is the A-Shell INI.CLR file, which looks something like this:

; Color Definitions (for a primarily blue background)

; Color legend: 0=blk, 1=wht, 2=blu, 3=mag, 4=red, 5=yel, 6=grn, 7=cyn

; VUECLR=override?,edit fg,edit bg, command fg, command bg, help fg, help bg, status/info fg,bg

; Use the following for a reasonable scheme using blue background.

VUECLR=Y, 1,2, 5,2, 7,2, 6,2

; Use the following to disable VUE colors, i.e. use current colors only.

;VUECLR=Y,-1,-1,-1,-1,-1,-1,-1,-1

; EZCLR=override?,text fg,bg, border fg,bg, cmd fg,bg, sts fg,bg, help fg,bg, highlight fg,bg, menu fg,bg, brief menu fg,bg

EZCLR=Y, 1,2, 1,2, 5,2, 0,9, 1,3, 1,4, 5,2, 7,2

; INFCLR=override?,display fg,bg, edit fg,bg, negative fg,bg, update fg,bg, message fg,bg, original msg line fg,bg, forms fg,bg

INFCLR=Y, 5,2, 1,10, 4,2, 7,2, 7,2, 1,2, 0,2

; MMOCLR=Y,border fg,bg, text fg,bg, arrows fg,bg, prompt fg,bg, status line fg,bg, protected fg,bg

MMOCLR=Y, 6,2, 5,10, 6,2, 7,2, 1,2, 7,2

; SCNCLR=override?,screen text (fg), screen background

; The following sets up white on blue

SCNCLR=Y,1,2

This seems like a simple enough format, but the unpredictable presence of the commented lines (marked by a semicolon), and the equal sign make it difficult or impossible to use INPUT CSV. STRTOK comes in handy here because it can be used on a string, allowing you to first input the entire line to check for commented out lines, then pass it to STRTOK. Also, it eliminates the need to deal with special tests for prematurely terminated lines, lines with comments in them, uneven spacing, etc. The following code parses the input, putting into the MAP structures:

MAP1 VUECLR'OVR,S,1

MAP1 VUECLR(4,2),S,1 ! 4 pairs

MAP1 EZCLR'OVR,S,1

MAP1 EZCLR(8,2),S,1 ! 8 pairs

MAP1 INFCLR'OVR,S,1

MAP1 INFCLR(7,2),S,1 ! 7 pairs

MAP1 MMOCLR'OVR,S,1

MAP1 MMOCLR(6,2),S,1 ! 6 pairs

MAP1 SCNCLR'OVR,S,1

MAP1 SCNCLR(2),S,1 ! 1 pair

MAP1 PLINE,S,100

MAP1 STATE,F,6,1 ! 1)VUECLR, 2)EZCLR, etc.

MAP1 RDELIM,S,2

MAP1 FDELIM,S,3,"=,"

MAP1 OPCODE,B,1,0

OPEN #1, "LIB:INI.CLR", INPUT

LOOP:

INPUT LINE #1, PLINE

IF EOF(1)=1 AND PLINE="" GOTO PREMATURE'END

xcall TRIM,PLINE,1

IF PLINE="" OR PLINE[1,1]=";" GOTO LOOP

OPCODE = 0

ON STATE CALL PVUE,PEZ,PINF,PMMO,PSCN

IF STATE < 5 GOTO LOOP

PREMATURE'END:

PRINT "PREMATURE END OF FILE"

DONE:

CLOSE #1

END

PVUE: ! parse VUECLR line

RDELIM = ";" + CHR(10)

xcall STRTOK,OPCODE,PLINE,FDELIM,VUECLR'OVR,RDELIM, &

VUECLR(1,1),VUECLR(1,2),VUECLR(2,1),VUECLR(2,2), &

VUECLR(3,1),VUECLR(3,2),VUECLR(4,1),VUECLR(4,2)

STATE = STATE + 1

RETURN

PEZ: ! parse EZCLR line

RDELIM = ";" + CHR(10)

xcall STRTOK,OPCODE,PLINE,FDELIM,EZCLR'OVR,RDELIM, &

EZCLR(1,1),EZCLR(1,2),EZCLR(2,1),EZCLR(2,2), &

EZCLR(3,1),EZCLR(3,2),EZCLR(4,1),EZCLR(4,2), &

EZCLR(5,1),EZCLR(5,2),EZCLR(6,1),EZCLR(6,2), &

EZCLR(7,1),EZCLR(7,2),EZCLR(8,1),EZCLR(8,2)

STATE = STATE + 1

RETURN

PINF: ! parse INFCLR line

RDELIM = ";" + CHR(10)

xcall STRTOK,OPCODE,PLINE,FDELIM,INFCLR'OVR,RDELIM, &

INFCLR(1,1),INFCLR(1,2),INFCLR(2,1),INFCLR(2,2), &

INFCLR(3,1),INFCLR(3,2),INFCLR(4,1),INFCLR(4,2), &

INFCLR(5,1),INFCLR(5,2),INFCLR(6,1),INFCLR(6,2), &

INFCLR(7,1),INFCLR(7,2)

STATE = STATE + 1

RETURN

PMMO: ! parse MMOCLR line

RDELIM = ";" + CHR(10)

xcall STRTOK,OPCODE,PLINE,FDELIM,MMOCLR'OVR,RDELIM, &

MMOCLR(1,1),MMOCLR(1,2),MMOCLR(2,1),MMOCLR(2,2), &

MMOCLR(3,1),MMOCLR(3,2),MMOCLR(4,1),MMOCLR(4,2), &

MMOCLR(5,1),MMOCLR(5,2),MMOCLR(6,1),MMOCLR(6,2), &

MMOCLR(7,1),MMOCLR(7,2)

STATE = STATE + 1

RETURN

PSCN: ! parse SCNCLR line

RDELIM = ";" + CHR(10)

xcall STRTOK,OPCODE,PLINE,FDELIM,SCNCLR'OVR,RDELIM, &

SCNCLR(1),SCNCLR(2)

STATE = STATE + 1

RETURN

The example above was complicated by the fact that every line of the file contained a different format and needed to be put into different variables. So we needed a lot of individual STRTOK commands. But we did not need any complicated substring processing–it was all very straightforward.


Large Packets, Multiple Delimiters

The next example is perhaps more typical, taken from a real-world data stream arriving over a TCP socket. The data represents the answer to an auto parts query, and is made up of a list of auto makes. Within each make is a list of models. And within each model is a list of years. The model records are terminated with a "|", the make records are terminated with ~, and the individual fields are terminated with semicolons. So a block of data may look something like this:

Ford; Mustang; 1975-79; 1985-88; 1999-2004|Pinto;
1968,1971,1980-85,1992|Explorer; 1992,1994-96; 1998-2004|Expedition; 2001;
2003~Chevrolet; Impala; 1957-61; 1965-70; 1976,1979|Camaro; 1962; 1964; 1966;
1968; 1975~Mazda; RX7; 1985-91; 1994|Miata; 2004~

Our program to parse the data looks like this:

MAP1 PARAMS

MAP2 MAKES(20) ! Up to 20 makes

MAP3 MKNAME,S,10 ! name of make

MAP3 MODELS(20) ! up to 20 models per make

MAP4 MODNAME,S,10 ! model name

MAP4 YEARS(30),S,10 ! up to 30 years per model

MAP1 PARAMS$,S,124200,@PARAMS ! for easy init of all

MAP1 INFO,S,10000 ! block of data

MAP1 RDELIM,S,2,""

MAP1 FDELIM,S,1,";" ! field delimiter

MAP1 OPCODE,B,1

MAP1 MKX,F,6 ! index to MAKES()

MAP1 MDX,F,6 ! index to MODELS()

MAP1 YX,F,6 ! index to YEARS()

! <receive data from socket into INFO>

INFO = "Ford;Mustang;1975-79;1985-88;1999-2004|" &

+ "Pinto;1968;1971;1980-85;1992|Explorer;1992;" &

+ "1994-96;1998-2004|Expedition;"2001;2003~Chevrolet;"

+ "Impala;1957-61;1965-70;1976,1979|Camaro;"

+ "1962;1964;1966; 1968;1975;1976; 1977;1978;"

+ "1980;1982;1984;1986; 1988;1990;1992;" &

+ "1994;1996;1998;1999;2000;2002;2004~" &

+ "Mazda;RX7;1985-91;1994|Miata;2004~"

PARAMS$ = "" ! Clear entire param array

MAKE'LOOP: ! input one 'make' record per loop

MKX = MKX + 1

RDELIM = ""

MAKE$ = "" ! clear entire MAKES(MKX)

xcall STRTOK,OPCODE,INFO,FDELIM,MKNAME(MKX)

IF MKNAME(MKX)="" GOTO DONE

MDX = 0

MODEL'LOOP: ! input models, one per loop

MDX = MDX + 1

RDELIM = "~|" ! could end on either delimiter

xcall STRTOK,OPCODE,INFO,FDELIM,MODNAME(MKX,MDX),RDELIM, &

YEARS(MKX,MDX,1),YEARS(MKX,MDX,2),YEARS(MKX,MDX,3), &

YEARS(MKX,MDX,4),YEARS(MKX,MDX,5),YEARS(MKX,MDX,6), &

YEARS(MKX,MDX,7),YEARS(MKX,MDX,8),YEARS(MKX,MDX,9), &

YEARS(MKX,MDX,10),YEARS(MKX,MDX,11),YEARS(MKX,MDX,12), &

YEARS(MKX,MDX,13),YEARS(MKX,MDX,14),YEARS(MKX,MDX,15)

! check what delimiter we ended with...

IF RDELIM="~" GOTO MAKE'LOOP ! get next make

IF RDELIM="|" GOTO MODEL'LOOP ! get next model

IF RDELIM<>";" GOTO ERROR ! unexpected delimiter

! if last delimiter ; get more fields – note we have

! a limit of 30 params so we could not do them all in

! one xcall

RDELIM = "~|" ! could end on either delimiter

xcall STRTOK,OPCODE,INFO,FDELIM,YEARS(MKX,MDX,16),RDELIM, &

YEARS(MKX,MDX,17),YEARS(MKX,MDX,18),YEARS(MKX,MDX,19), &

YEARS(MKX,MDX,20),YEARS(MKX,MDX,21),YEARS(MKX,MDX,22), &

YEARS(MKX,MDX,23),YEARS(MKX,MDX,24),YEARS(MKX,MDX,25), &

YEARS(MKX,MDX,26),YEARS(MKX,MDX,27),YEARS(MKX,MDX,28), &

YEARS(MKX,MDX,29),YEARS(MKX,MDX,30)GOTO MAKE'LOOP

GOTO MAKE'LOOP

Note that STRTOK does not clear the unused fields, so it is up to the program to reset them in advance. In the program above, although this is not a problem since we only use the arrays once, we use a string overlay to clear the entire 3 level array in one step just to illustrate the general case.


SUBMIT

Revised/reviewed January 2012

xcall SUBMIT, pid, stdin, stdout, stderr, executable, arg1, arg2 {,...argn}

(UNIX only) SUBMIT.SBR allows you to execute an arbitrary command (executable and arguments) as a child process of the current A-Shell process. It is similar to HOSTEX, but implemented using the lower level fork() / exec() sequence, rather than the higher level system() call used by HOSTEX. The lower level implementation provides some additional flexibility, which is mainly of use to SUBMIT.LIT, and thus is primarily of interest as an internal routine.

Parameters

Parameter | Type | I/O | Description
pid | Num | out | returns the process id number (pid) of the child process created to run the command. (Note that such pids can be larger than 64K in most modern UNIX implementation, thus B,2 is not a good choice.)
stdin | String | in | must specify the filespec (AMOS-style or native) of a file containing the input to be forced to the process (aka the "control file"). This is typically similar to a CMD file, but may contain raw keyboard characters as well as commands, and should start with a LOG command.
stdout, stderr | String | in | must specify the filespecs of files to which the standard and error output of the process will be sent. To mimic the AMOS log file behavior, set them both to the same name (typically with an extension of LOG and a base name either matching the control file or the job name).
executable | String |  | filespec of an executable which the child process will be forced to run. (In the case of SUBMIT.LIT, this is always "ashell", but could in theory be anything.) Normal operating system search path rules apply if the filespec doesn't specify a path.
arg1, arg2, ... argn | String | in | optional arguments to the executable. (Each parameter should contain just a single argument, with no embedded spaces unless the argument is quoted. For example, in the case of the ashell executable, the ini file name would actually occupy two arg parameters, one for "-i" and one for the miame.ini filespec.)

Example

xcall SUBMIT, RC, "CMD:TEST.CTL", "TEST.LOG", "TEST.LOG", "ashell", "-i", "/vm/miame/miame.ini"

Comments

Child processes launched this way are generally dependent on the parent process to continue running for the duration of the child process. To launch a child/background process independent of the current process, use SUBMIT.LIT with the /NEXT: or /AFTER: switch.

See Also

• The system parameter SBR option SUBMIT2 for related information.


SWPSBR

xcall SWPSBR, function, {parameters dependent on function}

SWPSBR.SBR performs various functions related to the Swap multi-session and screen-tracking system available as a third-party add-on in the AMOS world. A-Shell does not support Swap per se, since it has its own screen tracking system (TRACKER) and multi-session system (either PolyShell or using multiple Windows instances), but it does support most of the SWPSBR functions, which are listed below. Note that unless you already have a lot of code using these functions, you would be better off to use MSBOXX, which can do all of these things and which is both more powerful and better supported.

xcall SWPSBR, 0, active$

Function 0 tests whether the Swap system is active. A-Shell returns "Y" in the active$ parameter.

xcall SWPSBR, 1, screen

xcall SWPSBR, 1, srow, scol, erow, ecol, screen

Function 1 restores the previously saved window or entire screen. With Swap, the screen parameter was a buffer to hold the screen contents, but it is ignored with A-Shell, which has an internal storage scheme. (You can map it as X,1 to save space.) However, A-Shell's scheme acts like a stack, so you must save and restore in LIFO order (i.e. last item saved will be the first item restored.) The first format above restores the entire screen. The second format restores a previously saved partial screen.

You can also restore an entire screen with Tab(-1,203), assuming it has previously been saved with Tab(-1,202) or an equivalent. You can also save and restore partial screens using MSBOXX

xcall SWPSBR, 3, screen

xcall SWPSBR, 3, srow, scol, erow, ecol, screen

Function 3 saves an entire screen (first format) or partial screen (second format). See Function 1 above for the restore operation.

xcall SWPSBR, 7, srow, scol, erow, ecol, siz

Function 7 was used to establish the size needed to store the specified screen area. The call is simply ignored by A-Shell, since you do not need to provide any storage space for the save and restore operations.

xcall SWPSBR, 8, srow, scol, erow, ecol

Function 8 was used to restore attributes on the right side of the box. It is not implemented by A-Shell. You do not need this capability with mode emulations (such as Windows, VT100, etc.) and if you really need it, you can get it by using MSBOXX and the BOX_FAO option, or via Function 128.

xcall SWPSBR, 9, srow, scol, erow, ecol

Function 9 clears the specified box. It is equivalent to the MSBOXX option BOX_ERA.

xcall SWPSBR, 128, srow, scol, erow, ecol, flags

Function 128 draws a box, with various options determined by the contents of the flags parameter. The options are listed in the following table, and may be strung together using commas. For example, "T,C,B,O=2,I=3."

Flags | Description
B | Draw a border around the box. Equivalent to MSBOXX option BOX_BDR.
C | Clear interior of box. Equivalent to MSBOXX option BOX_ERA.
T | Seal up field attributes. Equivalent to MSBOXX option BOX_FAO.
I=<text fg> | Sets the text (interior) foreground color. For example, I=1 would set it to white. Equivalent to the IBOX'FG parameter in MSBOXX.
O=<border fg> | Sets the border (outside) foreground color. For example, O=2 would set it to color 2 (blue). Equivalent to the BRDR'FG parameter in MSBOXX.

xcall SWPSBR, 129, screen, fspec$

Function 129 saves the current screen, VUEs the specified file, then restores the screen. As with the other functions involving the Screen parameter, Screen is ignored by A-Shell, which instead uses EZTYP to save the screen, display the file, and restore the screen on exit.


TCPX

xcall TCPX, opcode, status, buffer, sockport, flags {,timer, hostname}

TCPX.SBR provides an interface for applications to communicate with other processes via TCP sockets. It supports both client and server operations, and is theoretically compatible with just about any TCP socket-based client or service, whether implemented via A-Shell on the local machine, or some entirely different language and operating system on a remote machine across the Internet.

Parameters

opcode (Num) [in]

indicates operation, per the TCPX Opcodes table.

status (F,6) [in/out]

Returns status of operation. <0 = -errno. >0 indicates number of bytes read or written. For other operations, 0 generally indicates success. See the Status table, which shows details by opcode.

buffer (String, Raw, or array) [in/out]

Packet of data to read or write. Note that there is no hard coded limit on the packet size; however the OS may impose its own limits. 8K should work nicely in all environments. Also note that the TCPOP_ACCEPT call will send the first 32 bytes of buffer (if not empty), unsolicited to the client. This can cause all kinds of confusion if the client is not expecting it, so in general you'll want to make sure that buffer = """ prior to accepting a connection.

sockport (Num) [in/out]

On connect or accept (opcodes TCPOP_ACCEPT, TCPOP_CONNECT, TCPOP_CONNECT_OLD) must supply the port number to listen on or connect to; returns the connected socket number, which must be supplied to all other calls (except opcode TCPOP_ERRMSG). See Advanced Server Connection Options for special case involving TCPXFLG_LISTEN. Also note that for some kinds of errors, TCPX may automatically close the socket, in which case it will return sockport set to -1, eliminating the need for your application to explicitly close it.

flags (Num) [in]

Usage varies with opcode as noted in the tables Flags1 and Flags2.

timer (Num) [in] optional

Number of milliseconds to wait before returning if operation cannot be completed. The value returned in status after a time out depends on the opcode. For opcode TCPOP_CHECK, status will return 0 on time out. For opcode TCPOP_WRITE and TCPOP_READ, status will return the number of bytes transferred before the timer expired. Under Windows only, timer also affects opcode TCPOP_ACCEPT (server wait for connection), causing it to return with status set to a negative value if no connection was accepted before the timer expired. Under UNIX, timer has no affect on opcode TCPOP_ACCEPT, which will wait until either a connection is accepted or the process is aborted by an external event.

The timer parameter works to set a limit on the amount of time waiting in the TCPOP_CONNECT operation. Although in theory, the TCPOP_CONNECT operation should succeed or fail without delay, in practice, DNS delays and some firewalls can cause the operation to hang for several seconds, particularly on failed attempts. In earlier versions of A-Shell, the timer parameter had no effect on that. Starting in build 996.3 of 15 Oct 2007, if the connection cannot be established within the specified time limit, the attempt is aborted.

hostname (String) [in]

Used only with opcode TCPOP_CONNECT. Must specify the host name or IPV4 address (###.###.###.###) of the host server to connect to. If specifying a name, do not include any protocol prefixes; just include the DNS name (e.g. myservice.mydomain.com, www.yourdomain.net, etc.).

Note that as a convenience for backwards compatibility with TCPCLI/TCPSRV, hostname can be the fifth parameter (if six parameters are specified and the sixth is numeric), or the last parameter (if five, six, or seven parameters are specified).

See Also

• Socket Programming for a more detailed discussion of sockets in general.

• Sample programs TCPxxx in [908,25] of the EXLIB.

• The subtopics.

• On the A-Shell forum, search for "TCPX" and "AIX / TCPX issue: async connects."

Warnings and Notes

• If you get tired of waiting for an asynchronous connection to complete, you can cancel the connection attempt by using TCPOP_CLOSE, just like you would for an established connection.

• The interpretation of the STATUS value returned from TCPOP_CONNECT depends on whether it is a normal or asynchronous (TCPXFLG_ASYNC) connection request. In the normal case, STATUS>=0 indicates success. In the asynchronous case, STATUS=0 means the connection is still pending, while STATUS=1 means success. If still pending, you need to use TCPOP_CHECK to determine the outcome. It will return STATUS=0 for still pending, STATUS=1 for success, or STATUS<0 for connection failed.

• If TCPOP_CONNECT (with the TCPXFLG_ASYNC flag) returns with STATUS=1 and SOCKPORT > 0, then the socket SOCKPORT is open (or "half open"), even though the connection is still pending. So you would be responsible for closing it if you don't follow through with the TCPOP_CHECK procedure to check for the result. On the other hand, if you get STATUS<0 on the TCPOP_CHECK (with TCPXFLG_ASYNC) operation, the socket will be automatically closed.

• If an asynchronous connection attempt returns the pending status, the socket will be in non-blocking mode, regardless of whether you initially specified the TCPXFLG_BLOCK flag. To get it back into blocking mode once the connection is established, you need to specify TCPXFLG_BLOCK along with TCPXFLG_ASYNC on the TCPOP_CHECK call(s).

History

2010 April, A-Shell 5.1.1180: Add support for STARTTLS.

2010 April, A-Shell 5.1.1178: Add support for TLS/SSL.

2010 April, A-Shell 5.1.1177: Add Setting The SO_LINGER Option.

Subtopics

Backwards Compatibility

Advanced Server Connection Options

Asynchronous Client Connections

Closing

TCPX Opcodes

Flags1

Flags2

Status

TCPCLI

TCPSRV


Backwards Compatibility

As a convenience for backwards compatibility with TCPCLI on the TCPOP_CONNECT opcode, flags can be the sixth parameter if the fifth parameter is a string (i.e. TCPX is called with the TCPCLI syntax:

xcall TCPX, opcode, status, buffer, sockport, hostname, flags


Advanced Server Connection Options

Normally the TCPOP_ACCEPT operation will open a listening socket on the port specified by sockport, and then wait for a connection to be accepted. At that point, it closes the listening socket and returns the connection socket in sockport to the caller.

There are two shortcomings to this protocol. One is that while waiting for a connection to be accepted, the server application is suspended; if no client ever connects, the server would be suspended indefinitely, unless it was aborted by Ctrl+C or some other signal. The other is that any attempt by a client to connect to the server while the server is servicing a connection will be rejected. To get around either or both of these shortcomings, you can use the flags TCPXFLG_LISTEN, TCPXFLG_ASYNC, and TCPXFLG_KEEPLISTEN in conjunction with the TCPOP_ACCEPT operation.

If the TCPXFLG_LISTEN flag is specified, then the TCPOP_ACCEPT operation returns immediately, with sockport set to the listening socket rather than the connection socket. The application should then save this returned sockport value in a separate variable, perhaps called LISTENSOCK, as it may be needed later after sockport has been again updated.

Since opening the listening socket is fast (does not require waiting for a client to make a connection request), this eliminates the possibility of the server getting stuck for an indefinite time waiting for a client connection. It can subsequently use the TCPOP_CHECK operation to check if a connection is ready, although it should do so frequently, since the clients do not like to wait very long. Once a connection is ready to accept, or if you decide you do not mind waiting, you can use the TCPOP_ACCEPT opcode again, this time with TCPXFLG_ASYNC (and optionally, TCPXFLG_KEEPLISTEN) to accept a connection on the listening socket specified in sockport. The accepted connection socket is returned in sockport. This would overwrite the saved listening socket number, so if you plan to accept further connections on this same listening socket, you must save the listening socket in another variable.

If the server wants to "stay open for business" while processing the current connection, it should use the TCPXFLG_KEEPLISTEN flag so that the listening socket previously opened—and hopefully saved in a separate variable, i.e. LISTENSOCK—can be left open and reused for the next connection.

As long as the listening socket is left open, any connection requests will queue up, either until the queue fills, or the client gets tired of waiting and cancels the request. The length of the queue is 64, which should be more than adequate for most situations.

Note that if you use TCPXFLG_LISTEN, and then do not accept a connection or accept one with the TCPXFLG_KEEPLISTEN flag set, the listening socket remains open, and must be manually closed (in addition to any connection socket) when your program ends. Use the normal TCPOP_CLOSE operation and specify the listening socket, which you hopefully saved in a variable separate from sockport.)


Asynchronous Client Connections

Attempts to establish client connections (TCPOP_CONNECT) are generally quick to succeed or fail, unlike listening for connections from the server side, which might involve an indefinite wait. Still, in some cases such as slow DNS servers, sneaky firewalls, many hops, routing problems, etc., it can take several seconds to determine whether the connection can be made, during which your application is effectively hung. You can put a limit on the wait by specifying a timer value, but that only gives you the ability to abort the connection if the attempt takes too long. If you're willing to allow the connection attempt to take several seconds, but don't want to be stuck while waiting, you can make an asynchronous client connection request, with the following procedure. (This capability added in edit 996.3).

Start by calling TCPX with the TCPOP_CONNECT opcode, but also specify the TCPXFLG_ASYNC option in flags. TCPXFLG_BLOCK is optional. You can set timer > 0 if you're willing to wait a short time to allow a successful connection to be fully established, but don't want to abort the connection if it takes longer than the limit. Otherwise, with timer = 0, the call will always return immediately. The only point of setting timer to, say 1 second, would be to possibly eliminate the need for the following TCPOP_CHECK calls if the connection succeeds quickly.

If the connection succeeds immediately, or within the limit set by timer, it will return status = 1, and the connected socket in sockport. This case is identical to the normal, synchronous, connection, except that the return status is 1 instead of 0, and from this point forward, it can be handled just like a normal connected socket.

Similarly, if the connection fails immediately or within the limit set by timer, it will return status < 0.

Otherwise, it will return status = 0 (indicating "pending") and yet it will return the open (or "half open") socket in sockport. In this case, you are free to do other things while waiting for the connection attempt to finally succeed or fail. To check on the progress of the operation, you must use TCPOP_CHECK with the half open sockport, also specifying TCPXFLG_ASYNC, and optionally, TCPXFLG_BLOCK. This will return status =0 to indicate that the connection attempt is still pending, 1 to indicate a successful completed connection, or <0 to indicate a failed connection, in which case the socket will be closed for you. If and when the connection succeeds, you can the treat it like a normal client socket.

Notes:

• If you want a blocking connection, you need to specify TCPXFLG_BLOCK both in the TCPOP_CONNECT call and in the TCPOP_CHECK call(s), since the blocking status cannot be set until after the connection is finally complete.

• If you get tired of waiting for the connection to complete, you can call TCPOP_CLOSE at any time to terminate it. This might be useful, for example, if you were to display a dialog box saying "Attempting connection…" which gave the user a CANCEL button option.

• Beginning in build 996.3 of 15 Oct 07, you can do other work while waiting for a connection to succeed or fail by specifying the TCPXFLG_ASYNC flag with the TCPOP_CONNECT operation. In that case, if the connection cannot be established within the time limit specified by TIMER (or immediately, if TIMER=0), then the subroutine returns with STATUS=0 and SOCKPORT (>0) set to the socket whose connection attempt is still in progress. (You can consider this socket "half opened", meaning it is open on your end, but the other end still hasn't responded.) You must then use TCPOP_CHECK (continuing to specify the TCPXFLG_ASYNC flag and the half-opened socket in SOCKPORT) to check whether the connection attempt is complete. STATUS=1 indicates success, STATUS<0 indicates an error, STATUS=0 indicates that the connection attempt is still pending.


Closing

The TCPOP_CLOSE operation used to (in TCPCLI/TCPSRV) issue both a bi-directional shutdown and a close. In TCPX, it only closes the socket. The distinction between close and shutdown is as follows:

• Shutdown sends a signal to the remote end indicating that the sender is shutting down its end of the socket. Since sockets are full duplex, it is possible to shutdown just the sending side, or the receiving side or both. Two new flags, TCPXFLG_SHUTRD and TCPXFLG_SHUTWR have been added to allow the application to take advantage of this capability. If both, or neither, are specified, the socket is shut down in both directions. Shutdown does not substitute for close though, and therefore should be followed (eventually) by a normal close.

• Close will generally have the same effect as a shutdown in both directions, except in the case where a socket is being shared by a parent and child process. The parent may have accepted the connection, then used XCALL SUBMIT to fork a child, which inherits the connection. Normally the parent would then close its connection socket. In the case, the close will not have any effect on the other end, since the child still has the socket open. Shutdown, on the other hand, would cause the other end to get an error if tried to read or write to the socket. When the child closes the socket, since it is the last one at its end to have it open, it will really be closed.

If the remote side attempts to read from the socket (or is in a blocking read) when the local socket is closed, it will return an error, although the precise error number may vary between operating systems and how the remote side performed the close/shutdown.


TCPX Opcodes

This table contains a brief explanation of the operation of each opcode. Note that in nearly all cases, you'll need to check the return value of the Status parameter to determine the outcome of the operation.

Symbol | Value | Operation
TCPOP_ACCEPT | 1 | Create listening socket on port specified by sockport, and wait for a client to connect. Be careful to make sure that the buffer parameter is empty, or else the first 32 bytes of it will be sent, unsolicited, to the client immediately after accepting the connection, which is likely to cause confusion unless the client was specifically expecting it.) On successful return, sockport is set to the connected socket, and must be specified to all the other calls for this socket.
TCPOP_WRITE | 2 | Write buffer to socket.
TCPOP_READ | 4 | Read buffer from socket.
TCPOP_SHUTDOWN | 5 | Informs the other end that we are shutting down prior to the close. This is mainly useful when shutting down only one direction. See flags.
TCPOP_CLOSE | 6 | Close socket. You must do this explicitly when done, since BASIC will not close sockets for you at the end of the program, like it does for files. Note that TCPX will automatically close the socket after certain errors, in which case it will set sockport to -1. In other words, if sockport = -1, don't bother to close it; doing so redundantly is harmless but will return you the error status = -1.
TCPOP_CHECK | 7 | Check if data available to read; returns status=1 if so, 0 if not, and <0 if the socket has been closed at the other end. Also used with Asynchronous Client Connections and Advanced Server Connection Options to check if the connection is complete or ready to accept.
TCPOP_CHKQTY | 8 | Check how much data avail to read; return number of bytes in status, <0 indicates socket closed or dropped at other end.
TCPOP_CONNECT | 9 | (client) Connect to generic server. If timer > 0 and the connection is not established within the specified time, the connection is aborted. See Asynchronous Client Connections.
TCPOP_CONNECT_OLD | 10 | (client) Equivalent to old TCPCLI opcode 1; now considered archaic
TCPOP_ERRMSG | 11 | Return system error message corresponding to status.
TCPOP_STARTTLS | 12 | TCPX opcode to initiate STARTTLS


Flags1

This first table describes the defined flags bits along with the opcodes that they go with:

Symbol | Value | Opcode | Meaning
TCPXFLG_BLOCK | &h000001 | TCPOP_ACCEPT, TCPOP_CONNECT | Establish connection being accepted as blocking.
TCPXFLG_LISTEN | &h000004 | TCPOP_ACCEPT | Causes TCPX to return with the listening socket in sockport instead of the connection socket, without waiting to accept a connection.
TCPXFLG_ASYNC | &h000008 | TCPOP_ACCEPT | Accept connection on previously opened listening socket. sockport must be the listening socket.
TCPXFLG_ASYNC | &h000008 | TCPOP_CONNECT | Attempt to connect asynchronously. See Asynchronous Client Connections.
TCPXFLG_ KEEPLISTEN | &h000010 | TCPOP_ACCEPT | Combined with TCPXFLG_ASYNC to keep the listening socket open after accepting the connection.
TCPXFLG_SHUTRD | &h000020 | TCPOP_SHUTDOWN | Shut receiving side only.
TCPXFLG_SHUTWR | &h000040 | TCPOP_SHUTDOWN | Shut sending side only.
TCPXFLG_NODELAY | &h000080 | TCPOP_ACCEPT, TCPOP_CONNECT | Disable the Nagle delay.
TCPXFLG_LINGER | &h000100 | TCPOP_ACCEPT, TCPOP_CONNECT | Set the standard TCP option SO_LINGER to "on". See Setting The SO_LINGER Option.
TCXPXFLG_TLS | &h100000 |  | Support for TLS/SSL.
TCPXFLG_STARTTLS | &h200000 | TCPOP_CONNECT | Support for STARTTLS.

Hex-Decimal Values


Setting The SO_LINGER Option

Added April 2010

You may set the SO_LINGER socket option to "on" by passing the flag TCPXFLG_LINGER (&h0100) and then putting the desired linger time (in seconds) into the 4th (high byte of B,4) byte of FLAGS during a TCPOP_CONNECT or TCPOP_ACCEPT call. For example:

TCPOP = TCPOP_CONNECT ! (or TCPOP_ACCEPT)

FLAGS = FLAGS or TCPXFLG_LINGER ! activate SO_LINGER option

FLAGS = FLAGS + (5 * (2 ** 24)) ! set timer to 5 seconds

The SO_LINGER option affects the behavior of the TCPOP_CLOSE operation, relative to data that has been sent but may not yet have been delivered. There are three possibilities:

By default, the SO_LINGER option is turned off, which means that the close operation returns immediately, but if there is any data still remaining in the socket send buffer, the system will try to deliver it to the remote end.

If SO_LINGER is turned on, and the timer value is 0, then the connection will be aborted when TCPOP_CLOSE is called. Any data still remaining in the socket send buffer will be discarded, and a reset packet (RST) will be sent to the remote end, rather than the normal termination sequence.

If SO_LINGER is turned on, and the timer value is non-zero, then the kernel will "linger" when the socket is closed either all of the data in the send buffer has been sent and acknowledged by the remote end, or the timer expires. If the socket is blocking, TCPOP_CLOSE will not return until one of those conditions is met. (If non-blocking, it will return, possibly with STATUS set to EWOULDBLOCK, but the kernel will still linger as just described.)

Note that the SO_LINGER timer should not be confused with the TCPX.SBR TIMER parameter, which relates to the time until the connection is made or accepted.


TLS/SSL

Added April 2010

A-Shell build 1178 of April 2010 introduces preliminary support for TLS/SSL via the new flag TCPXFLG_TLS. There are several notes and caveats to consider:

· You must pass the TCPXFLG_TLS flag with every call to TCPX.SBR. This will probably necessitate that the flags parameter be mapped as B,4. Note that the flag is above the range normally used for the transfer size for TCPOP_READ and TCPOP_WRITE (where flags may be used to specify the number of bytes to transfer).

· The multitude of variations and parameters relating to secure connections (ciphers, protocols, certificate types, algorithms, etc.) are currently all defaulted to a "standard set". Future releases will elaborate to this.

· Passing the TCPXFLG_TLS option to TCPX.SBR will cause the LIBASHTLS.DLL module to be loaded, along with several other DLL's which are part of the GnuTLS package. Currently these are all released together in a zip which should be unpacked into the %MIAME%\bin directory.

· See the sample program SOAP1.BP for an example of using the TLS feature to submit a SOAP request to a secure web server.


STARTTLS

Added April 2010

As of A-Shell build 1180 of 20 April 2010, the STARTTLS protocol is supported via a new opcode and flag (in ashell.def).

Symbol | Value | Meaning
TCPOP_STARTTLS | 12 | TCPX opcode to initiate STARTTLS
TCPXFLG_STARTTLS | &h00200000 | Use with TCPOP_CONNECT

Limitations: As with TLS connections (introduced in 1179.0), currently only client connections (TCPOP_CONNECT) are supported. Also, the TIMER option seems to interfere with the TLS handshaking. If having problems, turn that off and just use blocking mode, in conjunction with TCPOP_CHECK to check for data.

To initiate a STARTTLS connection, use the TCPOP_CONNECT opcode, along with the TCPXFLG_TLS and TCPXFLG_STARTTLS flags to initiate the unencrypted connection. When you want to start the TLS negotiation, use whatever unencrypted means are required to inform the server that you are about to start negotiating TLS, and then call TCPX.SBR with opcode TCPOP_STARTTLS. After the successful return (STATUS=0), you will be in encrypted mode, and the TCPXFLG_STARTTLS flag will no longer be needed. (However, as mentioned in the 1179 notes, TCPXFLG_TLS is required with EVERY call to TCPX.SBR if you are using TLS or STARTTLS protocol, including those calls prior to using TCPOP_STARTTLS.)

Note: EMAILX.SBR 5.1(121) uses this new feature to support the STARTTLS protocol extension to SMTP, permitting, for example, the use of the GMAIL SMTP server.

Linux installation requirements:

· Standard installation of the GnuTLS package, preferably version 2.8.6 (from www.gnu.org).

· Copy the latest libashtls.so.1.0.xxx (xxx currently at 204) into the $MIAME/bin directory (where the ashell executable is).

· Create /usr/lib/libashtls.so.1 as a symbolic link to the libashtls library in the $MIAME/bin directory, e.g.:

# ln -s $MIAME/bin/libashtls.so.1.0.204 /usr/lib/libashtls.so.1

Windows installation requirements:

· Download http://www.microsabio.net/dist/other/gnutls/gnutls-2.8.6.zip and unzip the contents into the bin directory (where ashw32.exe is).

· Download http://www.microsabio.net/dist/51dev/bin-win/libashtls-204.zip and unzip the contents (libashtls.zip) into that same bin directory.

Debugging notes: Use the "SOCKS" trace option (SET TRACE SOCKS ON) to record many details about the operation of the TLS library. For even more detail (particularparticularly about the handshaking process), also set the XDEBUG trace option.


Flags2

This table lists all of the opcodes and describes the interpretation of the flags parameter for each. Note that in several cases, such as with the read, write and check operations, the value of flags relates to a number of data bytes, rather than to bit values as in the Flags1 table..

Symbol

Interpretation of Flags Parameter

TCPOP_ACCEPT

TCPXFLG_BLOCK sets blocking mode, which means that read and write calls wait until they can be completed or the timer expires; in non-blocking mode, if timer=0 and the read/write operation cannot be immediately completed, an error status is returned.

TCPOP_WRITE

Specifies the number of bytes to write. Must be less than or equal to the size of buffer, unless buffer is subscripted, in which case we just trust the flags value. If flags=0 (or not specified), writes the entire buffer block. If flags non-zero, the specified number of bytes are written. In order to minimize partial packet writes, we set the send buffer low water mark to match the number of bytes to write, so that we do not start the operation unless the socket buffer has sufficient space. If timer > 0, it waits until the timer expires or the packet is fully written. If timer = 0 and the connection is non-blocking, it returns an error ("EWOULDBLOCK") if the packet cannot be written immediately. Otherwise it waits indefinitely, for the packet to be entirely written or the socket is closed at the other end. This is one case where you might have a problem if you use a packet size larger than the OS supports.

TCPOP_READ

Specifies the number of bytes to read. 0 means read whatever is available, from 1 byte to size of buffer. Otherwise, if timer > 0, routine will wait until the required number of bytes is read up to the time limit. If timer = 0 and flags > 0, for non-blocking connections, the flags value is only an upper limit; the routine will return as soon as the interface indicates there is data available even if not the requested number of bytes. For blocking connections, with timer = 0 and flags > 0, the subroutine will wait until the # of bytes is received, or the socket is closed at the other end.

If both flags = 0 and timer = 0, for blocking connections it should wait until any data or an error condition is available. For non-blocking connections, the behavior may be platform dependent. Under Linux and Windows, it should return immediately, either with data or with Linux error -11 (resource temporarily unavailable) or Windows error -10035 (a non-blocking socket operation could not be completed immediately). Under some versions of AIX, it has been reported to act the same as for a blocking connection—i.e. waiting until data or some other error is available. If this is a critical concern for your application, you should test it under the platform you'll be using. See the TCPTST test program in [908,25] of the EXLIB to simplify your testing.

TCPOP_SHUTDOWN

0 indicates a shutdown in both directions. Otherwise, you can shut down just one direction by specifying either TCPXFLG_SHUTRD (32) or TXPXFLG_SHUTWR (64).

TCPOP_CLOSE

flags not used.

TCPOP_CHECK

If timer specified, flags is ignored and timer is used. If timer not specified, flags specifies how long to wait before returning status 0 if no data avail. If flags is F,6 then it is interpreted as fractional seconds; otherwise it is interpreted as milliseconds. (You should specify timer in all new programs; the option to exclude it is only supported for backward compatibility with TCPCLI and TCPSRV, and is deprecated.) See Asynchronous Client Connections for special considerations involving flags and TCPOP_CHECK.

TCPOP_CHKQTY

flags not used.

TCPOP_CONNECT

TCPXFLG_BLOCK sets blocking connection (see TCPOP_ACCEPT)

TCPXFLG_ASYNC sets asynchronous mode (see Asynchronous Client Connections).

TCPOP_CONNECT_OLD

TCPXFLG_BLOCK sets blocking connection (see TCPOP_ACCEPT)

TCPOP_ERRMSG

flags not used.


Status

This table lists details relating to the interpretation of the status parameter, based on the opcode.

Symbol | Interpretation of Status Returned
TCPOP_ACCEPT | Status >= 0 indicates success. Any value > 0 implies that you had data in the buffer parameter, which was sent unsolicited to the client - up to 32 bytes. That is an unusual protocol though, and likely to confuse the client.
TCPOP_WRITE | Status returns the number of bytes written. <0 indicates an error. Note that for non-blocking connections, a special error value (EWOULDBLOCK, which is -10035 for Windows and typically -11 for UNIX) is returned if the socket cannot accept the data immediately. All other errors would suggest a permanent problem requiring the socket to be closed.
TCPOP_READ | Status returns the number of bytes read. <0 indicates an error. See note above for TCPOP_WRITE about the special EWOULDBLOCK error.
TCPOP_SHUTDOWN | Returns 0 for success, <0 for error.
TCPOP_CLOSE | Returns 0 for success, <0 for error.
TCPOP_CHECK | Returns 0 to indicate that the socket is not ready—that is, there is no data to read, or, in the case of Asynchronous Client Connections, the socket is not yet connected. <0 indicates an error; probably the socket has been closed at the other end, or the asynchronous connection attempt failed. 1 indicates that the socket has data to read, or the asynchronous connection has successfully completed.
TCPOP_CHKQTY | Returns the number of bytes available to read, or <0 for an error.
TCPOP_CONNECT | Returns 0 for a successful normal connection, else <0 for error. In the case of Asynchronous Client Connections, 0 indicates that the connection attempt is in progress, while 1 indicates that it connected successfully.
TCPOP_ERRMSG | Status should be set to the error code (probably returned from the previous operation) in order to get the error description. This is the one case where status is used for input to the subroutine rather than output from it.


TCPCLI

This subroutine has been superseded by TCPX; it is supported and documented for historical reasons only. Unless you are running an old version of A-Shell (prior to build 855 of November 2003—in which case you should update!), you should use TCPX.

xcall TCPCLI, code, status, buffer, sockport, hostname {,flags}

TCPCLI.SBR provides a way for a client process to communicate with a server process over TCP/IP sockets. It is specifically designed to interface easily with another A-Shell server process which is running TCPSRV, but it is flexible enough to be used with a wide variety of server processes.

Parameters

code (Num) [in]

Specifies operation, from choices below:

Value | Description
1 | Connect to TCPSRV server (same as 9 but waits for a response)
2 | Write contents of BUFFER to socket.
4 | Read data from socket into BUFFER
6 | Close socket
7 | Check if socket has data to be read (returns STATUS=1 if so)
8 | (UNIX only) Same as 7 but returns STATUS= number of bytes available to read
9 | Connect to server; same as 1 but does not wait for a response (works for any server, including TCPSRV)

status

Return status. <0 for errors (-errno), >0 indicates number of characters written or read.

buffer (String or Raw)

Read/write buffer (maximum 4096 bytes)

sockport (F,6)

For connect, caller must supply port number to connect to. On return, this will contain the connected socket number, which must then be passed to all the other calls for this session. If the connect operation returns <0, this indicates an error (with the number indicating which of the several internal steps failed).

hostname

On connect, must contain the host name or IP address of the server.

flags (F,6) optional

On the connect calls (1 & 9), set to 1 for a blocking connection, or 0 for a non-blocking connection. (Default is blocking.) On the check operation, set to number of seconds to wait before returning if no bytes are available. (Fractional seconds are ok; default is 0 if parameter not specified.) On the read call specifies (if non-zero) the maximum number of bytes to read (default is the size of BUFFER). On the write call, specifies (if non-zero) the number of bytes to write.

Comments

Sockets are not automatically closed when a BASIC program terminates, so it is important that you add a socket close command to your error trap. Otherwise you may not be able to reconnect to the socket.

You can translate the system error codes returned as negative numbers in the STATUS parameter by using XCALL MIAMEX, MX_ERRNOMSG, ABS (STATUS), MESSAGE$

The client connect calls will fail if the server is not already waiting for a connection. (In contrast, the server side the corresponding "accept connection" (Code 1) call using TCPSRV, will wait indefinitely for a client to make a connection.)

The number of bytes to read or write (as specified by FLAGS) will be trimmed to the smaller of the size of BUFFER and 4096 bytes. The one exception is that if the BUFFER variable is subscripted, then FLAGS may be as large as 4096. (This overcomes the obstacle when using an array caused by the fact that the subroutine calling mechanism reports the size of just one element, rather than the size of the entire array.)

Opcode 9 is recommended in place of Opcode 1, even when you know the server is running TCPSRV. The only difference is that Opcode 1 does an automatic read after connecting. It is more standard and flexible to issue a separate read to retrieve the server’s ACK message (if any).


TCPSRV

This subroutine has been superseded by TCPX; it is supported and documented for historical reasons only. Unless you are running an old version of A-Shell (prior to build 855 of November 2003—in which case you should update!), you should use TCPX.

xcall TCPSRV, code, status, buffer, sockport {,flags}

TCPSRV.SBR provides a way to create server processes that support client requests via a socket interface. Similar to TCPCLI, and in fact designed specifically to integrate easily with it, TCPSRV.SBR is nevertheless flexible enough that it can be used to communicate with a wide variety of client processes over TCP/IP sockets. For example, you could use it to create a server that responded to web queries submitted from a CGI process.

Parameters

code (Num) [in]

Specifies operation, from choices below:

Value | Description
1 | Create listening socket on port specified by SOCKPORT, and wait for a client to connect. If BUFFER parameter is non-null, then after the connection is accepted, the first 32 bytes of the BUFFERDATA parameter will be sent to the client as an acknowledgment message. On successful return, SOCKPORT is set to the connected socket, which must be specified to all the other calls for this socket.
2 | Write contents of BUFFER to socket.
4 | Read data from socket into BUFFER
5 |
6 | Close socket
7 | Check if socket has data to be read (returns FLAGS=1 if so)
8 | (UNIX only) Like CODE 7 except returns the number of bytes available to read.

status (F,6)

Return status. <0 for errors (-errno), >0 indicates number of characters written or read.

buffer (String or Raw)

Read/write buffer (maximum 4096 bytes)

sockport (String or Raw)

For connect, caller must supply port number to connect to. On return, this will contain the connected socket number, which must then be passed to all the other calls for this session. If the connect operation returns <0, this indicates an error (with the number indicating which of the several internal steps failed).

flags (F,6) optional

On the connect operation, may contain 1 for a blocking connection, or 0 for a non-blocking connection. (Default is blocking.) On the check operation, contains the number of seconds to wait before returning if no characters are available. (Fractional seconds are ok; default is 0 if parameter not specified.) For the write operation, it specifies the number of characters to write. (Default is size of the BUFFER parameter if FLAGS not specified.) For the read operation, if non-zero, specifies the maximum number of bytes to read.

Comments

Note that only one server process can wait for connections on a particular port number for a single machine. So it is important that the server do its job and close the socket quickly if there is a possibility of multiple clients making frequent requests. Typically, this kind of single-threaded server works best for quick and simple lookup operations, such as price lookups or inventory status checks.

See the sample program TCPTST.BAS for a working example.


TIMES

Added June 2009

xcall TIMES, opcode, elapsed

TIMES.SBR returns high-precision time information.

Parameters

opcode (Num) [in]

determines operation; see table

elapsed (Num) [out]

returns the elapsed time in the units and according to the logic described in the following table

Value | Units | Description
1 | secs | Returns the number of seconds since midnight. This is equivalent to the system variable TIME, except that if the elapsed parameter is a floating point variable, then the returned value may return fractional seconds.
2 | msecs | Returns the number of milliseconds since midnight. As with opcode 1, if elapsed is a floating point variable, a fractional number of milliseconds may be returned.
3 | usecs | Returns the number of microseconds elapsed since the previous opcode 3. Note that this is only practical for timing operations lasting only seconds or perhaps minutes, but not hours or days. The first time this routine is called, the return value will be essentially random garbage.


TINKEY

xcall TINKEY, char

TINKEY.SBR allows you to input a keyboard character if one is available, without waiting if one is not available.

Parameters

char (String or B,1) [in]

The input character—or a null byte if no input available—will be placed into the first byte of this parameter with no conversions or termination. A dynamic string (S,0) may also be used, although it doesn't make much sense.

Comments

If the session has received the hangup signal and is running in background pending an input operation to terminate, by default, XCALL TINKEY will not be counted as an input operation. If you want it to be counted as an input operation (and thus terminate the session), then specify the –hetcki command line switch when launching A-Shell.


TRIM

xcall TRIM, strvar {,flag}

TRIM.SBR removes both leading and trailing blanks from the specified string variable. In addition, it can optionally remove other non-printable characters.

Parameters

strvar [in]

is the string variable from which you want to trim the leading and trailing spaces. It does not need a trailing null byte.

flag (Num) [in]

may be specified as any non-zero value to cause TRIM to treat any characters with ASCII values less than 32 (space) or greater than 127 the same as space (i.e. remove them). Like spaces, they must still be prior to the first printable character or after the last one, and prior to the first null, to be removed. Any spaces or other control characters that are embedded between printable characters are left alone.

Comments

The EDIT$() function supports the ability to remove certain types of characters within (rather than just at the beginning or end of) the string.

The SBR=TRIMCTL setting in the system parameters file forces TRIM to act as if a nonzero flag value had been passed.

TRIM.SBR is actually a wrapper for STRIP.SBR with which it communicates by setting up a dummy second parameter. The problem is that the way it was done has the effect of updating the actual parameter passed. Users are advised that the flag parameter may be overwritten, and should therefore probably be expressed as a literal value (or in new programs, using a defined constant rather than a variable, i.e. define TRUE=-1 rather than MAP1 TRUE,F,6,-1).


TRMCHR

Updated December 2011

xcall TRMCHR, status, trmchr'map

TRMCHR.SBR provides a means to determine various characteristics of the terminal running your program. The current number of rows and columns, foreground and background colors, and other information is available. The A-Shell implementation is a compatible super-set of the AMOS version.

Parameters

status (F) [out]

Returns 0 for success. (Actually it does nothing under A-Shell, since there is no way for it to fail.)

trmchr'map

A structure which must be mapped as specified. Typically you would access the standard copy via ++include ashinc:trmchr.map). All fields are output only, except for TRMCHR'WINROW. See the following topic TRMCHR'MAP for full details.

Comments

See the sample program TRMCHR.BAS in sample program in [908,28] of the EXLIB, and the TRMCHR.BSI and TRMCHR.MAP include files in ashinc:

History

2005 January, A-Shell 4.9.915: A-Shell/Windows Extension: Under A-Shell/Windows GUI mode, if there is a standard modal dialog box open at the time of the XCALL TRMCHR, WINROW and WINCOL will be set to the usable number of rows and columns in the dialog box.

A-Shell/Server/ATE Extension: Under A-Shell/UNIX (or A-Shell/Windows on a telnet server with ATSD), if the client is ATE, then there is a possible ambiguity in TRMCHR over whether the information returned should be from the server or the client side. In most cases, these will agree, except for the case of WINROW and WINCOL, since dialog box information may only be known to the client. (The server application would have given the command to create the dialog box, but that information, and especially the knowledge of whether the dialog box is still open on the client, is not necessarily available to TRMCHR.SBR.)

To resolve the ambiguity, if you want the WINROW / WINCOL information to return information about a dialog box displayed on the ATE client, you must set WINROW to -1 prior to the XCALL. In that case, TRMCHR.SBR will query the client for all of the information. Otherwise, it will just use the server's view of the terminal status, which, as of build 915, will mean that the WINROW and WINCOL fields will come back 0. To clarify, the main reason why you would want to set WINROW to -1 before XCALL TRMCHR is if you are interested in knowing the size of the current dialog box on the client display, if any. (It makes no difference under A-Shell/Windows what you set WINROW to, since it always returns the client information in that case.)


TRMCHR'MAP

MAP1 TRMCHR’MAP

MAP2 TRMCHR’FLAGS,F,6

MAP2 TRMCHR’ROWS,F,6

MAP2 TRMCHR’COLS,F,6

MAP2 TRMCHR’COLORS,F,6

MAP2 TRMCHR’FORE,F,6

MAP2 TRMCHR’BACK,F,6

MAP2 TRMCHR’WINROW,F,6

MAP2 TRMCHR’WINCOL,F,6

MAP2 TRMCHR’TSLSIZ,F,6 ! (optional)

MAP2 TRMCHR’BSLSIZ,F,6 ! (optional)

MAP2 TRMCHR’BSSSIZ,F,6 ! (optional)

The individual fields are described in the following table.

Symbol | Description
TRMCHR’FLAGS | Returns the sum of flags from the following table.
TRMCHR’ROWS | The number of rows currently displayed.
TRMCHR’COLS | The number of columns currently displayed.
TRMCHR’COLORS | The number of colors the terminal supports. Monochrome terminals will report 0.
TRMCHR’FORE | The current foreground color. Monochrome terminals will report 0. The color values are: 0 Black, 1 White, 2 Blue, 3 Magenta, 4 Red, 5 Yellow, 6 Green, 7 Cyan
TRMCHR’BACK | The number of the current background color (same color values as TRMCHR’FORE).
TRMCHR’WINROW | The number of rows in the current dialog. If initially set to -1 and the terminal is ATE, the operation is performed on the ATE workstation instead of within the server job.
TRMCHR’WINCOL | The number of columns in the current dialog.
TRMCHR'TSLSIZ | (optional A-Shell extension) Length of top status line
TRMCHR'BSLSIZ | (optional A-Shell extension) Length of bottom status line
TRMCHR'BSSSIZ | (optional A-Shell extension) Length of bottom shifted status line

The following table defines the TRMCHR'FLAGS bits.

Value | trmchr'flags Meaning
&h00000001 | Alternate page support
&h00000002 | Block fill support
&h00000004 | Column insert/delete support
&h00000008 | Multiple color support
&h00000010 | Function key translation support
&h00000020 | Is an Alpha Micro terminal
&h00000040 | Has a status line
&h00000080 | Horizontal split screen support
&h00000100 | Erase to end of line support
&h00000200 | Erase to end of screen support
&h00000400 | Underscore attributes support
&h00000800 | Blinking support
&h00001000 | Dim video support
&h00002000 | Reverse video support
&h00004000 | Character insert/delete support
&h00008000 | Line insert/delete support
&h00010000 | Local printer support
&h00020000 | Settable 80/132 column support
&h00040000 | Selectable smooth scroll support
&h00080000 | Has box drawing commands
&h00100000 | Has "mode" type attributes
&h00200000 | Has AM-70 style color commands
&h00400000 | Has "no space" attribute commands
&h00800000 | Variable number rows and columns
&h01000000 | Enhanced tab(-1,192) support
&h02000000 | A-Shell GUI extensions


UNIQUE

xcall UNIQUE, fname

UNIQUE.SBR generates a unique filename based on your current jobname. This can be handy for generating print files and other temporary files which are periodically erased.

The parameter fname (string variable, 10+ bytes) will be set to <jobnam>.T#@ where # is a digit from zero to nine, and @ is an alphabetic character from A to Z. It scans through these names in order until finding one that is not in use. Thus if the current job is TSKAAA, the first name returned (assuming it is not already in use) will be TSKAAA.T0A, followed by TSKAAA.T0B, etc.


USPSBS

Updated January 2013; see History

xcall USPSBS, trackstr, routestr, barstr, status

USPSBS.SBR creates an encoded bar string for the US Post Office intelligent bar codes.

Parameters

trackstr (String, 21) [in]

tracking string

routestr (String, 12) [in]

route string

barstr (String, 66) [out]

returned encoded bar string. It is a character format equivalent of the graphic bar code, designed to be easy to convert to the graphic format. See the documentation on the USPS web page for specifications.

status (F) [out]

returned status code per the following table:

Value | Description
0 | Sucess
-1 | Parameter error
-2 | Unable to load USPS4CB.DLL
-3 | Unable to locate the USPS4CB() function
-99 | Not supported on current platform
>0 | invalid trackstr and/or routestr

Comments

The file USPS4CB.DLL is available from the US Postal Service's Intelligent Mail Barcode Resource Download Site and must be saved somewhere in the path or in the A-Shell bin directory.

See the publications on the above web site for details on creating the trackstr and routestr values.

See the EXLIB directory [908,52] for sample and test programs.

History

2013 January, A-Shell 6.1.1331: support added for Linux (routine previously was for Windows only)

2011 January, A-Shell 5.1.1201: added to A-Shell


USRCNT

xcall USRCNT, pcount {,lcount, mcount, ixcount}

USRCNT.SBR returns the number of physical nodes in use, logical nodes in use, maximum number of physical nodes allowed, and the number of instances of A-Shell that are running.

Parameters

pcount (F,6) [out]

returns the number physical nodes currently in use. Physical nodes count against the license. In theory, each physical workstation counts as a physical node, but due to the many ways in which devices can be attached and sessions established, the counter can sometimes be "fooled." However, for each physical node, there will always be at least one logical node.

lcount (F,6) [out]

returns the number of logical nodes (or jobs) currently in use. Logical nodes do not count against the license. When the number of logical nodes is greater than the number of physical nodes, it should be because of background sessions or multiple sessions originating from the same physical workstation.

mcount (F,6) [out]

returns the maximum number of physical nodes (i.e. the number specified in the license).

ixcount (F or I) [out]

returns the executable instance count, including the current instance. -1 indicates some kind of error, like an inability to execute the ps command under UNIX. 0 would indicate a different kind of error—i.e. that the current instance is detecting neither itself nor any other error while scanning the process or window list.

For Windows, this is a count of windows sharing the A-Shell main window class (MIAMEWClass). Note this would include A-Shell/Windows and ATE, which could involve more than one actual ASHW32.EXE executable. Note that in a peer-to-peer environment, one peer running this function would not see the other peers that may be sharing the same copy of ASHW32.EXE. (In this case, you should probably use SYSTAT as well to check for the possibility of other instances of A-Shell which share the ASHW32.EXE disk copy, but which are in different memory spaces or different workstations.)

For UNIX, it uses ps to check for processes whose launch command references the current executable (which isn't necessarily named "ashell").

In either case if the ixcount value is greater than the lcount (logical instance) value, that implies that there are instances of A-Shell running that aren't sharing the same JOBTBL.SYS.

This parameter was added to USRCNT in A-Shell build 988.4 of 10 May 07 primarily for the benefit of ASHUPD—i.e., to make sure there are no other instances of A-Shell running that would interfere with an update. The function might also be useful to applications attempting to monitor usage for the same reasons they are already using USRCNT.SBR.

Example

This simple program demonstrates the use of USRCNT.SBR.

MAP1 PCOUNT,F,6 ! # physical nodes

MAP1 LCOUNT,F,6 ! # logical nodes

MAP1 MCOUNT,F,6 ! # maximum nodes licensed

MAP1 IXCOUNT,F,6 ! # current instances

XCALL USRCNT,PCOUNT,LCOUNT,MCOUNT,IXCOUNT

? "# Physical Users: ";PCOUNT

? "# Logical Users: ";LCOUNT

? "# Licensed Nodes (max): ";MCOUNT

? "# Current Instances: ";IXCOUNT

end


VUESCR

xcall VUESCR, textarray, rows, cols, strow, stcol

VUESCR.SBR edits a rectangular array of text.

Parameters

textarray [in/out] optional

supplies the initial text and receives the updated text. It must be mapped as a string array, with the number of elements greater than or equal to the value of the rows parameter, and the size of each element equal to the value of the cols parameter.

rows,cols (Num) [in]

determines the dimensions of the rectangular area of text to be edited, and must correspond to the mapped dimensions of textarray.

strow,stcol (Num) [in]

determines the starting position of the rectangle on the screen. A border will be drawn outside this rectangle, so for best results, the starting row and column should be two or greater.

Comments

VUESCR is actually implemented as a front end to INMEMO, which already supports this exact function, although with different and more complex parameters. It is offered mainly as a convenience to programmers using the Swap (multi-session) utility under AMOS.


WAKNO

xcall WAKNO, jobno {,status}

WAKNO.SBR (UNIX versions only) wakes up a job that is sleeping (in SLEEP.SBR or SLEEP.LIT).

Parameters

jobno [in]

is the job number of the job to wake up. (See PLYJOB for a way of getting the number of another job.) Note that in order to be able to send a signal like this to another process under UNIX, you either have to be the superuser or have the same effective user id as the target user.

status [out] optional

returns the result of the operation:

Value | Description
-1 | No such job
0 | Success
1 | Insufficient privileges to wake target user
3 | No such process (job probably aborted uncleanly, leaving a phantom in the job table)


WINFLG

xcall WINFLG, flag {,feature}

The AMOS routine WINFLG.SBR was used within inSight to retrieve information about the current job and terminal environment. Flag is a 6-byte floating point variable, and feature is any numeric type.

If WINFLG was called with just the one argument, it was supposed to return 1 if inSight was supported, else 0. (A-Shell does not support inSight and thus returns 0.) If called with 2 arguments, then it returns flag = 1 if the corresponding feature is supported, else 0. The features 1-32 are equivalent to those used by JOBDAT (which see). Features 33-255 correspond to the equivalent TCRT or Tab(-1,x) numbers. Feature 256 indicates Multi or Office (and is thus set to 0 by A-Shell).

Since this routine is used very sparsely in the A-Shell community, A-Shell contains only a minimal implementation. Features 1-32 are supported, as in JOBDAT, but beyond that, A-Shell returns 1 for features 33-149, plus 202 and 203 (screen save/restore). In the case of Windows (except in Telnet mode), it also returns 1 for features 158-162 (mouse functions).


XCALEN

Added May 2016

xcall XCALEN, idate, xcdates(), exitcode, xcflags, sr, sc, title, sdate, edate {,coldef, xcflags}

XCALEN.SBX is an XTREE-based implementation of a calendar control featuring the following extensions beyond what is available in the standard Month Calendar Control. The extensions are:

• Ability to apply different colors/font effects to each date (whereas the standard Month Calendar is limited to marking selected dates in bold).

• Ability to store text associated with each cell that can be displayed as a tooltip.

Source, samples and related functions can be found in SOSLIB:[907,49].

Sample Images

Parameters

xcdates() (ST_XCALEN) [in]

DIMX-allocated array of individual dates of interest to mark on the calendar. Dates do not have to be in order. There is no particular limit to the number of dates in the array, but only one element per date is recognized, and there is no particular value to dates that all outside the range set by sdate,edate. When the calendar is displayed, dates for which there is an element in the xcdates() array will be shown with a "+" beside the day number, and will be given the background color specified in the BG field of the ST_CALEN element; see sample images. The ST_CALEN structure is defined—in ASHINC:xcalen.def—as follows:

defstruct ST_XCALEN

map2 DATE,B,3 ! standard (ODTIM/IDTIM) separated date

map2 BG,B,4 ! BackGround color (RGB value)

map2 MARK,B,2 ! various indicator flags (not yet defined.)

map2 COMMENT,s,1024 ! text

endstruct

The COMMENT field may contain up to 1024 bytes of free-format text to associate with the date. The text is displayed as a tooltip when the mouse hovers over the date; see sample images.

idate (B,4) [in]

initial date to select in calendar. Standard ODTIM/IDTIM format.

exitcode (Signed Int) [out]

Exit code indicating how control was exited:

Code | Meaning
-20001 | Use clicked 'X' to close calendar
-20002 | Out of range, navigating to previous month
-20003 | Out of range, navigating to next month
-20004 | User clicked date

-sr, sc (Num) [in]

Initial upper left corner of dialog in standard row/col units or in millirows and millicols.

title (String) [in]

Title (caption) for dialog. Ignore if the XCALF_NOCAPTION flag set in xcflags.

sdate, edate (B,4) [in]

Starting/ending date of range to allow for navigation. Standard ODTIM/IDTIM format. When user tries to navigate outside this range, routine returns exitcode -20002 or -20003.

coldef (String) [in]

Optional Advanced Coldef Options to be appended to the one automatically built. Allows you to customize the behavior of the control based on the capabilities of XTREE. Note that since the coldef string may grow quite large, and be frequently added to, you should probably use a dynamic string (s,0), lest you end up wasting time tracking down errors due to the string being truncated.

xcflags (B,4) [in]

Optional flags as defined in ASHINC:xcalen.def:

Symbol | Value | Description
XCALF_NOCAPTION | &h0001 | Eliminate caption bar from dialog
XCALF_ARCEDIT | &h0002 | Allow right click to edit text for date; see comments
XCALF_EDIT | &h0004 | Edit text for the current date

Requirements

Two icon files, nav_left_24.png and nav_right_24.png are used for the left/right navigation arrows and must be stored in the %miame%/icons subdirectory of the client workstation. You can replace them with any 24x24 png images using the same file names.

Comments

Each call to the XCALEN.SBX routine scans the xcdates() array, creates the control, and then puts the focus on the calendar grid, allowing the user to navigate between months (up until the limit set by the starting/ending dates specified in the sdate,edate parameters). If allowed by the XCALF_EDIT flag, the user can right-click a date to edit the text associated with it. Or they can exit from the calendar mode by generating just about any other exitcode (i.e. ESC or click on another control). On return from the XCALL, the calendar control is still visible, so you can leave it on the screen for visible reference.

Aside from the XTREE customization possible via the coldef parameter, further customization would probably require making a copy of the XCALEN.BP source code (available in [907,49] of the SOSLIB) and modifying it directly for your purposes.

Other than the internal ability to edit the text for a date, responsibility for maintaining the array of date information (text and colors) is purely on the programmer and outside the realm of XCALEN.SBX.

History

2016 March, A-Shell 6.3.1507: Routine added to A-Shell


XDEFLT

xcall XDEFLT, string

XDEFLT.SBR inserts characters (string) into the type-ahead buffer. The characters will sit in the type-ahead buffer until the next input operation, when they will act like they were typed at that point. If the type-ahead string contains carriage returns, and/or the next input operation is limited in length, then the unused remainder of the type-ahead string will be used on the subsequent input operation, until it is all used up.


XFOLD

Updated April 2010

xcall XFOLD, string, {mode, control}

XFOLD.SBR converts (folds) a string to standard upper/lower case.

Parameters

string (String) [in]

contains the string to be folded or capitalized.

mode (Num) [in]

may be set to 0 for "word mode" or 1 for "sentence mode." In word mode, each word is capitalized, whereas in sentence mode, typically only the first word of a sentence is capitalized. If not specified, capitalizes as a name (i.e. word mode); see Comments, below.

control (String) [in]

contains a list of delimiters, followed by a list of exceptions. The format is:

/delimiters/exception1/exception2/.../exceptionN/

The "/" character in the above string can be any character, as long as it is used consistently and is not part of any of the delimiter or exception strings. The purpose of the exception list is to override the more simplistic capitalization logic, preventing things such as "John Doe Iii" or "Sigmund Freud, M.d." A typical control string might be:

/ ,;:).!?/II/III/Jr/Sr/Mr/Mrs/Ph.D./M.D./i.e./NASA/IRS//

Comments

If only the first argument is specified, then the string will be capitalized as a name using an implied control string of:

"/ ,./II/III/Ph.D./M.D.//"

This will, for example, convert a STRING passed as "john q. PUBLIC ii" to "John Q. Public II".

For sentence mode, the delimiters list must contain first all of the word delimiters, then the period, followed by all of the other sentence delimiters. For example, in the list "\ ,;:.!?\", the period, exclamation and question mark are treated as sentence delimiters, while the space, comma, semicolon, and colon are treated as word delimiters.

Each exception must represent a complete word token, and may not begin with a word or sentence delimiter. However, it may end with one.

See also the discussion "XCALL XFOLD question?" on the A-Shell Forum.


XFRMMO

xcall XFRMMO, opstat, ch1, link1, ch2, link2

XFRMMO.SBR is an utility to move or copy an INMEMO logical memo, either between two memo files or within a single file. If moving between files, it can also change the link size from 2 to 4 or vice versa.

Parameters

opstat (Num) [in/out]

On input, must be set to 0 to copy (preserving the source memo) or 1 to move (same as copy followed by deletion of the source memo). On return, it will be set to one of the following values to indicate whether the operation succeeded:

Value | Description | Value | Description
0 | Success | 2 | File full
1 | Link error | 3 | System error

ch1 (Num) [in]

is the open file channel for the source memo file.

link1 (B,2 or B,4 to match the format of the source memo file) [in]

is the link to the source memo. Note that if opcode is 1 (move), this memo will be deleted (and link1 returned as 0).

ch2 (Num) [in]

is the open file channel for the destination memo file (which may be the same as ch1).

link2 (B,2 or B,4 to match the format of the destination memo file) [out]

will return the new link to the destination memo.


XLOCK

(1) xcall XLOCK, mode, lock1, lock2 {,class}

(2) xcall XLOCK, mode, myjob, lock'array(1)

XLOCK.SBR provides an abstract symbolic scheme for locking anything, based on a pair of numeric values to which you assign your own meaning. Note that syntax two is used only for retrieving a list of locks (mode = 3).

Parameters

mode (Num) [in/out]

determines the operation, per the following table:

Value | Description
0 | Set lock specified by lock1 and lock2. If successful, mode is set to 0. Otherwise (if a conflicting lock exists), mode is set to the job number of the job holding the conflicting lock. See note about SBR=MXLOCK below for information how what happens if your job has already set the lock.
1 | Same as mode 0, except that if the lock cannot immediately be set, it waits until it can.
2 | Clear lock. On return, mode is set to 0 if your job did not own the lock (i.e. it was not cleared), else it is set to the number of locks cleared (which could be more than 1 in the case of wildcards).
3 | List locks. In this case, mode returns with the number of locks in the list; myjob is set to your job number, and lock'array contains the list of locks.
4 | Same as mode 0 but does not actually set the lock.
5 | Same as mode 1 but does not actually set the lock.

lock# (B,2 or B,4) [in]

lock1 and lock2 together contain a pair of numbers which are being locked or released. The numbers themselves have no inherent meaning, but a typical use is for one to indicate a file channel number and the other a record number. A value of zero in either parameter acts as a wildcard. For example, the pair 22,0 matches all of the pairs whose first value is 22. (This might be useful for representing an exclusive lock on all records within file 22.) The double wildcard 0,0 matches all possible combinations. The range of values depends on whether the parameters are mapped as b,2 or b,4.

class (Num, 0-65535) [in]

Optional lock pool identifier. May be used to avoid potential conflicts between applications that might otherwise be using the same range of lock values. See Comments, below.

lock'array

map1 lock'array

map2 lok'jobnum,b,2

map2 lok1,b,x ! b,2 or b,4; must match size of mode param

map2 lok2,b,x ! " " "

Comments

The A-Shell implementation of XLOCK.SBR is upward compatible with the AMOS one, so you can refer to the AMOS.SBR documentation for more details. Note the following A-Shell enhancements:

• A-Shell supports lock1 and lock2 variables of either B,2 or B,4 (allowing values of up to two billion), whereas the AMOS version is limited to two-byte values.

• Under A-Shell, you have the option of treating a value previously locked by your job as available (default) or locked. In the latter case, you must set the miame.ini parameter SBR=MXLOCK; see SBR=MXLOCK and also SBR=AXLOCK, the latter of which controls whether a certain bug in the AMOS implementation will be emulated or not.)

• The optional class parameter allows you to create multiple locking pools (such as in multiple applications) which do not conflict with each other. The standard version of XLOCK uses lock class 0 for normal locks and lock class 256 for pending exclusive locks. Lock class 1 is used by the Aesops routine LOCK.SBR, and classes 2 and 3 are used by the OmniLedger routines XFLOCK.SBR and XLOCKS.SBR, respectively. If you want to define your own, we suggest picking something in the range of 100 to 200.

• An additional enhancement is that of lock "reservations." These were implemented to reduce the difficulty of establishing an exclusive (or wildcard) lock on a file (or other resource, represented by the lock1 value) in which multiple jobs are actively placing individual record locks. The problem is that the job desiring the exclusive lock may have to wait an unreasonable amount of time, since as long as there is one lock in the lock1 resource, the exclusive lock cannot be set, and even worse, there is no way to stop additional jobs from coming along and setting locks. The idea of the lock "reservation" is that once set, no new locks can be set on the resource, except by jobs that already have one or more locks set on that resource. This allows those jobs already using the resource to finish their transaction, but any additional jobs will have to wait until after the exclusive lock activity is complete. To use this feature, set mode to 4, lock1 to the resource you want exclusive control of, and lock2 to zero. This acts just like mode 0 (lock but do not wait) except that if the exclusive (wildcard) lock cannot be established, a reservation is set instead (using lock class 256). The calling job gets the same failure code as it would for mode 0 (i.e. mode is set to the job number owning the first conflicting lock). However, from that point on, no other jobs can set a lock conflicting with the reservation, unless they already have a lock set in that range. The calling job then repeats the mode 4 request periodically until the return value indicates success (at which point the reservation will have been converted to a normal lock, or in other words, the lock class will be changed from 256 back to 0).

• The final enhancement is the addition of two new modes which allow you to check for the presence of a lock without actually having to place one. mode 4 is like mode 0 (no waiting), and mode 5 is like mode 1 (wait until available) except that modes 4 and 5 do not actually set a lock. It will be left as an exercise for the clever programmer to figure out what possible motivation there could be for such a capability.

• The QUTL utility may be used to display the list of locks in use, as well as to forcefully clear them by resetting the job owning the locks.

• Note that XLOCK.SBR isn't really a file or record locking system (even though that's what people mostly use it for). It is really just a mechanism for limiting access to arbitrary resources which are coded using a pair of numeric values. There is no inherent meaning to the numeric values contained in your "locks". It is the application (and not A-Shell or the operating system) that has assigned meaning to the numeric values (typically using the first number to indicate the file channel and the second to indicate the record number).


XPAINT

xcall XPAINT, paintlit

XPAINT.SBR was developed to allow screens that were created with AlphaPAINT 2.0 screens to be executed by A-Shell. Under AMOS, these screens are assembled into LIT file executables, which are typically executed via AMOS.SBR. Since AMOS machine code will not run on other operating systems directly, A-Shell provides this interpreter that reads the specified LIT file and produces the expected screen display. Note that this only works for LITs generated by AlphaPAINT 2.0.


XPPN

xcall XPPN, ppn, device, job, trmdef

XPPN.SBR returns the PPN, Device, Job, and Trmdef in the formats shown below.

Parameters

MAP1 PPN

MAP2 Project,B,2

MAP2 Programmer,B,2

MAP1 Device,S,8 ! (e.g. "DSK1:")

MAP1 Job,S,6

MAP1 Trmdef,S,6

Comments

A confusing situation arises when PPN values, which by convention are always represented in octal notation (ranging from zero to 377, rather than zero to 255 as they would if represented in decimal), are stored in numeric variables. Since BASIC has no provision for displaying the value of a numeric variable in anything other than decimal, when the PPN [100,200] is stored in the Project and Programmer fields above and later printed using the PRINT statement, they would display (in decimal) as 64 and 128. To display them in their correct format as octal, you could use the MX_OCVT.

Another approach would be to set SBR=XPPNOCT in the system configuration file, which causes XPPN.SBR to correct for the octal/decimal discrepancy by converting the returned Project and Programmer values such that they display in decimal as if they were octal. Thus, the PPN [100,200] would be returned as Project=100 and Programmer=200, which is probably what you were expecting.

You might wonder why this was not done by default. The reason is that under AMOS, PPNs were stored as a pair of bytes (each byte ranging from zero to 377 octal). For closer compatibility, A-Shell internally uses the same representation, even though it is arguably arbitrary since at the operating system level, PPNs are mapped to directories that are purely text strings. However, many existing BASIC programs and subroutines relied on the fact that PPNs could be stored in a pair of single byte variables, and thus at some point we would have had to deal with the conversion anyway. 377 decimal does not fit in a single byte, which is why this particular subroutine uses the somewhat non-AMOS-like technique of storing the PPN as a pair of two-byte variables. For comparison, GETJTB returns the PPN both as a single two byte field and as a pair of three-byte strings (for binary and octal representations).

History

2009 September, A-Shell 5.1.1159: Routine modified to support returning data into dynamic variables, such that they expand as needed. Previously, the output data was being truncated to the current size of the variable, or 0 for uninitialized.


XSHLEX

Added January 2017

xcall XSHLEX, objectspec {,status, action, parms, dir, showflags, waitflag, clisvr, exitstatus}

The subroutine XSHLEX.SBX provides a standardized and robust way of doing a "Shell Execute"—i.e. launch the application that goes with a specified file or URL object—without having to consider which platform you are using. This does not provide much advantage over MX_SHELLEX for those in a pure local Windows environment, but for developers programming across various environments, it eliminates the need for logic to deal with local/remote and file transfer considerations. For example, in an ATE environment, it detects if the object is a file on the server, and if so, transfers it automatically to the ATECACHE directory when it then launches the corresponding app.

The parameters all correspond to the equally named MX_SHELLEX parameters, which see for specifications. Only the deviations/extensions from the MX_SHELL parameter descriptions are noted below. Also note that the order of the first two parameters is reversed from MX_SHELLEX, reducing the minimum syntax to a single parameter.

objectspec (String) [in]

File or URL to launch. Unlike MX_SHELLEX, the file spec may be in AMOS format; the routine will figure out if it is relative to the server or the client. If on the server in an ATE or ZTERM connection, file will be transferred to the client for launch using ATEAPX.SBX.

status (Num) [out]

Combines status codes returned by MX_SHELLEX, with those of ATEAPX.SBX—which is used for file transfer if necessary—and adds a few more. The best reference, both for documentation and actual program usage, is the function Fn'Shell'Exec'Status'Description$() in the SOSLIB fnshellex.bsi function .

action, parms, dir$, showflag, waitflag, exitstatus

same as for MX_SHELLEX

clisvr (String) [in]

Similar to MX_SHELLEX usage, except that if omitted or blank, the routine will attempt to figure out if objectspec is a file on the server or client. If the application knows the object is on the client PC, it can set it to "C" (for client) to avoid the self-determination logic.

Comments

The new fnshellex.bsi module (see link above) contains a convenient wrapper function Fn'Shell'Exec(objectspec$) for maximum simplicity, e.g.:

STATUS = Fn'Shell'Exec(objectspec$)

History

2017 January, A-Shell 6.3.1542: Routine created and added to the standard A-Shell distribution package.


XSTRIP

Added May 2011

xcall XSTRIP, strarg

xcall XSTRIP, strng, filter, opcode

XSTRIP.SBR performs various string editing operations. Note that in the first syntax, the routine is equivalent to XCALL STRIP (removes trailing blanks).

Parameters

strarg (String, 2+ bytes) [in/out]

the string to be operated on.

filter (String, 1+ bytes) [in]

contains filter info, depending on opcode.

opcode (Num) [in]

defines the operation.

Opcode | Function
1 | All occurrences of any of the individual characters in the filter are removed from strarg.
2 | All occurrences of characters NOT in filter are removed from strarg.
3 | Remove Words. Filter contains a comma-separated list of words to be removed from strarg. Double spaces resulting from the removal of a word are shortened to a single space. Example: strarg = "THIS IS A TEST OF THIS XCALL ROUTINE" filter = "THIS,TEST,ROUTINE" XCALL XSTRIP,strarg,filter,3 Result: strarg = " IS A OF XCALL "
4 | Removes matching characters from start of string. For example: strarg = "THIS IS A TEST TO SEE WHAT IS HAPPENING." filter = "SIHT " XCALL XSTRIP,strarg,filter,4 Result: strarg = "A TEST TO SEE WHAT IS HAPPENING." Note: The removal process was terminated at the first character of strarg for which there was no match in filter ("A").
5 | Remove matching characters from the end of the string. Same concept as opcode 4 but starts at the end of strarg and works backwards.
6 | Pair-wise character substitution: Filter must contain an even number of characters, interpreted as pairs. Each occurrence in strarg of the first character in each pair (of filter) is replaced with the second character of the pair. Example: XCALL XSTRIP,strarg,"A1B2",6 ! replace all "A" with "1"; "B" with "2"
7 | Reduce multiple spaces to single spaces. Filter not used. E.g.: XCALL XSTRIP,strarg,"",7

History

2011 May, A-Shell 5.1.1215: XSTRIP.SBR added to the standard release, after fixing some bugs introduced in 5.1 during translation of the original proprietary version written by John Pruitt.


XTEXT

xcall XTEXT, opcode, flags, src, dst, srow, scol, erow, ecol, exitcode, txtctl {, auxdata, fmtdef}

XTEXT.SBR provides access to a general purpose Windows text editing control in the A-Shell GUI environment. It is similar in concept to the INFLD multi-line feature, but goes well beyond INFLD to offer such features as:

• Ability to perform I/O to / from either text buffers or files.

• Essentially no limit on the size of the text, particularly in file mode.

• Optional RTF (Rich Text Format) support, including character attributes (bold, italic, etc.), fonts, paragraph styles, justification, etc.

• Search and replace.

• Optional / configurable interface components, such as ruler, toolbar, status bar.

• May be contained within another window or float independently (in which case it can have its own title bar and menu).

• Ability to protect existing text when adding new text.

Programmers familiar with XTREE may find that XTEXT is to a simple multi-line edit control as XTREE is to a simple list box, and in fact, the parameter structure and general design of XTEXT have a number of similarities to XTREE.

XTEXT requires the presence of an external module, TER##.DLL, which must be in the Windows system directory or the directory from which ashw32.exe was loaded.

See the updated ashell.def (edit 135+) for definitions of all symbols used in XTEXT (they all start with TX) and XTEXT.MAP for the layout of the txtctl parameter.

See the XTX1.BP in [908,40] of the EXLIB for a working example and utility for testing the usage of various flags and parameter options.

History

2016 December, A-Shell 6.3.1541: Add flag TXF_SILENT.

See other changes at XTEXT Updates.

Subtopics

Text Editing Overview

XTEXT Parameters

Other XTEXT Topics


Text Editing Overview

Although at its simplest, text editing can be considered more or less the same as an INFLD field editing operation (particularly INFLD's multi-line mode), XTEXT allows for a much more sophisticated approach, which can be broken down into the following sub-operations:

Create the control: The subroutine allows you to create a new control for each text editing session, or re-use an existing one. Up to five separate text editing controls can be defined at any one time.

Load text into the control: You can supply text to be edited by specifying a text file (plain text or RTF), or by passing the text in a string buffer. Unlike INFLD, the control can also maintain its own copy of the text between editing sessions, so that it does not have to be passed back and forth with the application each time the control gains/loses the focus.

Edit the text: The control allows for a full range of typical editing capabilities that will be familiar to most Windows users. The application has the ability to define various aspects of the display interface (size, toolbars, menus, rulers, window style, whether to display control characters, etc.), the editing format (e.g. wrap, whether character attributes are allowed), and keyboard commands (i.e. which function keys are passed to the control vs. causing the control to return to the application.)

Retrieve text from the control: The application can request to retrieve the control's text automatically when the user exits the control, or as an independent operation such as when the changes to an entire screen are to be finalized. The application can retrieve the text directly into a string buffer, or indirectly via a text file. In the case of the string buffer, if the text is too large for the buffer provided, the application is given the option of allocating a larger buffer (using Dynamic Arrays) and retrieving it again, or retrieving it in multiple pieces.

Store the text: If you use the option for direct file i/o, then that can be your storage format. Otherwise, if you retrieve the text into a string buffer, the application is left to its own devices as far as storage goes. You might decide to use the ISAM-A variable length record capability, or perhaps just break it up into a series of fixed length records, or maybe even use INMEMO as a filing system.

Destroy the control: The control may be destroyed automatically at the end of an editing operation, or explicitly under application control, or implicitly (as with other A-Shell AUI controls) when the screen is cleared.

Printing: If text editing is limited to plain text, then printing can be handled as it is for any other text data (although you may have to deal independently with the question of how to format a variable-length string of text into a suitable printing format). Most likely you will find that A-Shell's GDI Printing directives //TEXTRECTANGLE and/or //TEXTINDENT and/or //XTEXT, along with the MX_GDICALC subroutine, are quite useful for printing variable-length blocks of text.

If the text editing is more file-oriented, and especially if it includes character and other formatting attributes (RTF), you may want to enable the ability of the control to print its own contents directly to a printer, more or less like a normal word processing application would (see TXF_TOOLBAR and txc'toolbarmask for adding the printer icon to the toolbar, and txc'fmapctl to allow the F4 key to invoke printing.)

To embed RTF-formatted text directly into another A-Shell report, use the //XTEXT GDI Printing Directive.


XTEXT Parameters

Parameters that supply data to the routine are indicated with [in], and those used to get data from the routine are labeled [out].

Parameter | Type | I/O | Description
opcode | Num | in | Specifies the operating mode.
flags | B,4 | in | Used to enable exit keys and other options.
src | String | in | Source of text to be edited.
dst | String | out | Destination for updated text.
srow, scol, erow, ecol | String | in | Position of the control, based on the grid system used by the parent control.
exitcode | F,6 | out | Returns a code indicating how the list was exited.
txtctl | → | in/out | (Mapped structure) A collection of extended parameters and options.
auxdata | String | in/out | If a text string is supplied in the AUXDATA parameter, it will be used for the title of any dialog box displayed under XTEXT's direct control. If AUXDATA is not specified, or null, then XTEXT continues to use the SYS:APPMSG.xxx 000,001 message string, which is normally reserved for the application name.
fmtdef | String | in | Specify target printer.


opcode

Opcode (Num) determines the operational mode.

Symbol

Value

Description

TXOP_CREATE

1

This is the only operation you really need. It starts by creating a new text editing control or re-using an existing one, based on the txc'ctlno field of the txtctl parameter (which see for details). The control is then loaded with text, based on the src parameter and txc'docfmt'src field of the txtctl parameter. In this, the "normal" usage mode, a single XCALL XTEXT causes the control object to be created and loaded with data. (If the src parameter is empty, the new control starts out empty.) The focus is then put on the control, where the user can perform text editing operations until some kind of exit key or event is triggered. At that point, unless the TXF_DEFERSAVE flag is specified, the contents of the control are returned to the application via the dst parameter. Finally, unless the TXF_MODELESS flag is specified, the control is deleted.

TXOP_REEDIT

2

The reedit operation is identical to the TXOP_CREATE operation except that it operates on an existing control and its existing contents. If you have more than one active text edit control defined, then the txc'ctlno field of the txtctl parameter must indicate which one to reedit. The src parameter is ignored.

TXOP_DELETE

3

The operation deletes the control, and is only necessary when the control was created with the XTF_MODELESS flag (otherwise it would have been deleted automatically). Note that you can also delete the XTEXT control (like any other control) by clearing the screen with Tab(-1,0);

TXOP_DISPLAY

4

The display operation creates the control, displays it, and leaves it on the screen (regardless of whether XTF_MODELESS set.

TXOP_SAVE

5

The save operation retrieves the current contents of the specified text control and either returns it to the application or writes it to a text file, depending on the

txc'docfmt'dst

flags. This is useful in conjunction with previous TXOP_CREATE operations using TXF_DEFERSAVE and TXF_MODELESS flags. (TXOP_SAVE overrides the TXF_DEFERSAVE flag.)

TXOPF_PRINT

&h010

May be added to TXOP_CREATE or TXOP_REEDIT to print an XTEXT document independently of anything else and outside of the normal A-Shell printing subsystem.

The combination TXOP_CREATE + TXOPF_PRINT can be used to print an XTEXT document from the source (file or buffer), while TXOP_REEDIT + TXOPF_PRINT can be used to print an XTEXT document that is currently open and displayed.

You may also request to have XTEXT display a standard printer select dialog by setting the flag TXF8_SEL_PTR_DLG (&h10000000) to the txc'flags8 field in the txtctl parameter.

If the printer dialog option is not select, then printing via TXOP_CREATE + TXOPF_PRINT will not display the XTEXT.

Note that this flag was added to A-Shell in build 1149 of May 2009. When used with ATE, both A-Shell (server) and ATE (client) require that version or later.

TXOPF_PREVIEW

&h020

Mmay be added to TXOP_CREATE, TXOP_REEDIT, or TXOP_DISPLAY to cause XTEXT to display the print preview window. In the case of TXOP_CREATE or TXOP_REEDIT, the user will be left to manipulate the preview, which also means that he/she will be able to print and/or return to edit mode.

Definition file: XTEXT.DEF


flags

This parameter may be used to enable additional exit keys and other options. Specify as the sum of zero or more of the following.

Symbol | Value | Description
TXF_FKEY | &h00000001 | Allow F1 through F16 (returning Exitcodes -1 through –16). You must also set individual bits in txc'fmapapp to indicate which function keys you want returned to the app as exitcodes.
TXF_LEFT | &h00000002 | Enable Ctrl+LeftArrow (Exitcode -40)
TXF_RIGHT | &h00000004 | Enable Ctrl+RightArrow (Exitcode –41)
TXF_UP | &h00000008 | Enable Ctrl+UpArrow (Exitcode -42)
TXF_TAB | &h00000020 | Enable Tab (Exitcode -44), and Shift+Tab (Exitcode -35)
TXF_HOME | &h00000040 | Enable Ctrl+Home key (Exitcode –45)
TXF_END | &h00000080 | Enable Ctrl+End key (Exitcode –46)
TXF_ENTESC | &h00000100 | Enter key exits from control (Exitcode 0)
TXF_MODELESS | &h00000200 | Leave text control on the screen after exit
TXF_EOT | &h00000400 | Start editing with cursor at end of text (rather than start)
TXF_DEFERSAVE | &h00000800 | Defer (or skip) outputting text from the control to the dst parameter (unless overridden by TXOP_SAVE opcode).
TXF_HSCROLL | &h00002000 | Display horizontal scroll bar
TXF_VSCROLL | &h00004000 | Display vertical scroll bar
TXF_RULER | &h00008000 | Display ruler
TXF_STATUS | &h00010000 | Display status bar
TXF_TOOLBAR | &h00020000 | Display toolbar
TXF_READONLY | &h00040000 | Read only mode. Note that unless you also set TXF_DEFERSAVE, the text will still be output.
TXF_POSCUR | &h00080000 | Set initial cursor position.
TXF_SILENT | &h00100000 | Eliminates the user interface and causes the operation to exit immediately. This is mainly useful in conjunction with TXOP_CREATE to convert a file from one format into another.
TXF_DISABLE | &h00200000 | Disable control on exit
TXF_DEL | &h00400000 | Enable Del exit (Exitcode –47)
TXF_MARGIN | &h00800000 | Create space around border
TXF_NOCLICKOUT | &h01000000 | Ignores any click outside of the control with exitcode <-32.
TXF_WRAP | &h02000000 | Enable word wrap. Note that this flag may also be required to enable pasting of images and inserting of tables.
TXF_PRINTVIEW | &h04000000 | Enable print view
TXF_PAGEMODE | &h08000000 | Enable page mode
TXF_FITVIEW | &h10000000 | Enable fitted view (text is wrapped to fit width of control).
TXF_POPUP | &h20000000 | Give text control its own popup (movable) window
TXF_MENU | &h80000000 | May be combined with TXF_POPUP to create a text editing control window with a complete menu bar. This exposes many new capabilities, particularly for RTF editing.
Definition file: XTEXT.DEF


TXF_MODELESS

Leave edit control on the screen after exit from the subroutine, for possible re-entry or refresh later. (See opcode.) (The symbol name, TXF_MODELESS, is meant to represent "modeless", since this makes the edit control act something like a modeless dialog, i.e. a dialog that allows you to click back on the main window without first closing it, as opposed to the normal "modal" dialog.)

See Also

• TXF_DISABLE

• TXF_DEFERSAVE.


TXF_STATUS

This flag causes the status bar to appear at the bottom of the control, as shown in the example below:


TXF_TOOLBAR

Enable the display of a toolbar. By default the toolbar is two rows high and contains all of the objects shown in the screen shot below. (A ruler is also shown here, although it is enabled via the TXF_RULER flag.

You can reduce the toolbar display to just the first or second row, and you can also remove each of the objects (individually or in related groups) via flags in the txc'toolbarmask field of the txtctl parameter. For example, if you want to limit editing to plain text, you will probably want to remove the buttons and drop-down boxes related to character and paragraph attributes. And unless you want to allow the user the freedom to perform their own file operations (new, open, save, print, etc.) then you would probably want to remove those icons as well. See TXF_STATUS for a screen shot of a stripped-down toolbar.

See Trapping Toolbar Commands for additional information on intercepting mouse clicks on certain toolbar icons so that the application can handle them.


TXF_POSCUR

When set (and TXF_EOT not set), the initial cursor position for an editing session will be determined by the txc'xrow and txc'xcol parameter (if both are non-zero), or else by txc'xcuroffset. This can be useful when you want to start an editing session at some location other than the start or end of the text, and when searching (see txc'srchkey) to establish the initial position of the search operation.


TXF_DISABLE

Disable the text control on exit. Only makes sense if TXF_MODELESS also set. This might be useful to either visually make it clear to the user that the control is not active, or to eliminate the need to process a keyboard click string for when the user clicks on the control outside of the confines of XCALL XTEXT. See txc'kbdstr.


TXF_NOCLICKOUT

Without this flag, XTEXT will exit whenever you click on any object whose click string generates an exitcode of -33 or below. (This would be the normal situation for a screen or dialog that allows users to jump around by clicking on different fields, but because of the higher overhead of an XTEXT operation compared to simpler controls, or perhaps because you want to encourage the user to concentrate on writing a proper note, you might want to discourage them from exiting the operation in such a casual manner.) With the TXF_NOCLICKOUT specified, XTEXT will ignore such clicks. You will still be able to exit via Escape, Enter, or any of the explicit exit keys allowed by other flags bits.


src

The src parameter specifies the source text to be edited, and is interpreted in conjunction with the txc'docfmt'src field of the txtctl parameter, in one of the following ways:

• File: To specify a file to edit, set src to the filename, and set the TXFF_FILE flag in the txc'docfmt'src field of txtctl. Note that other bits in the txc'docfmt'src field should be set to indicate whether the file is in plain text or RTF format.

In the ATE environment (i.e. when running under UNIX with an ATE client), if the filename does not contain a drive letter or backslash, then it is interpreted as being resident on the server and is automatically transferred to the %ATECACHEDIR% directory on the client workstation for editing.

• String Buffer: To specify a string buffer, map src as a string variable of suitable size, load the initial text into it, and do not set the TXFF_FILE flag in txc'docfmt'src field.

• Current Control Contents: To reedit the current contents of an existing control, src is not required. Instead, set opcode to TXOP_REEDIT, txc'ctlno to the text control number.


dst

The dst parameter specifies the destination (where the updated text from the editing operation will be returned), and is interpreted in conjunction with the txc'docfmt'dst field of the txtctl parameter in one of the ways listed below. Note that while the destination and destination format are independent of the source, they can also be the same (i.e. the same filename or the same text buffer variable).

• File: To output to a file, set dst to the filename, and specify the TXFF_FILE flag in the txc'docfmt'dst field of txtctl.

• In the ATE environment (i.e. when running under UNIX with an ATE client), if the filename does not contain a drive letter or backslash, then it is interpreted as being resident on the server. Since the editing takes place on the workstation, the output is first saved to the local %ATECACHEDIR% directory and the transferred to the server.

• Internal Memory Buffer: If you set the TXF_DEFERSAVE flag, the updated text is held in an internal memory buffer owned by the control, and the dst parameter is ignored. (The idea here is that you will subsequently make another call to reedit the control using opcode TXOP_REEDIT.)

• String Buffer: To output the updated text to a string variable, map dst as a string of suitable size, and do not set the TXFF_FILE flag in txc'docfmt'dst field. If the amount of text in the control is too much to fit, then the txc'overflow field in the txtctl parameter will be set to 1, and only the amount that actually will fit will be output. At that point, your application has the option of retrieving the text using one or more subsequent calls using opcode TXOP_SAVE. Initially the txc'saveoffset field will be set to the position of the first unsaved byte (e.g. the size of dst), and subsequent save operations will start from that offset and then update the txc'saveoffset field accordingly. If you prefer to get the entire text into a single text buffer, you can first allocate a string variable of sufficient size (probably using the DIMX statement), and then set the txc'saveoffset field to -1 before calling XTEXT with opcode TXOP_SAVE. (If you set txc'saveoffset to 0 rather than -1 it will not realize that there was a previously incomplete save operation and will behave unpredictably.)

The txc'outbytes field will be set to the total size of the updated text. So to retrieve the entire text in a single step without the possibility of overflowing, you can first edit the control with the TXF_DEFERSAVE flag set, then allocate a dst variable of size matching txc'outbytes, then use opcode TXOP_SAVE to retrieve the text in one step.

Warning: the dst and src parameters must reference separate variables, else the initialization of the dst string will clear the src string before it gets displayed.


srow, scol, erow, ecol

The parameters srow, scol, erow, ecol (any numeric type) mark the upper left and lower right corners of the text editing box. Note that the size of the box does not affect the amount of text that can be edited, although it may affect the way the text is wrapped. See the flags TXF_HSCROLL, TXF_VSCROLL, TXF_FITVIEW.

If the TXF_POPOP bit is set in the flags parameter, the pop-up dialog will initially occupy the space specified by these row/column coordinates, but the user will be able to drag and resize the dialog. If the coordinates are negative, they are interpreted as pixel coordinates, allowing you to position the popup window relative to the desktop rather than the dialog or main A-Shell window.


exitcode

The exitcode parameter serves the same function as the corresponding parameter of the same name in routines such as INFLD and XTREE, i.e. it returns a code indicating how the control was exited, as summarized in following table. See the flags parameter for enabling other exit keys.

Exitcode | Meaning
0 | Normal exit (Escape w/ update, Enter with TXF_ENTESC)
1 | Cancel (Escape w/o update)
10 | Abort (Ctrl+C)
11 | Timeout; see txc'timeout in the txtctl parameter.
-35 | Shift+Tab (if TXF_TAB)
-40 | Ctrl+LeftArrow (if TXF_LEFT)
-41 | Ctrl+RightArrow (if TXF_RIGHT)
-42 | Ctrl+UpArrow (if TXF_UP)
-44 | Tab (if TXF_TAB)
-45 | Ctrl+Home (if TXF_HOME)
-46 | Ctrl+End (if TXF_END)
-47 | Del (if TXF_DEL)
-49 to -99999 | Another object clicked
99 | Unable to link to DLL
98 | Invalid txc'ctlno
97 |
96 | Unable to load (or save) text file
95 | Unable to allocate or lock memory
94 | Unable to load text buffer into control
93 | Control deleted by txc'delctlid


txtctl

Updated August 2011

This is a collection of extended parameters and options. The exact structure layout is defined in the definition file noted at the bottom of the table, which should be included in applications using XTEXT.

By convention in this document, we refer to the sub-fields within the txtctl structure with names preceded by the prefix txc' (e.g. txc'ctlno).

Symbol | Type | I/O | Description
txc'bcolor | B,4 | in | Background (window) color. See txc'fcolor.
txc'bprotclr | B,4 | in | Background protected color. See txc'protrows.
txc'ctlid | B,2 | out | Control ID (overall A-Shell AUI control list).
txc'ctlno | B,1 | in/out | Specifies control to use.
txc'delctlid | B,4 | in | ID of control to delete on entrance (life sign). This functions exactly like the analogous XTR'DELCTLID parameter in XTREE, which see for important notes.
txc'docfmt'dst | B,2 | in | Format of output (dst).
txc'docfmt'src | B,2 | in | Format of input (src).
txc'fcolor | B,4 | in | Foreground (text) color.
txc'flagmask | B,2 | in | 1's indicate which flags to update
txc'flags# | B,4 | in | Various low-level flags; see TXF#_xxx in XTEXT.DEF.
txc'fmapapp | B,4 | in | 1's enable FKEY to be send to app (exitcode).
txc'fmapctl | B,4 | in | 1's enable FKEY to be sent to control.
txc'fontattr | B,4 | in | Expresses font attributes in the same way as does fontattr in AUI_CONTROL.
txc'fontface | S,32 | in | Font typeface.
txc'fontsize | B,2 | in | Font point size.
txc'fprotclr | B,4 | in | Foreground protected text color.
txc'hflagmask | B,2 | in | Bitmap controlling interpretation of the txc'flags# fields; ; same concept as for txc'flagmask.
txc'hflags# | B,4 | in | HTML flags. See TXFH1_xxx and TXFH2_xxx in XTEXT.DEF for bit flag definitions. Note that most options require that the source document format as well as the destination (see txc'docfmt'src and txc'docfmt'dst) have the TXFF_HTML flag set —i.e. they may not work when converting from one document type to another. Also, see the Comments under txc'docfmt'dst for important notes relating to the TXF_PRINTFIEW and TXF_FITVIEW flags.
txc'idname | S,40 | in | ctlname or parentname>ctlname
txc'kbdstr | S,11 | in | Click code.
txc'maxbytes | B,2 | in | Maximum bytes allowed (0 = unlimited).
txc'maxrows | B,2 | in | Optional row count limit. If specified, a warning dialog will display when the limit is exceeded (as soon as it happens, periodically, and on exit). Text of dialog can be customized via SBRMSG.xxx 023,002 and 023,003.
txc'menumask1, txc'menumask2 | B,4 | in | TXC'MENUMASK1 and TXC'MENUMASK2 allow individual items and groups of menus to be removed when the TXF_MENU and TXF_POPUP flags are used. See TXMF1_xxx and TXMF2_xxx in XTEXT.DEF for the bit flag definitions.
txc'mgnbottom* | B,2 | in | Bottom margin (twips). Mainly of interest in TXF_PRINTVIEW mode.
txc'mgnfooter* | B,2 | in | Footer margin (twips). Mainly of interest in TXF_PRINTVIEW mode.
txc'mgnheader* | B,2 | in | Header margin (twips). Mainly of interest in TXF_PRINTVIEW mode.
txc'mgnleft | B,2 | in | Left margin (twips). Mainly of interest in TXF_PRINTVIEW mode.
txc'mgnright | B,2 | in | Right margin (twips). Mainly of interest in TXF_PRINTVIEW mode.
txc'mgntop | B,2 | in | Top margin (twips). Mainly of interest in TXF_PRINTVIEW mode.
txc'modified | B,1 | out | Non-zero if text buffer modified.
txc'orient* | B,2 | in | Orientation (0=dflt, 1=port, 2=land). Mainly of interest in TXF_PRINTVIEW mode.
txc'outbytes | B,4 | out | Number of bytes output.
txc'outlines | B,4 | out | Number of lines output (or to be output).
txc'overflow | B,1 | out | Non-zero if text too big for dst param.
txc'papersize* | B,2 | in | Paper size (see DMPAPER_xxx). Mainly of interest in TXF_PRINTVIEW mode.
txc'parentid | B,2 | in | ID of parent of control (e.g. a dialog): 0 for a normal child control on the main window.
txc'protrows | B,4 | in | Rows to protect (-1 = all, -2 all but last).
txc'saveoffset | B,4 | in/out | Position in buffer to start next save (or -1 to restart a previously incomplete save operation from the beginning).
txc'sflags | B,2 | in | Search flags
txc'srchkey | S,30 | in | String to search for
txc'timeout | B,4 | in | Milliseconds until timeout. The timer gets reset on keystrokes and on mouse activity within the control. If the timer expires, XTEXT will return EXITCODE=11 (like INFLD and XTREE) and any editing changes will be saved.
txc'toolbarmask | B,4 | in | 1's remove object from toolbar (see TXTB_xxx).
txc'wrapwidth | B,2 | in | Width in characters for word wrap.
txc'xcol | B,2 | in/out | Cursor column on exit and optionally on entrance (base 1) See TXF_POSCUR
txc'xcuroffset | B,4 | in/out | Absolute cursor position on exit and optionally on entrance. (base 0)
txc'xrow | B,4 | in/out | Cursor row on exit and optionally on entrance (base 1). See TXF_POSCUR
Definition file: XTEXT.MAP

* Note: Prior to A-Shell 1149 of May 2009, the (original) size of TXTCTL was 256, so it may be that existing applications or functions have a 256 byte limit which would make the fields marked with an asterisk invisible. For the same reason, if using XTEXT from ATE, both server and client would need to be at 5.1.1149 or higher in order for all the new fields to work.


txc'ctlno

When multiple XTEXT controls are in simultaneous use, specifies which one (range is 0 through 4) to use for this call. If opcode = TXOP_CREATE, you can set txc'ctlno to –1 to have XTEXT automatically assign the next available control number. If the control is modeless, you will need to save the returned txc'ctlno value for referencing it in subsequent calls. If you use only one XTEXT control at a time, you can just set this to 0 and ignore it.


txc'kbdstr

This field is used to specify the keyboard string that will be transmitted when this control is clicked (when not already active.) Typically you would set it to a Virtual Key Code, such as VK_xF101, so that if this control was clicked while another control had the focus, that control would exit with the corresponding exitcode value (-101 in this case) allowing your app to take the necessary action to switch the focus to this control.


txc'wrapwidth

This field only applies when the TXF_WRAP bit is set in the flags parameter, and neither of the flags TXF_FITVIEW or TXF_PRINTVIEW are set. In that case, it specifies the wrap width in character units. Note that with a proportional font, it may appear that the wrap trigger is different on each line.

If TXF_FITVIEW is specified, then this field is ignored and the wrap width is equal to the control width.

If TXF_FITVIEW is not specified and txc'wrapwidth is 0, then the wrap width will be determined by the ruler or the printer page width.

If TXF_PRINTVIEW is specified, txc'wrapwidth is ignored and wrap is determined by the combination of the paper width (txc'papersize), margins (txc'mgnleft, txc'marginright), and font (txc'fontface, txc'fontsize).

If the TXFF_TEXT_LINES bit is set in the txc'docfmt'dst parameter, the output lines will be terminated with line breaks at the point of the wrap (regardless of how the wrap was determined).


txc'docfmt'src

Updated May 2011

This field contains flags which adjust the interpretation of the src parameter. Choose no more than one value from each of the two sections of the following table.

Doc format | Value | Description
Storage medium |  |
TXFF_TEXT | 0 | Standard notepad-style text. CRLF is used to terminate paragraphs, not individual lines.
TXFF_TEXT_LINES | 1 | Text with line breaks. This only applies to the output, and if set, inserts line terminators at the points where wrap occurs.
TXFF_RTF | 2 | RTF (Rich Text Format)
TXFF_HTML | 4 | HTML (browser mode)
TXFF_UTEXT | 5 | Unicode text
TXFF_SSE | 6 | Proprietary (SSE) format
TXFF_STRING | &h0000 | String variable (aka "buffer," as opposed to "file")
TXFF_FILE | &h0100 | File (versus string/buffer). In the case of TXFF_HTML, this may also be a valid web URL. See Browser Mode.
TXFF_RAWBUFF | &h0400 | May be set in the txc'docfmt'src field to cause the source file to be transferred to the ATE client via the ATE auxport transfer protocol, rather than via FTP. (This is the default mode for ATSD, where FTP is typically not available but it may be set explicitly for UNIX applications. When txc'docfmt'dst is a buffer (i.e. TXFF_FILE flag is not specified), then TXFF_RAWBUF may be set in the txc'docfmt'dst field to cause the return buffer to be sent directly (via the stdin channel) rather than via FTP. In both cases, the TXFF_RAWBUF method is faster, provided the amount of text is less than about 4K. (FTP starts out slower due to the need to establish a new connection, but eventually catches up due to windowing and other flow maximization techniques.) Note that the TXFF_RAWBUF bit should only be used in the txc'docfmt'dst field for files that cannot contain binary data (such as embedded objects).
TXFF_XFER | &h0800 | May be specified in the source format field (txc'docfmt'src) to force XTEXT to interpret the source file as being local to the server and requiring transfer to the client. Without this flag, the PC filespecs (containing backslashes) will be assumed to be visible directly to the client and thus not requiring file transfer. (This mainly a concern with ATSD where both the server and client environments are Windows.)
Definition file: XTEXT.DEF


txc'docfmt'dst

This field is analogous to txc'docfmt'src except applies to the interpretation of the dst parameter. See the txc'docfmt'src table for possible values. Note that the input and output options are generally independent (see Comments, below). For example, you can input from a file in plain text format and output to a string variable in RTF format. You can also specify the same variable and options for both input and output in order to store the output on top of the input.

Comments

There are a couple of exceptions to the above relating to HTML. First, when src is a web-based HTML document, or a form, then the destination storage medium must be TXFF_STRING. In other words, when using XTEXT as a web browser, there is no real destination. You would normally have the TXF_READONLY flag set in this case anyway, so the question of output may be moot but TXFF_STRING avoids any ambiguity of intent.

The second exception is that when editing files in HTML format (either with the intent of creating actual web documents or simply as simpler alternative to RTF to allow basic formatting such as bold), you must select the TXF_PRINTVIEW option in flags in order to enable the txc'hflags# options that pertain to the output format options. In contrast, the TXF_FITVIEW option is intended for HTML browsing and only saves using a standard set of output options, ignoring most of the txc'hflags# bits.


txc'outbytes

This field indicates the total number of "user bytes" in the updated control available to be output, or that were already output. By "user bytes", we are referring to characters actually typed by the user, not to any formatting bytes that would be inserted automatically into the output stream based on the output format specified in txc'docfmt'dst.

In the case of plain text output (TXFF_TEXT or TXFF_TEXT_LINES), there are no extraneous formatting bytes needed, so the value can be used to determine the total size. This can be useful when outputting to a string variable using the TXF_DEFERSAVE option, as it would tell you how big of a variable you would need to retrieve the entire contents. But for output formats that include extraneous formatting bytes, such as RTF and HTML, the actual size required will be substantially larger than the value returned in txc'outbytes. You could, however, use a dynamic (self-expanding) string variable to receive the output, and then determine the actual length using the len() function.


txc'outlines

This field is updated on exit to indicate the number of logical lines of text as displayed. Note since in most cases, lines are soft-wrapped in a manner dependent on several variable factors, so the number of lines might easily change. It is probably most useful in conjunction with the txc'wrapwidth field, since in that case it might be used to estimate the number of storage records needed (assuming each logical line was saved in a single storage record).


txc'saveoffset

This field is primarily useful when outputting to a string variable that is not large enough to hold the entire text. In that case, it indicates the starting position of the next byte to be saved, relative to the beginning of the text buffer. For example, if the dst parameter was 5000 bytes long and the total size of the output text was 13000 bytes, then in the first save operation, 5000 bytes would be output to dst and txc'saveoffset would be set to 5000. On the next call (with opcode set to TXOP_SAVE), the save operation would continue from that position, and again output until dst was full (presumably another 5000 bytes). At this point, txc'saveoffset would be set to 10000. On the next call with opcode TXOP_SAVE, the save would start from that offset and continue to the end of the file (13000) in this case.

In another scenario, let's say that after receiving the first 5000 bytes, you decide that you would rather get it all in a single 13000 byte butter. In that case you could allocate a 13000 byte string to receive the entire block of text, and set txc'saveoffset back to -1 so that the next save operation would re-start from the beginning. (The -1 tells the control to use the intermediate storage from the previous save operation.)


txc'fontface

This can optionally be set to any of the standard Windows font typeface names, e.g. "Courier New", "Arial", "Times Roman", etc. If not set, then the standard Windows dialog font will be used.

To specify a fixed pitch font, you should specify one of the typeface names that is known to be fixed pitch (e.g. Lucida Console or Courier New). If you specify any font, you must also specify a size.


txc'fontsize

Unlike most other GUI controls which express the font size as a percentage of the "standard" size, the XTEXT control, being more like a "real" text editor or word processor, prefers to use printer point size units (e.g., 12 for 12 point type.) You can also specify the font size in twips, in which case set txc'fontsize to negative the desired number of twips in height.

If you specify a non-blank font (in txc'fontface), you must also specify a non-zero size (or else you will get microscopic text). Note that regardless of the specified font size, the user can increase or decrease the display magnification using the Ctrl+Plus and Ctrl+Minus keys, or using the zoom dropdown on the toolbar.


txc'srchkey

If this field is not blank, an edit operation (opcode TXOP_CREATE or TXOP_REEDIT) will start by searching for the specified string, based on the options set in the txc'sflags parameter. The search starts from the same place that the cursor would ordinarily start (see flags TXF_EOT and TXF_POSCUR and parameters txc'xcol, txc'xrow, txc'xcuroffset).

If the search flag TXSF_EXIT is specified in txc'sflags, then the operation will return immediately. If successful, the exitcode will be 0 and the cursor position parameters (txc'xcol, txc'xrow, txc'xcuroffset) will be set to indicate the location of the first match. If not successful, exitcode will be set to -49 and the cursor position parameters will remain unchanged. To search for additional occurrences of the string, adjust the txc'xcol and/or txc'xrow parameters by 1 (forwards or backwards, depending on the direction of the search) and repeat the operation.

If the search flag TXSF_EXIT is not specified, then the normal editing operation will take place after the search.

The following character sequences can be embedded in the search string to search for special control characters:

Two-char code in txc'srchkey | Matches special char in control
^p | Paragraph marker
^t | Tab character
^m | Manual (hard) page break
^+ | Em dash
^- | En dash
^^ | ^ character


txc'sflags

This field may contain one or more of the following options, affecting the way the search operation works.

Symbol | Value | Description
TXSF_SCROLL | &h0001 | Scroll located text into view
TXSF_CASE | &h0010 | Case sensitive search
TXSF_WORD | &h0020 | Match whole words only
TXSF_BACK | &h0080 | Search backwards
TXSF_EXIT | &h1000 | Exit immediately after search


txc'flagmask

This field controls the interpretation of the following flag fields (txc'flags1, txc'flags2, etc.) These fields provide access to a large number of individual (mostly obscure) options in the text edit control. Each of the bits in both the low byte and high byte of txc'flagmask correspond to one of the txc'flags? fields. (The low bits in each byte, &h01 and &h0100, correspond to txc'flags1, etc.)

If both bits (from the upper byte and lower byte) corresponding to a particular flag field are zero, then the bits in that corresponding txc'flags? field are OR'd into the current flag settings. In other words, if txc'flagmask = &h0000 and txc'flags1 = &h0201, then the flags represented by the bits &h0201 would be activated, in addition to whatever flags are set internally be default. Since it is difficult to understand all of the reasons for the internal defaults, but it may be possible to recognize a particular flag that you'd like to set, this is by far the most likely way to use these fields.

However, the txc'flagmask provides two other ways to interpret the txc'flags? fields. If the bit corresponding to a txc'flags? field in the upper word of txc'flagmask is set, then any bits which are set in that corresponding to txc'flags? field will clear the associated internal flag. This would only be useful in a situation you were able to identify a particular default flag that you wanted to turn off.

The final possibility is where the bit in the upper byte of txc'flagmask is clear, but the bit in the lower byte is set. In that case, the corresponding txc'flags? field is used to set or reset ALL of the associated flags. For example, if txc'flagmask = &h0001 and txc'flags1 = &h0400, then all of the flags represented by txc'flags1 would be cleared, except for the one represented by the eleventh bit (&h0400) would be set. As with the previous case, this mode requires that you understand all of the flags for that flags word, since you will be setting or clearing all of them at once.

Flags | Description
Flags (high byte) | Description
&h0000 | (Additive mode) Enable flags specified by 1's in the txc'flags? fields
Flags (high byte) | Description
&h0001 | Set/clear all flags in the txc'flags1 field
&h0002 | Set/clear all flags in the txc'flags2 field
&h0003 | Set/clear all flags in the txc'flags3 field
&h0004 | Set/clear all flags in the txc'flags4 field
&h0005 | Set/clear all flags in the txc'flags5 field
&h0006 | Set/clear all flags in the txc'flags6 field
&h0100 | Disable flags specified in the txc'flags1 field
&h0200 | Disable flags specified in the txc'flags2 field
&h0300 | Disable flags specified in the txc'flags3 field
&h0400 | Disable flags specified in the txc'flags4 field
&h0500 | Disable flags specified in the txc'flags5 field
&h0600 | Disable flags specified in the txc'flags6 field


txc'flags1

A set of flags that can be individually set to enable the corresponding options. See txc'flagmask. Note that all of the possible bits correspond to some feature (we only documented those that seemed even remotely interesting); on the other hand, even those that are documented are not necessarily fully implemented in XTEXT.

By default, several of the flags represented by the various txc'flags? words are internally set, so care should be taken to not change the values of existing flags you do not understand. (Set txc'flagmask to 0 to turn on individual flags, or by set the bit(s) in the high byte of txc'flagmask to 1 to turn off individual flags.)

Value | Description
&h00000002 | Show ruler measurements in metric units
&h00000004 | Set the page orientation to that of the default printer. (Applies only when either the TXF_PRINTVIEW or TXF_PAGEVIEW bits are set in flags.)
&h00000020 | Disable the internal accelerator table. (Also see txc'fmapctl and txc'fmapapp.)
&h00000080 | Show caret even in read-only mode
&h00008000 | Automatic vertical scroll bar
&h00100000 | Disable use of printer
&h00200000 | Disable drag/drop for text
&h00400000 | Disable OLE editing
&h02000000 | Show the page break lines even in read-only mode. (See Page Breaks.)
&h80000000 | Swap decimal and comma in dialog boxes


txc'flags2

More flags similar to those in txc'flags1.

Value | Description
&h00000080 | Show section page number on status bar
&h00000100 | Do not change cursor shape as mouse moves over edit window
&h00000200 | Scroll the text window while dragging the vertical scroll bar (smooth scroll)
&h00000400 | Do not auto-repaginate while editing text
&h00000800 | Do not save the original as a backup before saving text to file
&h00002000 | Hide soft page break lines when in TXF_PAGEMODE
&h00004000 | Protect the formatting of protected text
&h00008000 | Do not write hidden text to RTF file
&h00010000 | Do not apply shading to field text (e.g. dates, page numbers)
&h00100000 | Always fully repaint text box
&h02000000 | Do not show cancel print dialog when printing
&h10000000 | Do not adjust cursor when placing it over protected or hidden text
&h20000000 | When cursor is not allowed within protected text, move it to start of protected text rather than after it. (See next flag.)
&h40000000 | Do not allow the cursor in the middle of protected text.


txc'flags3

More flags similar to those in txc'flags1.

Value | Description
&h00000001 | Wrap extra spaces at the end of the line to start of next line
&h00000010 | Display text in gray in read-only mode
&h00001000 | Use older RTF format (for older versions of Word)
&h00040000 | Do not collect undo information
&h00400000 | Scroll one line at a time when up or down arrow pressed
&h10000000 | Read PNG images from RTF files
&h20000000 | Do not adjust text color to contrast with background
&h40000000 | Do not allow text selection with mouse


txc'flags4

More flags similar to those in txc'flags1.

Value | Description
&h00000001 | Count paragraph character as 2 characters (CRLF)
&h00000002 | Do not allow cursor anywhere in protected text
&h00000020 | Smooth scroll
&h00000200 | Save RTF pictures in binary (instead of hex) format
&h00004000 | Disable OLE drop
&h00020000 | Do not update date/time fields. (Does not apply to plain text)
&h20000000 | Paste properties of last paragraph when text pasted in empty paragraph.
&h40000000 | Print WMF (metafile) images as bitmaps


txc'flags5

More flags similar to those in txc'flags1.

Value | Description
&h00000001 | Disable text drop from other applications. (Must be set when control first created.)
&h00000002 | Group undo operations into one undo
&h00000004 | Translate 'exact' row height to minimum row height in RTF input
&h00000010 | Disable text selection using the keyboard
&h00000040 | Ignore embedded objects when display status line number
&h00000800 | Allow caret to stop before and after hidden text
&h00002000 | Show page setup rather than print setup options in printer setup dialog.
&h00004000 | Fully repaginate document on load (no matter how big)
&h00008000 | Save PNG data in RGB format
&h00010000 | Do not show space symbol (when showing marks)
&h00400000 | Save JPG, PNG, GIF images in WMF format
&h01000000 | When applying an indent to a set of marked lines, give them all the same indent (rather than keeping the relative indents).
&h08000000 | Allow for unlimited OLE storage space
&h10000000 | Display old style ruler


txc'flags6

More flags similar to those in txc'flags1.

Value | Description
&h00000008 | Use printer-independent metrics for wrapping and pagination.
&h00000040 | Embed pictures using real pixel size (ignore recommended size)
&h00001000 | Insert dropped pictures as linked rather than embedded
&h80000000 | Generate line break when Enter pressed, and CarriageReturn when Shift+Enter pressed (reverse of normal).


txc'flags7

More flags similar to those in txc'flags1.


txc'flags8

More flags similar to those in txc'flags1.

Symbol | Value | Description
TXF8_SEL_PTR_DLG | &100000000 | Select printer dialog (TXOPF_PRINT)
TXF8_PROTECT_FORM | &h20000000 | Protect form (only input fields can be changed)
TXF8_ESC_SAVE_EXIT | &h40000000 | Force Escape to save any changes and then exit
TXF8_ESC_EXIT_NO_SAVE | &h80000000 | Force Escape to exit without saving changes


txc'fmapctl

This is a 32 bit bitmap in which each bit set to 1 enables the corresponding function key to be sent to the control. For example, &h00000001 enables F1 to be sent to the control and &h00008000 enables F16 to be sent to the control. (The upper 16 bits correspond to Shifted F1 through F16.) The following table indicates how the control would normally interpret the function keys:

Key | Action
F1 | Help
F3 | Save
Shift+F3 | Save As
F4 | Print
Shift+F4 | Printer Setup
F5 | Search
F6 | Replace
F10 | Jump to line number

History

2006 August, A-Shell 4.9.963: XTEXT.SBR now supports an option to make the Save icon on the toolbar act like "Save As" (i.e. display a dialog to allow you to choose a filename and location) rather than just "Save." To active this option, clear bit 3 (corresponding to the Save command, which is equivalent to F3) and set bit 19 (corresponding to the Save-As command, or Shift+F3). For example, if you previously had txc'fmapctl = &h000000FF (i.e. send all the functions corresponding to F1-F8 to the control), you would change this to &h000400EF to force the Save button to act like Save-As. Note that this would not affect the keyboard commands F3 and Shift+F3, which would continue to distinguish between Save and Save-As.


txc'fmapapp

This is a 32 bit bitmap similar to txc'fmapctl except that it specifies which function keys are to be sent to the application. (This requires that the TXF_FKEYS flag be set). Such keys will cause the control to exit with exitcode set to -1 through -16 and -17 through -32 for F1 through F16 and Shift+F1 through Shift+F16 respectively.


txc'toolbarmask

The flags in this bitmap field allow you to remove objects from the toolbar (and only apply if TXF_TOOLBAR is specified in the main flags parameter.

Symbol | Value | Item being Removed
Flags (second row) |  |
TXTB_ROW1 | &h00000001 | Entire first row of toolbar
TXTB_NEW | &h00000002 | File | New button
TXTB_OPEN | &h00000004 | File | Open button
TXTB_SAVE | &h00000008 | File | Save button
TXTB_PRINT | &h00000010 | File | Print button
TXTB_PREVIEW | &h00000020 | File | Preview button
TXTB_CLIPBOARD | &h00000040 | Clipboard buttons (cut, copy, paste)
TXTB_UNDOREDO | &h00000080 | Undo/redo buttons
TXTB_FIND | &h00000100 | Search (binoculars) button
TXTB_DATE | &h00000200 | Insert-date button
TXTB_PAGENUM | &h00000400 | Insert-page # button
TXTB_PAGECOUNT | &h00000800 | Insert-page count button
TXTB_SHOWMARKS | &h00001000 | Show marks (e.g. paragraph) button
TXTB_HELP | &h00002000 | Help button
TXTB_ZOOM | &h00004000 | Zoom button
TXTB_ROW2 | &h00010000 | Entire second row of toolbar
TXTB_STYLE | &h00020000 | Paragraph style dropdown
TXTB_FONTFACE | &h00040000 | Font typeface dropdown
TXTB_POINTSIZE | &h00080000 | Font point size dropdown
TXTB_CHARATTR | &h00100000 | Bold/italics/underline buttons
TXTB_ALIGN | &h00200000 | Alignment buttons
TXTB_NUMLIST | &h00400000 | Numbered list button
TXTB_BULLETS | &h00800000 | Bullet list button
TXTB_INDENT | &h01000000 | Indent buttons
TXTB_SHOW_HIDE | &h80000000 | May be used in conjunction with TXF_RULER, TXF_TOOLBAR and/or TXF_STATUS to automatically remove the ruler, toolbar and status ribbon when the control is in-active, and re-display them when the control is re-activated via TXOP_REEDIT.


txc'fcolor

The lower 3 bytes of this 32 bit field are used to specify a custom foreground text color as a set of RGB values. Te low byte is the R (red) value, the second lowest byte is the G (green) value and the third lowest byte is the B(blue) value. The maximum for each field is 255. When all three are set to 255 (e.g. &h00FFFFFF) you get white; when all are set to 0 (e.g. &h00000000) you get black. However, to distinguish the latter case from the default (which is also &h00000000) you must set one of the bits in the upper byte to a non-zero value. For example, to set the text color to black, you might set txc'fcolor to &h10FFFFFF. (Since the default text color is black, this is not much of an issue, but the concept applies to all of the RGB-style color fields.)


txc'fprotclr

This field is similar to txc'fcolor except it applies only to protected text. Protected text is normally displayed in a slightly lighter shade from the regular text, but if the distinction is not enough for you, you can set it to anything you like with this field. Alternatively you may find that it looks better to set the protected text background color to a light shade of gray (e.g. &h00D8D8D8).


txc'protrows

This field allows you to specify a block of existing lines of text to be protected from change. This is particularly useful in a rigorous transaction environment where your application encourages the use of comments but rightly makes it difficult for anyone to remove previously entered comments. Another possibility is to use this feature as a way of protecting a few header lines of text which instruct the user how text should be entered. If you set txc'protrows to a positive number, it protects that many lines, starting from the top. If you set it to a negative number, it protects all but a certain number of lines at the bottom: -1 protects all lines, -2 protects all but the last line, -3 all but the last two lines, etc.


txc'idname

This field allows you to specify names for the parent and/or XTEXT control. You may use any of the following formats:

TXC'IDNAME = "xtextname"

TXC'IDNAME = "parentname>xtextname"

TXC'IDNAME = ">xtextname"

Note that if the parent control name is specified this way, then it overrides anything in the txc'parentid field (and that field will be updated on return with the numeric control ID matching the specified parentname.)

Note that despite the similar format used by the INFLD V parameter, in this case a name by itself (with no ">") is interpreted as the name of the control rather than the name of the parent control (as in INFLD).


txc'maxbytes

This field allow a maximum number of bytes to be specified for the text memo. Note that the mechanism for determining when the limit is reached is not perfect, and only operates during the processing of normal keystrokes. It does not operate during the paste operation, nor during the memo load, nor during replacement operations. (These loopholes may be closed in a later release.) Also, the field only supports a limit of up to 64K, on the theory that the space in the TXTCTL structure is more valuable than the likelihood of somebody wanting to set a limit of more than 64K. However, if you see a problem with that, please comment back to the developer.


txc'flagmask

This 16 bit bitmap controls how the routine will interpret the txc'flags# fields. Because of the large number of flags, and the fact that some of them default to ON while others default to OFF, it is not practical for applications to have to consider and properly set/reset all of them. Instead, it is typically more convenient to force just a few individual flags ON, or OFF, or to replace a block of flags. These three modes are referred to "addition", "subtraction", and "replacement", respectively. In "addition mode", any bits set in the txc'flags# field will be added to the current or default flags for the control (i.e. forced ON or ENABLED). In "subtraction mode", any bits set in the txc'flags# field will be subtracted from the current settings (i.e. forced OFF or DISABLED). In "replacement mode", all of the flags corresponding to an entire 32 bit txc'flags# field are replaced (i.e. turned ON/OFF) according to the pattern of 1s and 0s in field.

The default mode is addition, meaning that to enable any individual flags, just set the corresponding bits in the txc'flags# fields. (The specified options will be enabled; all the other options corresponding to the 0s in the txc'flags# fields will be left in their current or default state.) To specify subtraction or replacement mode for any of the txc'flags# fields, set the txc'flagmask bitmap to a combination of bit patterns from the following table:

Bit Pattern | Interpretation
&h0001 | Replacement mode for txc'flags1
&h0002 | Replacement mode for txc'flags2
&h0004 | Replacement mode for txc'flags3
&h0008 | Replacement mode for txc'flags4
&h0010 | Replacement mode for txc'flags5
&h0020 | Replacement mode for txc'flags6
&h0040 | Replacement mode for txc'flags7
&h0080 | Replacement mode for txc'flags8
&h0100 | Subtraction mode for txc'flags1
&h0200 | Subtraction mode for txc'flags2
&h0400 | Subtraction mode for txc'flags3
&h0800 | Subtraction mode for txc'flags4
&h1000 | Subtraction mode for txc'flags5
&h2000 | Subtraction mode for txc'flags6
&h4000 | Subtraction mode for txc'flags7
&h8000 | Subtraction mode for txc'flags8

Example

txc'flagmask = &h0410 ! subtraction for txc'flags3, replacement for txc'flags5

txc'flags1 = TXF1_METRIC or TXF1_HIDE_PAGE_BREAK ! set these flags (addition)

txc'flags3 = TXF3_EMBEDDED_TABLES or TXF3_NO_SCROLL ! clear these flags (subtraction)

txc'flags5 = TXF5_GROUP_UNDO or TXF5_NO_KB_SEL ! set these and clear all other TXF5_xxx flags (replacement)


fmtdef

You may specify the target printer (using standard Windows printer name syntax) by adding the following clause to the fmtdef parameter:

Printer=name

where name is the descriptive name of the printer, as it appears in the print manager control panel applet. If there are other clauses in the fmtdef parameter, terminate this one with a "~" or ",". If no printer is specified, the current default printer is used.


Modeless Operation

In addition to the additional programming required (multiple XCALL XTEXT operations using different opcode values), these present the problem of how to respond to the user clicking on the edit control when some other input field has the input focus (i.e. when not inside of an XCALL XTEXT operation). You can prevent this problem by disabling the control on exit (see flags TXF_DISABLE) or you can define a keyboard click-to-enable string in txc'kbdstr, which would be received by whatever input routine had the focus at the time the user clicked on the text control. This would allow your application logic to take appropriate action, presumably including executing a new XCALL XTEXT operation. If you neither disable the text control when inactive, nor define a click-to-enable string in txc'kbdstr, then the user may have the impression of operating on the control, but your program will not be aware of it. (That might be acceptable though, since the application could retrieve the current text at a later time by executing XCALL XTEXT with opcode set to TXOP_SAVE.)

The recommended format for txc'kbdstr, is "VK_xF###" where ### is the absolute value of the desired negative exitcode value to be returned when the user clicks on the text control while another input control has the focus (i.e. INFLD, XTREE, AUI_EVENTWAIT, etc.) For example, "VK_xF901" would generate exitcode -901.


Multiple XTEXT Controls

You may have multiple XTEXT controls defined and displayed at once. To do so, you must specify a unique control number (0=first, 1=second, etc.) in the txc'ctlno parameter, and use the flags TXF_MODELESS option (so that you can exit the first control without destroying it).

See the note next to txc'ctlno for information on auto-assigning a control number.


Controls in Container Windows

You may place a XTEXT control within a container window such as a modal dialog box or a tab control by setting the txc'parentid parameter to the parent control ID.


Editing in a Standalone Window

You may also invoke the text editor in what appears to be a standalone window, almost as if it was an independent application (with its own title bar and menu). To do this, set the TXF_POPUP bit in the flags parameter (and set the txc'parentid field to a suitable parent control.) As with other control/window arrangements, set the coordinates relative to the grid system of parent window, although once the control is displayed, the user will be able to move and resize it, almost as if it were independent of the application (except that it will still act like a modal dialog.)

Note that as of build 953.3 you can specify the coordinates in absolute pixels by setting the srow, scol, erow and ecol parameters to the negative of the desired pixel coordinates. In that case, the txc'parentid wo not affect the positioning, but it will still affect the "z-order" and the ownership of the popup XTEXT window. (For example, if you specify the parent ID of the current dialog, then the XTEXT popup window will be automatically deleted when the dialog is deleted, whereas if you set txc'parentid to 0, the popup XTEXT window will not be affected by deletion of the current dialog.)


Search / Replace

A search operation may be initiated either by the application (see txc'srchkey) or by the user by clicking on the search icon (binoculars) on the toolbar (see TXF_TOOLBAR and txc'toolbarmask) or by hitting F5 (assuming that txc'fmapctl has been set to forward F5 to the control. The operator can continue searching for additional matches by hitting Ctrl+F (search forwards) or Ctrl+Shift+F (search backwards)..

Currently replace operations can only be initiated by the user, by hitting f6 (again, assuming that that txc'fmapctl has been set to forward F6 to the control).


Page Breaks

Hard page breaks are represented by ASCII 12 characters (chr$(12) or Ctrl+L). Depending on the text editing software (e.g. VUE, EZTYP, WORD, NOTEPAD, XTEXT, etc.) these hard page breaks may display in different ways, from a cryptic "garbage character" (often appearing as a small box) to a row of ^^^^ to a graphic line with the words "Page Break" in the middle. XTEXT will normally use the latter approach, except for two situations:

• If the ASCII 12 character is not on a line by itself, it will appear as a small rectangular symbol rather than a formal ("pretty") page break unless you set the TXF_WRAP bit in the flags parameter. If you do not really want any lines to be automatically wrapped, then you can set the txc'wrapwidth field to a sufficiently large number, say 500, so that you do not get any unwanted line wraps. Note that when you specify a non-zero txc'wrapwidth value, it does not make sense to specify the TXC_FITVIEW or TXC_PRINTVIEW flags.

• If you set the TXC_READONLY flag, ASCII 12 characters will appear as a small rectangular symbol rather than a "pretty" page break, unless you set the &h02000000 flag in the txc'flags1 parameter. (You might just want to make that a default setting.)


Trapping Toolbar Commands

Most of the toolbar commands perform editing operations (like the clipboard operations, undo, redo, etc.) that are best handled internally by the XTEXT control without bother the application. But the following five toolbar commands involve I/O operations which the application might want to intercept and handle in a custom manner:

Toolbar Command | Fkey Equivalent
Help | F1
Open | F2 *
Save | F3
Print | F4
Search | F5

* F2 by itself does not invoke the Open command, but clicking on the Open toolbar icon is handled (for the purpose of intercepting the command and returning an exitcode) as equivalent to F2. The other F keys (F1, F3, F4, F5, F6) invoke the corresponding action regardless of whether the toolbar icon is present.

To intercept any of the above toolbar commands and return them to the application as exitcodes, set the TXF_FKEY flag, and also set the corresponding bits in the txc'fmapapp field and clear them from the txc'fmapctl field. For example, if display the Save icon on the toolbar and want to trap it in your application (rather than letting the control handle the command itself), then you would set &h0004 (tgurd bit, corresponding to F3) in txc'fmapapp and clear the same bit from txc'fmapctl. The user's click on the icon would then generate an exitcode -3.


XTEXT as a Report Viewer

Here are some suggestions and things to consider when using XTEXT as a report viewer:

• Since most reports use fixed-pitch type, you will probably want to specify a fixed pitch font (e.g. Lucida Console or Courier New) in the txc'fontface field. Note that when specifying a font face name, you must also set the txc'fontsize to something reasonable (like 8).

• Since there is no equivalent to the 80/132 column display modes of EZTYP, you will have to rely on the horizontal scroll bar (TXF_HSCROLL).

• Since you probably do not want to allow modification of the report, set the TXF_READONLY and TXF_DEFERSAVE flags.

• See Page Breaks for information on making sure the hard page breaks display properly.

• There is currently no equivalent of the EZTYP "goto page" function, but F10 pops up a dialog allowing you to go to a specified line number. If the report has printed page numbers, you can also use the search function (on the toolbar or F5) search for a page number.

• If you want the viewer to occupy the entire screen, set the coordinates to something like -1,-1,-2000,-2000. This would correspond to pixel coordinates of (1,1) for the upper left corner and (2000,2000) for the lower right corner, but A-Shell will shift and/or trim the size of any popup window (you need the TXF_POPUP flag) to fit the screen. But, in that case, you had better not use the TXF_MODELESS option, or else the XTEXT control will obscure the rest of the app and not give you any easy way to get back to it.

• To achieve similar functionality to the EZTYP command line, consider wrapping the XTEXT control in a dialog which contains buttons, and perhaps even a command line, along the bottom of the dialog. For example, to implement a printing capability similar to EZTYP's, you could trap the printer toolbar icon (or F4; see Trapping Toolbar Commands) and then prompt the user for printing parameters such as starting/ending page, printer, etc. If you had created an EZPRTX.SBX to customize EZTYP printing, you could reuse that logic by calling the subroutine directly from your application.


Copy and Paste

Updated May 2011

XTEXT shares the clipboard with A-Shell (and the rest of Windows), allowing you to easily cut/copy/paste between it and other applications. The user can access the clipboard operations by any of the following methods, all of which are fairly standard among Windows applications:

• Keyboard commands: Ctrl+X (cut), Ctrl+C (copy), Ctrl+V (paste)

• Toolbar commands: See TXF_TOOLBAR, and txc'toolbarmask for details on displaying the toolbar and selecting which toolbar icons appear.

• Context (right-click) menu: Right-clicking within the area of the XTEXT control will display a pop-up menu (aka "context menu") containing options for the three clipboard commands. By default, the menu uses the words "Cut", "Copy" and "Paste", but you can customize them (either to confuse your users or for non-English environments) by adding the following items to the SYSMSG.xxx file (where xxx is the extension for the current language definition, as defined by the LANGUAGE statement in the miame.ini):

004,001,Cut

004,002,Copy

004,003,Paste

• In addition to pasting text, XTEXT will also paste clipboard images if the destination format (txc'docfmt'dst) supports it. Note however, that in some configurations, the TXF_WRAP flag may be required.

Beginning in A-Shell 5.1.1217, bitmaps are recognized as paste-able in addition to text.


Browser Mode

XTEXT may be used as a very simple web browser, by specifying the TXFF_HTML flag in the txc'docfmt'src field and setting the TXF_READONLY flag. The usual source type options apply (TXFF_STRING and TXFF_FILE), except that in the TXFF_FILE case, the filespec can also be a web-based URL. For web-based HTML documents and forms, the destination (txc'docfmt'dst) must be a string/buffer.

In the case of a form, if the user clicks the SUBMIT button, XTEXT returns with exitcode=30 and the action, method, and data fields are output to the dst parameter in the following format:

&url=<form url or filespec>&action=actionstr&method=

methstr&name1=value1&...&nameN=valueN

The fields actionstr, methstr and nameN are as defined in the form itself. (methstr will be GET or POST.) The valueN fields return the data entered by the user in the form. (Checkbox and radio button fields return 0 or 1 to indicate empty or checked.) If a value contains the character "&", the entire value string will be quoted. So you may want to use STRTOK to simplify parsing the returned string.

Notes

• Requires that the module HTS13.DLL be present in the bin directory, and that you use TXFF_HTML with TXFF_FILE in the TXC'DOCFMT'SRC or TXT'DOCFMT'DST fields. Only file mode is supported.

• For browser mode, you must set TXF_READONLY. Otherwise it will be in editing mode, similar to the existing RTF editing mode.

• You must use TXF_FITVIEW for all but the simplest files.

• You may specify a web URL in the TXC'DOCFMT'SRC field, such as "http://www.microsabio.com". However, you may not output to a web address. (We recommend using .HTM as the extension for local HTML files.)

• You can use the HTML format as simpler version of RTF with the goal of supporting just a few text attributes. To minimize the size of the outputted HTML file, you may want to set the TXC'HFLAGMASK and TXC'HFLAGS1 as follows:

TXC'HFLAGMASK = &h0001 ! Set/clear all flags from HFLAGS1

TXC'HFLAGS1 = &78006 ! strip out head, body, font, style tags

• Although browser mode the TXFF_HTML flag were introduced in A-Shell 1112 of May 2008, the function was not fully operational until A-Shell 5.1.1191.3 of August 2010.


ATE Issues

When XTEXT is used with ATE to edit files originating on a remote server (whether UNIX or Windows), the source file or source text must be transferred from the remote server to the client PC in order for XTEXT to operate on it. Although this is handled automatically by XTEXT.SBR, here are some possible technical obstacles that could interfere with the desired result:

• The server must have an FTP server that the client can access (no firewall or other security restrictions). Note that you can also configure ATE to use SFTP (via the SSH service on port 22 if FTP is not available or if you want better security).

• The ATE client must be configured with a valid FTP login and password. Otherwise XTEXT will have to prompt the user, which wo not be very efficient.

• The FTP (or SFTP server) must use the same root directory as A-Shell on the server is using (because this is how XTEXT constructs the filespecs in the generated FTP commands).

• If the source is a file, XTEXT will look at the first line to see what kind of terminators it uses, and then select the appropriate file transfer mode (binary vs. ASCII) so that the copy seen by the control has the standard Windows CRLF terminators. One way this could fail is if, in order to close a security loophole in some FTP servers, the FTP ASCII transfer mode was disabled. In that case, if the source file had LF terminators, the control will display graphic boxes where there should be line breaks. Workarounds for that problem would include reconfiguring the FTP server to allow ASCII transfers, changing the file terminators on the UNIX side from LF to CRLF (see OPTIONS=CRNL in the miame.ini), and switching from FTP to SFTP. Note that in the case of the vsFTP server (common on some Linux platforms), the relevant configuration setting is "ascii_download_available" in the /etc/vsftpd.conf file.

• If the source is a string, then FTP is not used and the line terminators will not be adjusted, so the application string must include CRLF terminators.

• When the updated file or string is transferred back to the server, XTEXT will attempt to give it the appropriate line terminators based on the standard terminators for the server OS and whether the OPTIONS=CRNL switch in the miame.ini was specified.

Also see the subtopic listed in the table of contents.

Subtopics

Non-FTP Channel Text Return


Non-FTP Channel Text Return

Beginning with A-Shell build 995 of 23 Sep 07, XTEXT supports an alternate method of returning updated text to the server, which does not require FTP. This method works via the keyboard channel and only works when the destination is a string buffer—i.e. TXFF_FILE flag is NOT set in the txc'docfmt'dst field.

The primary motivation for this non-FTP mechanism is to deal with servers that do not have FTP support configured, or have it configured in a mode that prevents access to the directories where A-Shell lives on the server; this is quite common with Windows servers. It is also somewhat more efficient when editing small files, which would be consistent with the use of string buffer mode rather than file mode.

This requires a current (later than 995) of ASHW32 on both sides.

This mode is automatic with Windows servers (ATS), but you can also force it for UNIX servers by setting the new flag TXFF_RAWBUF in the txc'docfmt'dst field.


Spell Checking

Spell checking requires the following modules be in the BIN directory:

SPELL32.DLL

DICT25.APP (application dictionary)

DICT25.D (main dictionary data)

DICT25.I (main dictionary index)

DICT25.S (small/core dictionary)

DICT25.U (user dictionary - optional, created as words added)

To activate spell checking, set TXC'FLAGS4 = &h100 before calling XTEXT.

Misspelled words will be underlined in red; right-clicking on them will provide a list of similar words and an option to either add the word or ignore it. Added words go into the DICT25.U file, which will be created if it doesn't already exist.


Keyboard Commands

Added June 2008

The following table shows the various miscellaneous keyboard commands that may be used in conjunction with XTEXT.

Keystroke | Operation | Notes
F1 | Help | See txc'fmapctl.
F2 | Open
F3 | Save
Shift+F3 | Save As
F4 | Print
Shift+F4 | Printer Setup
F5 | Search
F6 | Replace
F10 | Jump to line number
Alt+F10* | Display font selection dialog
Ctrl+B* | Bold | Applies only if text is in RTF mode.
Ctrl+U* | Underline
Ctrl+D* | Double underline
Ctrl+I* | Italics


Tables

Added May 2011

XTEXT supports tables. Note the following prerequisites and related factors:

• The destination format must support them. (Each cell will appear as a separate paragraph if stored in plain text format.)

• You will need to enable the menu (see the TXF_MENU flags bit) in order to have access to the Table > Insert option in order to create a table. There is no keyboard shortcut.

• TXF_WRAP (see flags) is required.

• At least one of TXF_PRINTVIEW, TXF_PAGEMODE or TXF_FITVIEW is also required. Note that TXF_PRINTVIEW by itself will display the table "folded" into a single column for editing purposes, so adding one of the other bits is recommended.


XTEXT Updates

February 2013, A-Shell 6.1.1338

XTEXT enhancement: Automatically add "Paste Special" to the context menu when complex clipboard formats are available. Depending on the formats, the menu option will open a submenu with more specific paste options, such as picture, spreadsheet, etc. To customize the wording of the menu option, add or modify the 004,011 message in the SYSMSG.xxx file. All SYSMSG.xxx included in the release package have been updated with rough translations. Note that if you don't want this capability, you can disable it by setting the TXMF1_EDIT_PASTESP flag in the TXC'MENUMASK1 field.

Feburary 2011, A-Shell 5.1.1207

XTEXT update: Since 5.1.1204, A-Shell has nominally supported TER15/HTS10 as well as TER18/HTS13, but experience has revealed problems with trying to support both versions in the same A-Shell executable. One symptom was that the //XTEXT GDI directive wasn't working with TER18, but did work with TER15. So as of this release, only TER18.DLL and HTS13.DLL are supported if using XTEXT.

On the plus side, there is a new feature which might possibly be useful (besides the hundreds of new features that we'll probably never use, and the hundreds of bug fixes that we may never appreciate): the ability to read (but not write) Word docx files. A new TXFF_DOCX symbol (7) has been defined in XTEXT.DEF, although for input (txc'docfmt'src), any value will work (other than TXFF_HTML), since the docx internal format is easily recognized.

There is another new DLL, TXML2.DLL, which in conjunction with the Windows DLL MSXML# (# = 2+), is required for the docx import feature.


XTREE

Updated May 2014

xcall XTREE, Srow, Scol, Answer, Array, Itemcount, Coldef, Exitcode {Erow, Ecol, Flags, File, Mmoclr {,Xtrctl, Filidx, Xinfo}}

XTREE.SBR is a full-fledged implementation of a Windows "tree" control, supporting multiple columns and multiple levels of rows. The name "tree" comes from the ability to create a branching hierarchy of items, which at each level can be collapsed and expanded. Windows Explorer, for example, is essentially a tree control.

For examples of the results produced by XTREE, and to get an idea of how XTREE has been used by various developers and for different purposes, see the online MicroSabio gallery of XTREE images.

For information on the differences between PCKLST and XTREE, and how PCKLST/XTREE handles text versus GUI issues, see the note on those subjects in XTREE Miscellaneous Notes.

Subtopics

XTREE Inputs and Outputs

XTREE Parameters

XTREE Techniques

XTREE Sample Programs

XTREE Miscellaneous Notes


XTREE Inputs and Outputs

XTREE offers a choice of two ways of providing the data for the list:

• Array; this is recommended, as it provides the most flexibility and is required for some of the more advanced features

• Sequential file; most convenient for simpler configurations. Both fixed width and CSV formats are supported.

XTREE supports three types of output:

• A selected "item" (aka "row" or "record"). This is referred to as "single-selection mode."

• An array of selected items ("multiple-selection mode").

• An array of updated cell values (either checkbox values or text strings). This only applies when the data contains editable cells; see flags XTF_EDITABLE, and advanced coldef column formats E, u, U and T.

Not all features support all types of input or output, or there may be differences in the way the parameters are interpreted or mapped. So as you read the documentation, please be alert for qualifications which reference one or more input/output combinations, such as "single-selection array mode" or "multiple-select file mode."

Limits and Capacities

Item | Maximum allowed | Updated in Version...; old value
Trees | 32 | 1134 of Jan 09; 10
Columns | 100, may be editable or not | 1157 of Aug 09; 80
Rows | no limit |
Font definitions | 4 |
List definitions | 26 |
RGB definitions | 52 | 1167 of Nov 09; 26
Combined mask length | 1024 |
Exit characters | 64 |
Length of title, footer in characters | 128 |


XTREE Parameters

Parameters that supply data to the routine are indicated with [in], and those used to get data back from the routine are labeled [out].

Parameter | Type | I/O | Description
Srow, Scol, Erow, Ecol | String | in | Position of display.
Answer |  | in/out | Sets and returns the identity of the selected row(s), and/or in the case of editable cells, supplies and returns updated values.
Array | Array | in | In array mode, specifies an array of strings to be loaded into the list box.
Itemcount | Num | in | Specifies a number of items (i.e. "rows"), with the precise meaning being relative to the opcode:
Coldef | String | in | Defines the column structure.
Exitcode | +/- Num | out | Returns a code indicating how the list was exited; 0 indicates a normal exit via the Enter key, 1 indicates Escape. See the Flags parameter for enabling other exit keys.
Flags | B,4 | in | Used to enable additional exit keys and other options.
File | String | in | Specifies a file to be used for input instead of the array parameter. This is referred to as "file mode."
Mmoclr | Struct | in | Specifies colors for various parts of the pick list.
Xtrctl | Struct | in/out | A collection of extended parameters and options.
Filidx | B,4 | out | Creates an index to the file while it is being loaded into the array.
Xinfo | String | in/out | This optional parameter may be specified to allow XTREE to return additional information.


Srow, Scol, Erow, Ecol

The parameters srow, scol, erow, ecol mark the upper left and lower right corners of the display box, provided that flags contains the option XTF_XYXY. Otherwise, they are interpreted as row, col, strow, endrow as in PCKLST. Note that since this XTREE supports horizontal scrolling and column resizing, the width of the display box is independent of the width of the data. Also note that the coordinates are relative to the main window or dialog, or to the control specified by XTR'PARENTID.

The "ANSWER" topic (following) in XTREE could use some reorganization. In a 10/23/06 email, Jack suggests the following, though Ty is not thrilled with it.

Simple (single selection only)

Array

File

Advanced (editable, multi-sel, etc.)

Multi-Selection

Editable Cells

Drag-and-Drop


Answer

Answer specifies and returns the identity of the selected row(s), and also passes back and forth updates to editable cell data.

In the simplest case (single-selection array mode, no editable cells, no drag/drop), answer is treated as in PCKLST, where it is a single numeric variable of any numeric type and is interpreted as the selected row number (first row is 1), e.g.

MAP1 ANSWER,B,4 ! selected row for single selection

For multiple selection mode using array or file input (but no editable cells or drag/drop) (see flags XTF_MSEL, XTF_EDITABLE, XTF_DRAGDROP), answer must be an unformatted variable mapped as follows:

MAP1 ANSWER

MAP2 ANSARY(x),S,1 ! each item is "0" if not selected, else "1"

! (x) must be at least as large as addcnt

To support both single and multiple selection modes with a single form of the parameter, you can add the following MAP statement for the single selection response:

MAP1 ANS,B,4,@ANSWER ! selected row for single selection

You can still pass the unformatted ANSWER variable (rather than ANS), but XTREE will treat it as if a B,4 variable in single selection mode. In other words, in single selection mode, XTREE assumes that an unformatted answer parameter is overlaid by a four-byte binary.

Note that although the rows may be sorted on the screen, either by the user or by XTREE based on the XTR'COLUMNSORT parameter, this does not affect the order of the original data, to which the row numbers returned in answer remain relative. In other words, if answer=5 on calling XTREE, it will select the fifth row in the source data (array or file), which may or may not appear as the fifth row on the screen, and which may be sorted again by the user to yet another position. Similarly, the answer value(s) returned will not necessarily reflect the position(s) of the selected item(s) as displayed, rather their position in the source data (which remains unaffected by any sorting performed by XTREE). Also note that if answer=0, the default selection will be the first row, except in the case of the append operation, in which case it will be the first row appended. Any other answer values are always interpreted as relative to the combined data (original plus appended).

For more complicated situations (involving some combination of multiple selection, editable cells, and/or drag-and-drop), answer must an array dimensioned at least as large as the number of rows of data in the tree, and whose row elements are formatted into one or more fields which must be precisely mapped according to the following principles:

• If drag-drop allowed, the first field of every row must be a 4 character string which will return the original row number (1-9999).

• If multi-selection allowed, the next field of every row is the one-byte selection flag (as described above).

• If there are editable checkboxes/radiobuttons, then the next N fields will be for each of the editable checkboxes/radiobuttons, according to the relative sequence in which they are defined in the coldef parameter. Note that for each checkbox/radiobutton column that supports individual cell colors, the column width (in the main array and in the answer array) will be 2; otherwise it should be 1. Also note that all checkbox/radiobutton columns are represented in the answer array prior to any other kinds of editable columns, regardless of the order in which the checkboxes/radiobuttons and editable columns were defined.

• Finally, for every editable column, there must be a corresponding field in each row of the answer array, whose size matches the defined size of the column. As with checkboxes and radio buttons, if the editable column supports individual cell colors, the width of the column in the answer array must be expanded by one to make room for the cell color byte at the start of the cell. And as before, the order of these editable columns in the answer layout must match the relative order in which they are defined in coldef (as opposed to the order in which they appear in the raw data).

See Editable Image Cells and Examples.


Examples

Consider a tree with three editable checkbox columns. You would map the answer array as follows:

MAP1 ANSWER

MAP2 ANSARY(x),S,3 ! (x=# rows, 3=number of editable checkbox columns)

Or, perhaps more clearly:

MAP1 ANSWER

MAP2 ANSARY(x) ! (x) must be at least as large as addcnt

MAP3 ANS'CB1,S,1 ! first editable checkbox column

MAP3 ANS'CB2,S,1 ! second editable checkbox column

MAP3 ANS'CB3,S,1 ! third editable checkbox column

The encoding of these arrays is similar to that for multiple-selection mode, i.e. "0" = unchecked, "1" = checked, and " " (blank) causes the cell to be left blank (with no checkbox at all). For three-state checkboxes, "2" specifies the indeterminate state.

If multi-selection is allowed, then the first column of the answer array is reserved for the selection flags. For the example above, the multi-selection version should be mapped as:

MAP1 ANSWER

MAP2 ANSARY(x) ! (x) must be at least as large as addcnt

MAP3 SELECTION,S,1 ! selection flags (must be first)

MAP3 ANS'CB1,S,1 ! first editable checkbox column

MAP3 ANS'CB2,S,1 ! second editable checkbox column

MAP3 ANS'CB3,S,1 ! third editable checkbox column

When editable text or combobox columns (see cformat E and l) are present, the same rule as for checkboxes applies, except that the width of the elements in the answer array must include the total width of all the editable columns. To continue the example above, if, in addition to the three checkbox columns there were also two editable text columns, one a standard edit 12 bytes wide and the other a combobox 25 bytes wide, and both the first checkbox and the first editable cell supported individual cell colors (cformat B), the correct mapping of the answer array would be:

MAP1 ANSWER

MAP2 ANSARY(x) ! (x) must be at least as large as addcnt

MAP3 ANS'CLR1,S,1 ! color byte for first editable checkbox column

MAP3 ANS'CB1,S,1 ! first editable checkbox column

MAP3 ANS'CB2,S,1 ! second editable checkbox column

MAP3 ANS'CB3,S,1 ! third editable checkbox column

MAP3 ANS'CLR2,S,1 ! color byte for first editable text column

MAP3 ANS'TEXT1,S,12 ! first editable text column

MAP3 ANS'TEXT2,S,25 ! second editable text (combobox) column

Regardless of the relative position of the checkboxes (and radiobuttons) vs. the editable text columns in the source array, the checkboxes and radiobuttons must precede the text columns in the answer array, as shown above.

Notes

• Although using a multi-level mapping as shown above is the easiest way to visualize the format of the answer array, you may also map or dynamically allocate a single-dimension array (e.g. DIMX ANSARY(X),S,Y) and pass that array to XTREE by specifying the first element (e.g. xcall XTREE, srow, scol, ANSARY(1), ARRAY(1), addcnt,...), provided that you use substring modifiers or some other method to construct each row of the array according to the rules described above. Better yet, use a Dynamic Array of Structures.

• Note that the order of the columns is relative to the order in which they are defined (in Coldef) and is not affected by the user rearranging their order in the display.

• The answer array can be initialized to nulls or blanks. Whenever the tree is loaded or re-entered, if the answer array is all blank, the editable cells will be loaded purely from the data array. However, if the answer array contains any non-blank / non-null characters, then the answer array data will override the corresponding cells in the data array. Whenever XTREE exits, it will update the answer array cells to reflect the current status (with the exception of the color bytes - see next bullet). The concept is to use the data in the main array to represent the original data; and the data in the answer array to represent the current data. Beware that if, as a result of editing, you manage to clear all of the editable cells such that the entire answer array is blank, then on the next re-entry, the entire tree will be set back to the initial status per the data array. (To prevent this, you'll either need to copy the blank answer array over the data array, or perhaps define a color column and plug in an explicit code for white, just to have a non-blank byte in the answer array, so that it is considered valid rather than uninitialized.)

• On creation of the control, blank individual cell color bytes in the answer array are initialized from the data array, like other answer array fields). On return, they will be set to the current status (in this case, the current RGB color index) of the field, or blank for no (i.e. default) color. Note that to set a cell which currently has an individual cell color back to the default color, set the corresponding byte in the answer array to blank prior to re-entry. (This works as of edit 1210, even with the XTF_NOREDRAW flag set; prior to that, blank was treated as "no change" rather than "no color", and XTF_NOREDRAW stifled color updates.) Note, however, that the default color for the cell in this case may not be the same as the default color for the entire tree; the cell default color may be affected by a column color. To override the column color and force the cell to use the tree's default (typically white) color, use the special RGB color index code "=".

• Individual cells within an editable text column can be marked to ignore by setting the associated field in the answer array to "|" (vertical bar), followed by whatever text you want to display in the cell (if any). See the advanced coldef option RGBignore for an additional note on this, and the sample program XTRA5 for an example. (The description in the 3rd row is marked non-editable by this means.)

• To disable an editable checkbox (T) or radio button (R) cell, add 4 to the numeric code in the answer array byte. For example, while 0 is unchecked/enabled and 1 is checked/enabled, 4 would be unchecked/disabled and 5 would be checked/disabled. See the sample program XTRA6 for an example of this (select the validation option, then as you click on Yes and No radio buttons, the corresponding N/A button will be enabled/disabled.)

• Editable text and editable checkboxes are only supported in array mode (not file mode).


Array

In array mode, specifies an array of strings to be loaded into the list box. The interpretation and parsing of these strings into columns is determined by the coldef parameter. To pass the array to XTREE, you may either specify a specific starting element (e.g. ARRAY(1)) or an unformatted variable under which the array is defined (ARRAYX in the example below). Note that you can use DIMX to dynamically allocate the array (either a simple array or a Dynamic Array of Structures), in which case you have to pass it to XTREE via the starting element.

MAP1 ARRAYX ! unformatted variable

MAP2 ARRAY(50),S,100

Each array element must have at least one trailing null byte. Note that by using the overlay feature, you could support several array layouts with the same XTREE statement, i.e.

MAP1 ARRAYX2,@ARRAYX ! overlay on ARRAYX above

MAP2 ARRAY2(10),S,60 ! array of ten sixty byte strings

MAP1 ARRAYX3,@ARRAYX ! yet another overlay

MAP2 ARRAY3(80),S,8 ! array of eighty 8 byte strings

Any text in an individual cell (in array mode) or line (in file mode) which follows a backslash ("\") will be hidden from view (unless the cformat \ switch is specified).

In single-selection file mode, the array parameter is interpreted as an ordinary string to return the text of the selected items (all columns, but with right-justified columns stripped of trailing blanks.) If the XTF_FILANS flag is set, then array is ignored on entry; otherwise it should contain the text of the item to initially select, as returned from the prior call. In CSV mode (see XTF2_CSV), although the return string will contain all the columns (comma-delimited), on entry only the first column is used for locating the initially selected item. If you need more precision than that, use the XTF_FILANS flag/method.

In multiple-selection file mode, the array parameter is ignored. The selection information is passed via the array of one byte flags in the answer parameter, just as in multiple-selection array mode.

Subtopics

Array Descriptors


Array Descriptors

Modified March 2016; minor edits

XTREE enhancement: array descriptors. Provides an alternate method of specifying the answer and data arrays, using the following structure as defined in SOSLIB:ASHINC:xtree.sdf:

DEFSTRUCT ST_XTRARYDESC ! [136] array descriptor

map2 BASEADDR64 ! [136] address of base of array

map3 BASEADDR'LO,B,4 ! [136] low 32 bits

map3 BASEADDR'HI,B,4 ! [136] hi 32 bits (for 64 bit mode future)

map2 LOADFROM,B,4 ! [136] element # to start loading from (base 1)

map2 FLAGS,B,4 ! [136] misc flags

map2 WIDTH,B,4 ! [136] array width

map2 TOTROWS,B,4 ! [136] total rows in ENTIRE array

ENDSTRUCT

To retrieve the address of the base of the array (and for convenience, the width as well), use XCALL GETADR as follows:

MAP1 xtary'desc,ST_XTRARYDESC

MAP1 xtary(5000),S,99

xcall GETADR, xtary(1), xtary'desc.BASEADDR64, xtary'desc.WIDTH

That would load the BASEADDR64 and WIDTH members of the structure. You can get the total number of elements using the .EXTENT() function:

xtary'desc.TOTROWS = .EXTENT(xtary())

Then just specify the desired starting row with an assignment:

xtary'desc.LOADFROM = 1 ! start loading from 1st element

This descriptor structure can then be used in place of the data or answer array, e.g.:

XCALL XTREE, srow, scol, answer, xtary'desc, itemcount, coldef, ...

Note that you still need to set the ITEMCOUNT parameter to the number of rows to be loaded, just as you normally would. (The TOTROWS member of the descriptor is just there as a safety check against accidentally trying to load more rows than exist. (Either way, XTREE has to trust you on the total size of the array, but if you use the .EXTENT() function as shown above, it should be easy to avoid mistakes there.)

The ST_XTRARYDESC structure definition has been added to ashinc:XTREE.SDF

History

2012 June, A-Shell 6.1.1307: XTREE Array descriptors added to A-Shell.


Itemcount

Updated and reviewed January 2011

This parameter specifies a number of items—i.e. "rows"—with the precise meaning being relative to the opcode, as shown in the following table. itemcount may be specified by any numeric data type.

XTR'OPCODE | itemcount interpretation
XTROP_CREATE | For array mode, set to # of items to load from the data array parameter. For file mode, set to 0 to load the entire file.
XTROP_REPLACE | Same as for XTROP_CREATE. If less than the number of items already in the tree, the excess items will be deleted from the tree.
XTROP_APPEND | # of items to append (from the data array parameter to the end of the existing items in the tree)
XTROP_DELETE | Ignored
XTROP_RESELECT | # of items currently in the tree (see Comments)
XTROP_DELSEL | Same as for XTROP_RESELECT
XTROP_PRINT | If tree doesn't already exist, set to # of items to load from the data array. Else set as for XTROP_RESELECT.

Comments

• In PCKLST, itemcount specified the maximum number of items in the input array, and was ignored for file mode. XTREE obeys it for both array and file mode, but interprets 0 as meaning to load the entire file.

• Note that when loading an array starting from some position other than the first element, itemcount must be adjusted so that it does not cause the input operation to run past the end of the array.

• For operations that don't involve adding data but may involve processing an answer array (such as XTROP_RESELECT and XTROP_DELSEL), itemcount is mainly needed in order to identify the number of elements in the answer array when the answer parameter is specified as an array element (rather than as an unformatted variable overlaying the entire array).

Note: this parameter (itemcount) was previously known as addcnt. The documentation was changed in January 2011 to make its meaning clearer.


Coldef

This input parameter, "column definition", defines the column configuration layout and other related details of the tree configuration, according to one of three syntax variations:

• Traditional Coldef Syntax

• Simple Multi-Column Coldef Syntax

• Advanced Coldef syntax

Advanced Coldef Syntax

To use the Advanced coldef syntax, you must specify the XTF_COLDFX option in flags, and then provide a coldef string in the following syntax:

cpos~ cwidth~ ctitle~ cformat {~option1 = value1{ ~option2 = value2...} ~~cpos~ cwidth...~~

This syntax specification consists of a series of column definitions, one per column, delimited by a pair of tildes (~~). Each column definition begins with four mandatory parameters (cpos, cwidth, ctitle and cformat), each delimited by a single tilde, followed by zero or more optional Advanced Coldef Options using the form (optionN=valueN). This is admittedly cryptic, but has the virtues of being flexible, easily extensible, compact, and easy to map.

Parameter | Description
Cpos, Cwidth | Define the starting position and width of the column.
Ctitle | Sets title.
Cformat | Specifies formatting and sorting of column contents.
<more> | Advanced Coldef Options.

See Also

• File Mode Coldef Extensions

• Advanced Syntax Example for tips on specifying column attributes as well as widths


Cpos, Cwidth

These parameters define the starting position and width of the column relative to the input source (whether array or file). The first position is 1. If you are defining the columns consecutively (in the same order as the input, then you can specify 0 for cpos in which case it will assume that the column starts immediately after the end of the previous column. For comma-delimited file input, set cwidth to 0 and cpos to the field number.

For CSV input, cpos and cwidth just need to be greater than zero; see XTF2_CSV for additional details.

You may set both cpos and cwidth to 0 to define a pseudo-column, which does not count in the column numbering scheme, nor take up any display space in the control, but may instead be used to define advanced options that are not column specific or which may need to be defined in order to be referenced later. This may be referred to elsewhere as Pseudo Column Zero." See the column options PopupMenu, HdrFont, HdrScale, Font, RGBfg and Scale for examples.

Note that although the ctitle and cformat parameters are ignored for the pseudo column zero, they must contain something because two adjacent tildes mark the end of the column definition. By convention, specify a title of "X" and a format code of "H" (hidden), e.g. coldef = "0~0~X~H~..."

See Also

• Constant Data Column


Ctitle

This parameter may be a text string of any length to display as the column title. Note that the initial column display width is determined based on the largest string in either the title or any of the data items for that column. If you do not need a title for a particular column, set it to a blank (" "), otherwise you will end up with two adjacent ~ delimiters which will confuse the parser. You can embed line breaks in the header for a column using CR+LF (i.e. chr(13)+chr(10)).

You may embed a tilde in the ctitle string (so as to appear in the column heading when the control is displayed) by replacing it with the HTML-inspired encoding "%7e."

History

A-Shell 5.1.1107 of 12 April 08: New XTREE option to override the alignment of the column headers. Normally the column header text is aligned the same way as the data in the column is (i.e. based on the last cformat field of the coldef parameter). You can now override this by starting the column header text with one of the three alignment characters: > (right), < (left), or | (center) followed by a space. For example:

COLDEF="1~20~> Right Title~<S~~" ! text left aligned, header right

Without the space in the 2nd position of the title, the < character would have simply been treated as the start of the title text.


Cformat

The cformat parameter is made up of one or more of the following characters, which are used to determine how the column should be justified and sorted. Note that they do not cause the data in the column to be re-formatted. For example, if a column contains dates, it is up to the calling program to preformat them appropriately to match the cformat specification. (The only purpose of defining such a column as a date is to allow sorting to work properly.) The most generic and common type would be S (String).

Switch | Meaning
! | Preserve foreground color.
@ | List hierarchy.
# | Numeric data, allows 0 - 9. Use "." and "-" to allow decimal points and minus signs.
\ | Literal backslash.
. | (Decimal point) Use with # to allow numbers with decimal points. See Numeric data.
+ | Added to T (Editable checkbox) extends the checkbox functionality.
++ | Added to T (Editable checkbox) further extends the checkbox functionality.
- | (Minus sign) Use with # to allow numbers with minus signs. Negative numbers are automatically displayed in red. See Numeric data.
] | May be added to any column in a file-mode tree to force trailing blanks to be stripped before loading the cell. (This is automatic in array mode, but in file-mode, the blanks may be needed to preserve the interpretation of the returned selection string.)
= | Expand/Collapse State.
1, 8 | Character Set allows you to specify ANSI/Latin1 or UTF8 at the column level.
3 | 3 state version of checkbox. When used in conjunction with either T or t allows the checkbox to have 3 states (0=unchecked, 1=checked, 2=indeterminate).
A | ASCII Sort.
B | Background cell color.
b | Background row color.
C | Row color.
c | Row color option
D | Standard Date Format.
d | Superceded by expanded capability of code D; retained only for backward compatibility. Date in dd-mon-yr format.
E | Column contains editable text.
f | Font definition column.
H | Hidden column.
h | Indicates a column with times in it. This acts like a string column except for sorting purposes, where any time format supported by IDTIM will be recognized and sorted accordingly.
I | (Capital i) Image column.
K | Keep column position (i.e. do not allow it to be reordered by the user). Needed (as an override) only when flags XTF_REORD set
L | Lock column—i.e., do not allow it to be resized by the user or by XTREE itself. Must be accompanied by Dspwid or Dspmin or else the column will become hidden.
l | (Lower case el). Combo Box. Previously called "list," hence the "l".
ll | (Lower case double el) Use in place of "l" for list substitution in a non-editable column or tree.
M | Allow embedded CRLFs.
m | Used with E to specify a multi-line edit, while retaining single-line display. For both multi-line edit and display, use M with E.
n | Causes empty cells to always sort to the bottom, regardless of whether sorting up or down. May be used with any column type. Added in build 961 of 17 July 06.
O | (Upper case "O") Indicates that this column is allowed to overflow into the next column (provided the next column contains the "o" option and the cell is empty.)
o | (Lower case "o") Indicates that an overflowing previous column may overwrite this column, provided the cell is empty. This setting is not just automatic based on the prior column, because of the possibility of the user reordering the columns at runtime. Note also that this could affect the layout of the returned item in the array parameter; so if it is critical to you that all spaces be preserved in that line, don't use this code.
P | The First Position Reserved option may be used with editable cells to indicate that the first position is reserved for either a space (editable) or a "|" (not editable).
R | Editable radio button.
r | Non-editable radio button. Just like t (which see for details about the column data format) except for the appearance (a circle with a dot in it rather than a square with a checkmark or "tick").
S | String data (left justified by default).
s | Defines the column as being capable of referencing the List. Similar in concept to B (Background cell color) in that it reserves the first character of each cell in the column for the index letters that associate the cell with one of the predefined lists.
ss | Use in place of "s" for list substitution using a shared list in a non-editable column or tree.
T | Editable checkbox. Also see + above.
t | Non-editable checkbox.
tt | Acts like "t" , but instead of always displaying in dim intensity, instead uses the same formula based on the value of the cell as with editable checkboxes. In other words, by default, "tt" checkboxes display in normal intensity; to force individual checkboxes to display as dim, add +4 to the cell value.
U | Application-editable only.
u | Read-only editable.
uu | Works like "u" but displays only a frame around the cell rather than overlaying the cell with an edit or combo control. This is just an aesthetic variation. Note that "uu" automatically exits on Enter, rather than acting like Tab, as it does in most other cell navigation situations. The theory here is that uu is mainly intended for people who prefer the keyboard to the mouse, for whom Enter would be the most natural way to "select" (i.e. exit from) the current cell.
W | Auto-wrap columnar data onto multiple lines. See note about XTR'ITEMLINES above, and Comments in Allow embedded CRLFs. Sample image here.
X | Conditional validation.
x | Unconditional validation.
< | Left justify column (default).
| | Center justify column. This applies during editing, as well as for display.
> | Right justify column. Note that in file mode, this causes the trailing blanks for this column to be stripped, which affects the return data. See the flags option XTF_FILANS. This applies during editing, as well as for display.
^ | Causes sort to be case insensitive. Note that whether case sensitive or not, the collating sequence is based on the Windows locale and not the LDF. Added in build 961 of 17 July 06.
 | (blank) No Strip.
_ | (underscore) May be used with editable columns to cause the edit cell to shrink to fit only the number of allowed characters (so as to not give the user an initial false impression of the number of allowed characters). This will probably only be reasonable when a fixed pitch font is used.


Character Set

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Character Set

Added November 2013

cformat switch: 1, 8

Two cformat codes allow you to override the default character set at the column level:

• "1" interprets the column data as ANSI/Latin1

• "8" interprets the column data as UTF8

The overall default character set for the tree is ANSI/Latin1, unless the XTF2_UTF8 flag is set, in which case it is UTF8.

Note: the entire coldef string is interpreted according to the default character set for the tree, so you cannot mix UTF8 and Latin1-encoded titles even though the corresponding columns are individually set with "1" or "8".

Two new sample programs, XUTF8B and XUTF8C illustrate both cases of mixed UTF8 and Latin1 columns.


ASCII Sort

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

ASCII Sort

Added April 2012

cformat switch: A

This is just like cformat code S (String) except that it forces XTEE to use the standard ASCII sort instead of the "natural" sort. The A may be added to the S or used in place of it. Note that the LDF collating sequence applies, regardless of the sort algorithm.


Allow embedded CRLFs

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Allow embedded CRLFs

cformat switch: M

Sample image here and another sample image here. https://picasaweb.google.com/104621584508159374964/GUIGallery7XTREE - 6014032610809671442

Items in column may contain embedded CRLFs causing it to display using multiple lines. Note that XTR'ITEMLINES determines the maximum number of lines of text displayed in a cell. (Cells that exceed this number of lines will display an ellipsis or "+" to indicate that there is more data than can be displayed.) Also see flags XTF_VARY (variable item height). Note that you cannot use embedded CRLF line breaks in file mode, because CRLF is used for the record terminator.

Comments

When cformat code M is combined with E (editable text cell), cformat m is also implied.

When M is specified for any of the "columns" in a property sheet (see XTF2_PROPSHEET), then it will be applied to all of them, since all of the logical "columns" effectively share the same display column, and the embedded CRLF feature is only adjustable at the display column level. This point applies also to cformat code W.


Application-editable only

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Application-editable only

Updated April 2012

cformat switch: U

This designation may be added to an editable text column (type E, Column contains editable text) to cause the column to only be updatable by the application. In other words, this will make the column editable but not-editable. Possible reasons for using this format type include:

• You want to update the field when re-entering the tree with XTROP_REPLACE. (Only cells associated with the answer array are updated when re-entering with XTROP_REPLACE, and only editable cells are in the answer array.) The alternative would be to use XTROP_REPLACE when re-entering the tree, in which case all of the data cells can be updated, but the operation is less efficient.

• You want to use the same variable for both the answer and data arrays. (This requires that all fields be "editable".)

History

2012 April, A-Shell 6.0.1247: Adding cformat code U (application-editable only) to a checkbox (T or t) or radio button (R or r) now has the expected effect, i.e. the same effect as on regular text cells. That is, the checkbox/radio button becomes disabled to the user, but gets updated by the answer array.


Background cell color

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Background cell color

cformat switch: B

Sample images here and here and here.

Allows you to specify custom background colors for individual cells. Unlike the other color column codes (b, C, c) this one is usually specified in conjunction with some other column type. The first character of the column data is assumed to be an RGB color index (see RGBfg), i.e. A-Z, (or 0-9 which is considered equivalent to A-J). Any other value, or if the specified color index does not reference an RGBfg or RGBbg definition, then that cell will have the normal background color. (Typically you would put a space in the first position for all the "normal" cells, and just use this feature to highlight a few special cells in the column.) For example, if the cell contained "Asold out", it would display "sold out" with the background color associated with RGB color index A. Note that if you want the cell to be blank (i.e. just show a color), do not put any other data in the column, but use the Dspwid option to set the display width of the column.

Also note that if the column contains editable data (E,U,u,T) then the first byte of the corresponding field in the Answer array must also be reserved for color codes. (As of 968.6, this is true even for checkboxes, which previously always occupied only one column in the answer array.) The purpose of using up an extra byte of the answer array for the cell color flag is to allow you to update the color of individual cells during editing validation. To simplify this, the color codes returned on exit will always be blank. Leaving them blank on re-entry causes the previously established color for the cell to be preserved. If you plug in an RGBbg color index value in the answer array for a particular cell and re-enter, that cell's color will immediately be updated accordingly.


Column contains editable text

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Column contains editable text

Rewritten May 2014

cformat switch: E

Sample image here and another sample image here.

When focus is placed on a cell in the column by clicking directly or by navigating with keyboard characters, the cell becomes an edit control, allowing the text contents to be changed. Aside from very basic editing parameters (type of characters, maximum length), validation is left to the application. The XTREE operation can be made to exit, allowing the application to retrieve the updated cell contents from the Answer array to validate/correct/reject the edit and then re-enter at a chosen cell.

This option may be combined with and/or modified by several other Cformat codes, Advanced Coldef Options, and flags options. In particular:

• cformat X (Conditional validation)

• cformat x (Unconditional validation)

• cformat U (Application-editable only)

• cformat u (Read-only editable)

• cformat l (Combo Box)

• InfDef

• Mask

See Also

• Editable Tree Controls


Conditional validation

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Conditional validation

cformat switch: X

This is for use with editable text (E) or checkbox (T) columns; forces an exit for validation immediately after each cell edited, but only if the cell changed during editing. For editable read-only (u) cells, X forces an unconditional exit on entrance into the field (for pre-validation). EXITCODE in either case is typically -48, unless there was another reason to exit the tree besides just the need to validate. XTR'XROW and XTR'XCOL will indicate the cell that previously had the focus; XTR'TARGETROW and XTR'TARGETCOL will indicate the "target" cell (the one that was clicked on, or that will be next in the navigation sequence). XTR'XVALIDATE will be 1 if the former cell needs validation (i.e. changed); 2 if the latter (target) cell needs pre-validation, or 3 if they both need validation. See Editable Tree Controls and (x). Note that prior to build 974, X caused unconditional validation.


Preserve foreground color

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Preserve foreground color

Updated April 2012

cformat switch: !

May be used in conjunction with format codes C or c to force the foreground color to be preserved even when the row is selected. Normally, the foreground (text) color of selected rows is white, so as to offer good contrast with the color of the selection bar, which is usually blue. But this makes the rows which have custom text colors indistinguishable from the ones that do not (when selected). When ! is specified, A-Shell will attempt to determine if the foreground color is "too close" to the color of the selection bar to distinguish; if so, then it uses black for selected text; otherwise it retains the original foreground color. (This is probably mainly of interest with multi-selection mode.)

History

2012 April, A-Shell 6.0.1248: adding the cformat code "!" to any column now assigns that and all remaining columns the "retain foreground selected color" feature. Previously it only applied to row colors; with this change, it can be applied to colored columns as well.


List hierarchy

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

List hierarchy

cformat switch: @

For multi-level lists, a column must be defined using this type, and must also contain a digit indicating the hierarchical level of each row (0 through 9 with 0 being the top level.) Note that you would almost always want to also use the H code to hide this column, otherwise you will have a visible column containing the level indicators. Due to some internal complexities in the control, it may not be possible to hide the first column; to avoid this problem, make sure the @ column is not the first one defined.

The compound code "@@" may be used in place of just "@" to force the left/right arrow keys to always act as expand/contract/navigate keys, even if the XTF_LEFT, XTF_RIGHT, or XTF_EDITABLE flags is present. See XTREE Techniques ... Mouse and Keyboard.


Numeric data

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Numeric data

Note that the standard edit control used by XTREE does not have the sophistication to accept decimal points or minus signs without accepting other non-numeric digits, so adding "." or "-" to the # type effectively allows any character to be entered (like S or #S). However, the explicit use of the decimal point or minus sign in the cformat string makes the intent more clear, and since the implementation may be upgraded later, is therefore recommended when applicable. Also see the advanced coldef option Mask for further control over the formatting of the field.


Literal backslash

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Literal backslash

Updated March 2011

cformat switch: \

The backslash may be used to declare that a backslash within the column should be treated as a normal character, rather than as the start of hidden text (as would otherwise be the case when in file mode). Note that using the \ type on any column effectively turns it on for all columns.

History

2008 July, A-Shell 5.1.1119: The determination of whether a "\" marks the beginning of hidden text in XTREE has been improved for array-mode trees. Previously, unless one of the columns specified the cformat code "\", all backslash characters were considered as the start of hidden text (from there to the end of the row). This was taking people by surprise, especially when the backslash occurred in an editable column (like in a filespec). The new rule is that a backslash will be treated as a literal character if ANY of the following is true:

• The cformat code "\" is present for any column (as before).

• The backslash occurs prior to the last physical column in the array data (without regard to the order in which the logical columns are defined).

• The last physical column is editable.

2005 October, A-Shell 4.9.945: switch added to A-Shell


Background row color

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Background row color

cformat switch: b

Allows you to apply custom background colors to individual rows. This is the same concept as the column type c except that it only uses colors defined by RGBfg clauses (either on the pseudo column or on any other column). The column must contain a single alphabetic character (A-Z) matching an RGB color index, or, if you prefer numbers, you can use a single digit 0-9 (which is treated as equivalent to A-J).

Sample image here.


Row color

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Row color

cformat switch: C

Allows you to apply custom foreground colors to specific rows. Column may contain an RGB color index (A-Z, a-z) which matches the index assigned to an RGBfg or specification on another column. The corresponding color is applied to the foreground (text) of the remaining columns in the current row. Leave column blank (or "=") to use the default color scheme for that row. Note that you would almost always want to also use the H code with this column type to hide it.

Sample image here.


Row color option

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Row color option

cformat switch: c

Identical to C, except that it takes effect starting from the first visible column even if the color definition column is not the first column. This is a workaround for a limitation in which trying to make the first defined column invisible does not always work. (XTREE seems determined to make the first column reappear.)

Sample image here and here.


Combo Box

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Combo Box

cformat switch: l (lower case el)

Similar to column format E except that instead of an edit control, a combobox control is used for editing the cell when the cell has the focus. The combo box choices must be defined with one of these Advanced Coldef Options: List, CellList, ListX and CellListX. There are three variations of comboboxes. In the default variation, the user can only select among the defined choices. If the E code is specified in addition to the l code, then the user will also be able to type in a text value that is not in the list. The third variation is the so-called "self-service" combo in which the list just contains "…" and when the user clicks on the dropdown button, it exits with exitcode 29 (as in INFLD).

Note: regardless of whether the E code is specified, combo box columns are treated like editable columns in that they must be represented in the answer array. In order to prevent individual cells or entire columns from being actually editable by the user, prefix the column data with a "|". This may require expanding the column width, again both in the data array and answer array.


Standard Date Format

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Standard Date Format

cformat switch: D

MM/DD/{CC}YY format or DD/MM/{CC}YY format, depending on language definition. Supports quite a bit of flexibility in formats, including dates with other delimiters (e.g. 12-31-06), no delimiters (e.g. 12312006), as well as dd-mon-{cc}yy format (e.g. 12-dec-2006). If a two digit year is specified, XTREE uses the SBR=CCYY:## parameter in the miame.ini for determining the century. The default value is equivalent to SBR=CCYY:60, meaning that any YY value of 60 or higher is assumed to 19YY; otherwise it is assumed to be 20YY.

Note that there is no internal validation or formatting logic associated with the D cformat code. Its purpose is solely to inform the sorting routine (see XTF_SORT) so that it can interpret the column data to be able to effectively sort it in chronological order. For editable date columns, the only way to enforce a consistent format is to use the Advanced Coldef Options InfDef=D and Format=<format string>, which cause the Windows date/time picker control to be used for editing.

History

2008 May, A-Shell 5.1.1113: Date columns that include both a date and a time (e.g. "25-May-08 08:25 PM") will now be sorted taking both into account.


Font definition column

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Font definition column

cformat switch: f

Same concept as the color definition column (cformat c) Column should be 1 character wide, and contain a space or digit 0-4. Space or 0 causes the default font to be used for that row, else references the first through fourth special fonts defined previously using the Font and/or Scale options with a pseudo column.


Hidden column

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Hidden column

cformat switch: H

Allows you to start with a fixed format source of data (either array or file) and customize it at runtime by making selected columns invisible. (Hidden columns are loaded into the list box just like any other data, so you would not want to over-use this technique with large data sets due to the wasted overhead.)

Note that the hidden column flag (H) overrides the Dspmin and Dwpwid options.


Image column

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Image column

Updated June 2010

cformat switch: I (upper case eye)

Sample image here.

Column data contains the filename of an image file to display in the column. Supports JPG, BMP, PCX, GIF, TIF, PNG and ICO file types but requires the A-Shell Imaging Library (an add-on module). You must also specify the options ImgSiz, ImgCount, and optionally ImgDir. You can include arbitrary text in the cell, along with the image, by appending a comma to the filename, followed by the arbitrary text. The column definition has to be wide enough to include both the filename and the desired display text.

Note that although image cells can display additional text, and the text may be made editable (if the column is editable), the image filename itself is not editable. To change it, you need to programmatically change the filename in the column data and reload the tree.

Note also that in the case of ICO files, you may either specify the .ICO file itself (as with the other image types), or you may specify an icon resource using the resname::dllname syntax.

History

2015 May, A-Shell 6.1.1410: Support multiple image columns per XTREE. Previously only one was allowed.

2010 June, A-Shell 5.1.1113: Icons may now be loaded into image cells


First Position Reserved

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

First Position Reserved

Added March 2011

cformat switch: P

Code P may be used with editable cells (cformat codes E, l) to indicate that the first position (after any cell code bytes such as the color byte used with cformat B) is reserved for either a space (indicating editable) or a "|" indicating that the cell is not editable.

Note that the "|" prefix has long been supported as a code to indicate that the cell is disabled for editing, but it is sometimes awkward to use because of confusion over whether to shift the remaining characters over. The new P option allows you to reserve a position (same concept as with the background cell color byte used with B), which may be easier to use, depending on your application logic.

Also note that feature is not necessary with the shared lists (cformat s used with CellList or CellListX), because in those cases, a space is already reserved for a prefix code, in which "|" is already an option.

History

2011 March, A-Shell 5.1.1208: Added to A-Shell


Editable radio button

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Editable radio button

cformat switch: R

Sample image here.

Similar to T (checkbox) but has the additional behavior of automatically clearing any other radio buttons in the same group when one of them is set. Thus a group of radio buttons may serve as a way of inputting a "one of" choice. See sample program XTRA6.

By default, all of the radio buttons on a row are in the same group, whether contiguous or not. To define multiple groups of radio buttons (or a vertical group), see the "Group" option in Advanced Coldef Options.

The XTRA6 sample program illustrates radio buttons with cell colors.

See Cformat code r for non-editable radio button.


Editable checkbox

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Editable checkbox

Updated November 2013; see History

cformat switch: T (standard) or T+ (extended) or T3+ (three-state extended) or T++ (extra extended)

An editable checkbox is represented in the data and answer arrays by a one-character column coded according to the following table:

Code | Description
0 | Unchecked
1 | Checked
2 | Indeterminate
4 | Unchecked, disabled
5 | Checked, disabled
6 | Indeterminate, disabled
. | A space blanks out the cell entirely

Note: values in the above table are strings ("0", "1", etc.), not binary values.

Extended 2-state checkboxes (T+) and 3-state checkboxes (T3+) support the following additional mouse & keyboard commands:

• When the focus is on a checkbox cell, Ctrl+A sets (ticks) all the enabled checkboxes in the column.

• When the focus is on a checkbox cell, Ctrl+B resets (clears) all the enabled checkboxes in the column.

• When the focus is on a checkbox cell, Ctrl+Z reverses the action of the immediately preceding Ctrl+A, Ctrl+B, or Shift+Click.

• To set (tick) a range of checkboxes in the same column, click to set the first checkbox in the normal way, then Shift+Click on the last checkbox in the range. Since this technique only works to set checkboxes, you the checkboxes at either end of the range must be unset to start with (because the click operation toggles the setting).

Extra-extended (T++) 2-state or 3-state checkbox columns will have a 3-state checkbox added to the header of the column which is automatically set to the checked state if all the boxes in the column are checked; the unchecked state if all the boxes are unchecked, or the indeterminate state if there is a mixture (or if all of the boxes are indeterminate), as in this example:

Clicking the checkbox in the header cycles through the check-all, uncheck-all, set-all-to-indeterminate (if 3-state), and back to the original mixed state (if applicable).

The following special context menu commands (see PopupMenu) relate specifically to extended checkboxes:

• $CBSET acts like Ctrl+A (sets all checkboxes in the column over which the mouse was right-clicked to bring up the context menu). If the menu is activated by right-clicking on any column other than an extended checkbox column, this option will not appear on the menu.

• $CBRST is like $CBSET, but acts like Ctrl+B (reset or clear all checkboxes)

• $CBUNDO acts like Ctrl+Z. Like $CBSET and $CBRST, it will only appear in the menu if the menu is activated for an extended checkbox column. In addition, if undo is not possible, the option will be grey.

• $CBSETDEP is like $CBSET, but applies only to the dependents of the current item. If the item clicked has no dependents, the option will be grey. If the tree is not multi-level (XTF_MLVL not set – see Flags), the option will not appear at all.

• $CBRSTDEP is like $CBSETDEP, but resets rather than sets the dependent checkboxes.

Because the above context menu commands adjust to the runtime circumstances, they can be added to the common PopupMenu for a tree, without regard to whether the tree even contains extended checkboxes, rather than having to add them only to column-specific context menus. The only reason why these items weren’t just automatically defined for extended checkbox columns is to allow you to define the wording. For example, for a tree in which the items represented styles of products, grouped into categories, you might define the context menu items as follows:

Coldef = "0~0~x~H~PopupMenu=Order all styles,$CBSET;Cancel all,$CBRST;"; &

+ "Order all styles in category,$CBSETDEP;Cancel all in category;$CBRSTDEP; &

+ "Undo;$CBUNDO~~"

The context menu might then appear as:

Notes

• You must also specify the flag XTF_EDITABLE when using checkboxes.

• If the checkbox column supports cell colors (cformat code B) then the column data (in both the data and answer arrays) should be two characters wide (instead of one), with the first character reserved for the color code.

• Use Cformat code t for non-editable checkbox, and code 3 for three-state checkboxes.

History

2016 October, A-Shell 6.3.1530.6: Column ordering for all the columns (up to the max of 100) can now be saved when using the TreeID mechanism with the XTUCFG_COLORD bit set in the XTR'USRCFG field. Previously the limit was 31 columns, which remains the limit when using the XTR'COLORDER() array method without the TreeID option.

2016 October, A-Shell 6.3.1530.5: Extended checkbox columns may now be extended to a second degree by adding a second "+" (e.g. T++ or T3++). This adds a 3-state checkbox to the header of the column which is automatically set to the checked state if all the boxes in the column are checked; the unchecked state if all the boxes are unchecked, or the indeterminate state if there is a mixture (or if all of the boxes are indeterminate). Clicking the checkbox in the header cycles through the check-all, uncheck-all, set-all-to-indeterminate (if 3-state), and back to the origional mixed state (if applicable).

2013 October, A-Shell 6.1.1363: The PopupMenu options $CBSET, $CBRST, and $CBUNDO now return EXITCODE=-48 and XTR'XVALIDATE=3 when validation (conditional or unconditional) is active for the column. $CBSETDEP and $CBRSTDEP return XTR'XVALIDATE=4.


Non-editable checkbox

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Non-editable checkbox

cformat switch: t

This should be a single character column, whose contents are "0" for an unchecked box, "1" for a checked box, or blank for a blank cell (with no checkbox). Non-editable checkboxes act just like other data columns, and do not require the XTF_EDITABLE flag or have any correspondence with the array parameter.


Read-only editable

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Read-only editable

Updated June 2016

cformat switch: u

Similar to "U" in that it defines a variation on an editable text cell. While "U" causes the editing logic to skip over the cell in input mode, making it only updatable by the application, lower case "u" allows the cell to be given the edit focus but in read-only mode. Read only mode looks the same as regular edit mode except that the background of the cell is gray instead of white.

The idea behind this feature is to give the user a sense of being able to edit the cell, but without allowing them to directly edit it. Instead, when the cell has the focus, most keys other than navigation keys will cause the XTREE to exit (with EXITCODE = -48, as for normal cell editing validation), so that the application can then present a more customized cell editing capability.

For example, in an appointment scheduler, you might want the user to be able to "edit" a cell in order to make or change an appointment, but you don't want them to just be able to type anything in the cell. Instead, they cause the cell to have the focus (using navigation keys or by clicking with the mouse) and then they can indicate the desire to update the cell by hitting Enter, or any exit key, or for that matter, any normal character key. The application would then detect this event by the combination of the EXITCODE (-48 for Enter or printable characters, or the normal exitcode for other exit keys) and determine the cell by the XTR'XROW and XTR'XCOL fields. Then it might pop up a dialog designed for editing an appointment. When that dialog is finished, the application can plug an updated value for the cell into the appropriate slot in the ANSARY parameter and re-enter the XTREE using XTR'OPCODE 4 (reselect).

Note that when re-entering, the initial focus will be determined by the XTR'XCOL and XTR'XROW fields (presumably still pointing the cell we were just in) and the XTR'XNAVCOD field, which contains the value of the key used to exit the field. Depending on that value, the initial focus may be advanced to another cell. For example, the standard action for the Enter key is to advance to the next cell. If you don't want that, then zero out XTR'XNAVCOD before re-entering the XTREE.

Also note: XTR'XNAVCOD can be used to determine which key the user entered to cause XTREE to exit. 13=Enter, while values from asc("1") to asc("z") indicate the corresponding character key.

Pre-Exit on read-only cell

The combination "uX" (editable read-only, with validation) causes an automatic exit with EXITCODE -48 whenever the cell is ENTERED (rather than EXITED).

This makes some sense, given that you should not be able to modify the cell if it is read-only, so there isn't any point in post validation. But there is a point in pre-validation if you wanted to perform some action whenever the user selects one of these cells, either by clicking on it or using keyboard navigation.)

Note that the XTR'XVALIDATE flag will be set to +2 to indicate that pre-validation of the cell identified by XTR'TARGETROW and XTR'TARGETCOL is needed.

Also note that as of A-Shell 6.3.1516 there is no straightforward option to pre-validate an editable cell. However, you can simulate the effect by setting the adjacent columns to unconditional validation. In your program's validation routine, you can then detect when you are about to enter the column you wish to pre-validate by checking if it matches XTR'TARGETCOL. This will trap most cases of navigating into the column, except the user directly clicking on the column or the app directly starting on it.

History

2006 October, A-Shell 4.9.968:

• This function now supports individual cell colors.

• Text in the cell is not selected when starting the edit operation

• Double-click now exits with EXITCODE -59.


Unconditional validation

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Unconditional validation

cformat switch: x

This flag may be used for "unconditional validation" of normal editable cells. When combined with "u", it defeats the pre-validation and always causes post validation. (The value of post-validating an edit of a read-only cell may be debatable, but this might be useful for the sake of uniformity if you want to validate between every cell movement.)


No Strip

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

No Strip

Added January 2011

cformat switch: " " (blank)

When used in conjunction with a Mask, this code causes any leading spaces introduced as a result of the mask formatting to be preserved within the field. (Normally they are stripped before applying the column's justification.)

This rather obscure feature may be useful in property sheets where you want to right justify some fields, but don't want them justified all the way to the right edge of the edit column (which may be wider than appropriate for the items in question, due to other, longer text items). For example, if you have some numeric items that you want to right justify (so that they line up with each other) but don't want way over at the right edge of the column, you can specify the combination of "<" (left justify), " " (no strip), and "Mask=###,###,###,###.##". The "<" will force the data to be left justified in the cell, but the no strip option will effectively preserve right justification (provided that you are using a fixed pitch font). Typically in this case, you'll want to make the column and mask wider than you would otherwise need, so that the displayed values are pushed farther to the right. The xtra15.bp sample program has been updated to illustrate this.

History

2011 January, A-Shell 5.1.1202: Added to A-Shell


Expand/Collapse State

Subroutines > XTREE > XTREE Parameters > Coldef > Cformat

Expand/Collapse State

Added April 2013

cformat switch: = (equals sign)

This option is used for maintaining the expand/collapse state of items in a multi-level tree. When loading data items (XTROP_CREATE or XTROP_REPLACE), the column values will be processed as follows:

Value | Action
" " (blank) | No special action
0 | Force item to be collapsed
1 | Force item to be expanded (immediate dependents displayed)
"A" | Same as "1" but expand out all dependents of the item

Normally you would want to hide this column by adding "H" to the cformat code (e.g. "=H").

To retrieve the current expand/collapse state of the items on exit from the tree, you add the "U" code (e.g. "=HU") to make the column editable by the application so that the corresponding column of the answer array will be updated on return from the tree. This also means that item expand states will be potentially updated when re-entering the tree in XTROP_RESELECT mode. Note that in this case, you must use XTF2_ANSEQDATA flag (the answer and data arrays must be the same format, or perhaps even the same array).

History

2013 April, A-Shell 6.1.1348: Added to A-Shell


Advanced Coldef Options

Zero or more of the following options may be specified to further define column options. Syntax is:

~option = value~

Example

COLDEF = COLDEF + "10~15~Title~S~Color=3,7~Scale=200~~"

Note that both options and values are case sensitive. Additional examples may be found in the Advanced Syntax Example.

Option | Description
CellList | Use to associate shared lists (combo boxes) with individual cells rather than entire columns.
CellListX | List substitution style (aka INFLD ||L) combo lists. See ListX and CellListX.
ClickExit | Define Exitcode values for left and right click on the column. Applies to all columns if the ClickExit clause is associated with column 0, otherwise applies only to the specific column. A right-click value in ClickExit takes precedence over PopupMenu. Format: ClickExit=<left exitcode>,<right exitcode>. See also XTR'KBDSTR.
CollapseExit | Triggers an exitcode when a branch is collapsed; see ExpandExit.
Color | A pair of digits, comma separated, representing the desired foreground and background text color for the column, from the A-Shell palette. Use only if you want the column to have a different color scheme from the others. E.g.: Color=1,2. (Foreground color one, background color two). Also see RGBbg, RGBfg.
ColOptRows | Determines how many rows are considered when optimizing the column widths.
CtlName | You can assign a name to an XTREE control by adding the coldef clause "CtlName=name" to any column (where name is the name you want to assign).
CurSym | Defines an alternate currency symbol to replace the $ in a mask (e.g. Mask=$###,###.##).
Data | Use to define the contents of a Constant Data Column.
DefaultFont | Sets the default font for the entire tree. The syntax is the same as for Font.
DefaultScale | A font scaling percentage (100=normal), e.g. DefaultScale=120. Works similarly to Scale, except that it affects all subsequent columns, not just the current column. Furthermore, if specified with a pseudo-column, it affects all the rows, eliminating the need to define a special font column with coldef code "f". This makes it much easier to apply a scale factor to an entire tree. Note also that the DefaultScale value is taken into consideration when XTREE determines the row height for fixed-height rows. HdrScale=0 and DefaultScale=0 are interpreted as requesting the default Windows desktop font size.
DragDropClick | DragDropClick=###, where ### is the negative exitcode to be generated when an item (or items) from the source tree is/are dropped on to the destination tree. For example, DragDropClick=150 will generate exitcode -150.
DragDrop Protect | DragDropProtect=### allows ### rows at the top (or -### rows at the bottom) to be protected from drag/drop operations. Note that because sorting would confuse the issue, DragDropProtect=### will automatically set HdrLines=### (if ### positive and HdrLines not already set), and TotalLines=### (if ### negative and TotalLines not already set). Also supported is the syntax DragDropProtect=##,##, which will protect rows at the top of the screen (first number) and the bottom (second number); use positive values for each.
DropExit | "DropExit=###" may be used to force XTREE to exit with the specified exit code (###) at the completion of a Drag/Drop operation. Note that the exitcode will be -### (i.e. DropExit=88 will return exitcode -88 on a drag/drop). This is the same syntax as SelChgExit=###.
Dspmin | Similar to Dspwid except sets the minimum display width. (Unless the column is locked with the cformat L option, the user can resize the column, subject to this minimum.) E.g. Dspmin=5. The dspmin option is overridden by the hidden column (H) option. See
Dspwid | Sets the initial display width of the column, e.g. Dspwid=10.
EnterGoTo | EnterGoto=# specifies the column # to jump to when the Enter key is hit.
ExitChars | Defines a set of characters that will force an exit from the tree.
ExpandExit | Triggers an exitcode when a branch is expanded.
FastMax | FastMax=# sets the number of characters for an editable text or combo field which can be entered before it automatically advances to the next field. Supercedes InfDef=F, which no longer does anything. This clause is compatible with cell validation. Change In A-Shell 1377 of March 2014: FastMax=1 now causes the cell to exit after clicking on a new selection in the dropdown list, or after using the up/down arrow keys to change the selection and then hitting ENTER.
FixedLayout | Causes XTREE to handle the specified column in a more "INMEMO-friendly" manner.
Fold | Fold = <Upper or Lower>. For editable cells, this flag causes contents to be automatically folded. The folding applies during editing of cell but does not change the underlying data. See Cformat ^. Also see Coldef Default.
Font | A font face name and/or font attribute code, separated by a comma. See Coldef Default.
Footer | See Title and Footer.
Format | Sets options related to the Date/Time Picker control associated with an editable date/time column.
Group | Associate a radio button cell with a Radio Button Group.
HdrClickExit | When specified, clicking on this column header causes an exit with the specified exitcode.
HdrFont | Same format and concept as Font, but applies to the header row.
HdrLines | This analogous to the TotalLines option, but allows you to specify a number of lines at the top of the tree that are to be treated as fixed headers and thus not included in sorting.
HdrScale | This is to Scale as HdrFont is to Font, e.g. HdrScale=125. HdrScale=0 and DefaultScale=0 are interpreted as requesting the default Windows desktop font size.
ImgCount | Required with cformat I to allocate space for the image storage
ImgDir | Optional with cformat I to specify the default image directory
ImgSiz | Required with cformat I to define image size and scale parameters
InfDef | Used to specify some variations of XTREE editable cell behaviour using INFLD TYPE codes.
List | Define combobox entries for column type l.
Listx | List substitution style (aka INFLD ||L) combo lists. See List and ListX and CellListX.
Mask | Define a numeric formatting mask
MaskView | This is identical to the existing Mask option, except that the non-numeric mask characters (relative to the current LDF) are stripped from the editable fields returned in the answer array. This is most convenient when you plan to use the data returned from the tree in numeric calculations, where the mask formatting characters may interfere with the conversion from string to number. Added in A-Shell 6.3.1514, June 2016.
NegFgBg | Allows control over the color used to display numeric cells with negative values.
PopupMenu | Defines a popup menu that will appear when the user right-clicks on a row.
ParentID | Specify the alphanumeric control ID (see Control names) of the parent control. XTR'PARENTID (in Xtrctl) must be set to zero.
Print | Disables printing on popup menu, including with ^P.
RGBfg | Define a foreground color specification.
RGBbg | Define a background color, for a column or to be used for a row or cell.
RGBignore | Applies to editable text columns, and is equivalent to RGBbg except that it only applies to cells that are marked to ignore. Cells are marked to ignore by placing a "|" in the first column of the answer array for that cell.
RGBfgSel, RGBbgSel | Define the foreground/backgroud colors for the selection bar; see RGBfgSel and RGBbgSel.
RGBfgHeaders, RGBbgHeaders | Define the foreground/background colors for the header line; see Headers and Totals Colors.
RGBfgTotals, RGBbgTotals | Define the foreground/background colors for the totals line; see Headers and Totals Colors.
RGBbgOdd, RGBbgEven | Define the default background color for the odd and even rows. This is typically used to create a "green bar" effect to improve readability. Although this could be done using using individual row colors, the problem is that sorting would mess up the effect by requiring that you handle your own sorting via HdrClickExit. Note that any other color settings pertaining to individual rows or cells will override these. The format for these is the same as for RGBfgSel and RGBbgSel. If only specifying one of these values, use RGBbgOdd. Sample image here.
RGBbgAll | RGBbgAll=r,g,b sets background color for all rows and columns. Affects even unpopulated rows, unlike all other RGBbg options except RGBbgEven and RGBbgOdd.
Scale | A font scaling percentage (100=normal). (e.g. Scale=50). When associated with a real column, the font defined (indirectly via the scale factor) affects just that column. When associated with a pseudo column (i.e. with cwidth = 0) it just serves to define the font so that it can be referred to by data in a font definition column for applying specific fonts to individual rows (see cformat f in the table above). See Font and Default Scale.
ScrollMode | Change the operation of Up/DownArrows to act like Ctrl+Up/DownArrows.
SelChgExit | Causes XTREE to exit with exitcode -### whenever the selection changes.
Title | Title=<clause>. Used as a page head and window title when using the XTREE print function. <Clause> supports one or two "|" delimiters to separate it into Left|Center|Right. If no delimiters, the text is used as the right title, and the default left title is the date. If one delimiter, it is treated as Left|Right.
TotalLines | TotalLines=# where # is the number of lines at the bottom of the list which represent totals and thus should not participate in sorting. TotalLines=1 is equivalent to setting flag XTF_TOTALS.
Tooltip | Specify a custom tooltip for the column.
TreeID | Tree=<identifier> identifies this tree uniquely to enable Saving User Adjustments specific to this tree.
VertAlign | Overrides default vertical centering of text or images within each cell. Choices are Top and Bottom—e.g. VertAlign=Top.

Note 1: When option is associated with the pseudo zero column, it becomes the default for all subsequent columns. That default can be overridden by individual column settings.


ClickExit

ClickExit=<left click exitcode>, <right click exitcode>

Causes a single click on a cell in the column to generate an exitcode. Examples: ClickExit=-88,89 (left click generates exitcode -88, right click 89.) ClickExit=0,-88 (left click ignored, right click -> -88); ClickExit=-97,0 (left click -> -97, right click ignored).


ColOptRows

Added December 2010

This option, Column Optimization Rows, is used to determine how many rows are considered when optimizing the column widths. In earlier versions of A-Shell, XTREE always looked at the first 100 rows, and this remains the default. But you can override the default by specifying the Advanced coldef parameter:

ColOptRows=###

If ### is positive, it indicates the number of rows to consider for that column (max is 32767). If negative, it indicates the percentage of the total rows to consider.

Any column that does not have a ColOptRows=### parameter will use the default # of rows (normally 100). To change the default, specify ColOptRows=### with the zero column.

Note that the entire point of this exercise is to balance the column optimization with performance. The more rows that have to be considered, the longer it takes to arrive at the optimum width. The default of 100 rows is generally sufficient for "pretty good" optimization, and with negligible performance overhead. But, depending on the variability of the data in each column it may be that much less would be sufficient, or much more insufficient. As a rule of thumb, figure about 25 cells per millisecond of optimization time.

So for a 1000 row x 30 column grid, the default optimization (looking at 100 rows) would take about 100 ms, while looking at all 1000 rows would take 10 times longer, or 1000 ms, which will be noticeable. But if only one of the columns has data of widely varying width, you could set ColOptRows=-50 (i.e. look at the first 50% of the rows) for that column, and perhaps change the default (for the other columns from 100 rows to 10 rows). That would reduce the number of cells considered from 30000 to 790, and thereby reducing the total optimization time from 1000 ms to about 27 ms.

Although the length of this discussion may imply that it is very important to get the column width optimization right, keep in mind that the only downside of too little optimization is that some columns many initially be too narrow to show the widest cells without truncating, thus forcing the user to manually adjust the column width in order to see all the data. (Which can be done by either dragging the right column border, or double-clicking on it, in which case it optimizes that column considering all the rows.)

On the other hand, too much optimization just wastes time, reducing responsiveness. But that isn't likely to become noticeable until you have upwards of 5000 cells to consider.

History

December 2010, A-Shell 5.1.1198: Added to A-Shell


CurSym

Added January 2013

CurSym=###

where ### is the decimal value of the ANSI (8-bit) character to use.

This option is used to define an alternate currency symbol to replace the $ in a mask (e.g. Mask=$###,###.##).

As with many other advanced coldef options, if associated with the zero column, it becomes the default; else it only affects the specified column. So you could have Dollars in one column, Euros in another, and Pounds in a third. The most likely options would be:

CurSym=128 ! Euro symbol

CurSym=163 ! Pound symbol

Note: ANSI character sets vary in support for some of the currency symbols. It is left to you to make sure that the value specified displays as desired in the font you are using.

Comments

There are two complications here. One is that we are using the ASCII version of the XTREE control. (To really support non-ASCII characters, we should switch to the UNICODE version, which we may do at some point. For now, this is a workaround.) The other is that there is no way for us to be sure whether all existing XTREE masks which include the $ symbol really want to indicate dollar or the local currency. So rather than make it automatically default to the local currency, we opted to eliminate the possibility of breaking an existing application (and thereby forcing anyone who wants non-$ currency to add a new clause to their coldef.) A side benefit of this approach is that it allows you to have different currency symbols in different columns or trees at the same time.

History

2013 January, A-Shell 6.1.1330: Added to A-Shell


Constant Data Column

Added August 2015

data=<text>

This allows you to define the contents of a column that is constant for all rows. This is essentially just a shortcut to redundantly specifying the same text in every row of the data array, and is typically most useful for columns containing "buttons", such as a "delete item" button on any row. Aside from specifying the column contents in the Data=<text> clause, you must also set the cpos and cformat parameters to -1.

For example, you can define a column of delete "buttons" as follows:

coldef += "-1~-1~Del~I~ImgSiz=16,16,24~ImgCount=1~" "Data=delete2::ashico1~ClickExit=-300,0~~"

History

2015 May, A-Shell 6.1.1410: Added to A-Shell


Dspwid

Updated April 2011

Dspwid=<width in grid column units>

Sets the initial display width of the column (in character positions based on the standard character grid). For example, if set to 10, the column will occupy the same width as ten ordinary fixed-pitch characters (although it may display more in the typical proportional font.) If not specified, the initial column widths will be set wide enough to accommodate the longest data. This option is mainly useful for columns that may contain variable length text (see cformat W option above), lest they expand to fill the entire pick list width, forcing the user to have to scroll horizontally (or manually resize the column) to see the other columns. (e.g. Dspwid=10)

Also, this option may be used to specify a fudge factor adjustment (+/- pixels) rather than just a fixed size. To specify a fudge factor, insert a + or - after the =, e.g.

Dspwid=+5 ! increase calculated width by 5 pixels

Dspwid=5 ! set width at 5 grid units

The fudge factor is particularly useful in situations where some minor internal miscalculation of the optimum column width is resulting in column data being truncated.

Note that the Dspwid (and Dspmin) options are overridden by the hidden column (H) option. Also see Coldef Default.

For property sheet mode (XTF2_PROPSHEET), Dspwid takes on a slightly different meaning. Since in this mode, all of the logical columns occupy the same display column, they cannot each have their own display width. Instead, Dspwid applies only to the width of the editable cell (i.e. when the cell is actively being edited; the units in this case are average character widths in the current font. This is similar to cformat "_" (which see), but allows more flexibility, since it is often preferable to make the editable box slightly wider or narrow, in order to allow for variability in the character widths.

Examples

Without a Dspwid specification (and assuming cformat "_" not specified), the edit box will occupy the entire width of the column, as shown here:

With Dspwid=6, the edit box is reduced to fix approximately 6 characters, as shown here:

See Also

XTF2_AUTOEXPCOL

History

2011 April, A-Shell 5.1.1213: Dspwid now works with combo box cells in property sheet mode to limit the width of the combo box. Note that the width specified includes the dropdown button, so you may need to adjust it upwards.


EnterGoTo

Updated October 2013

EnterGoto=# specifies the column # to jump to when the Enter key is hit while editing a cell in this column. If #>0, it jumps to defined column # in the next row. If #<0, it jumps to defined column # in the current row. (Defined column numbers are based on the order in which they are defined in the coldef string; this could be unrelated to the display column # due to both hidden columns and reordering - see XTF_REORD.) If EnterGoto is not specified, the default is for Enter to act like Tab and advance to the next editable cell to the right, wrapping to the next row if necessary, unless the XTF2_ENTERNAVDOWN flag is specified.

Beginning in A-Shell 6.1.1318, EnterGoto=# may now be set to 0 (EnterGoto=0) to cause the tree to exit on ENTER, with exitcode = -48. If you don't like exitcode -48, you can use the syntax EnterGoto=##### where ##### is >= 10000, or <= -10000, in which case it will return with exitcode set to the specified value offset by 10000. For example, EnterGoto=10099 will return exitcode 99, while EnterGoto=-12500 will return exitcode -2500.

History

2012 October, A-Shell 6.1.1318: Accept value of zero, as described above.


ExitChars

ExitChars=<list of chars>

Defines a set of characters that will force an exit from the tree, where <list of chars> can be any combination of the following:

0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ

Notes

· The alphabetic characters are not case sensitive.

· The exitcode will be set to -51.

· XTR'XNAVCOD will be set to the actual character entered

· Use the carat ( '^') to specify control chars

· This feature is not column-senstive.

History

2010 March, A-Shell 5.1.1176: ExitChars now work in all kinds of editable cells. Previously, they worked only in checkboxes and radio buttons.

2008 December, A-Shell 5.1.1133: ExitChars now supports control characters, using the control character as a lead-in. For example, "ExitChars=ABCD^S^Z" would exit on A,B,C,D plus Ctrl+S and Ctrl+Z.


ExpandExit

Added April 2013

These two options trigger an exitcode when a branch is expanded or collapsed:

ExpandExit=clickcode

CollapseExit=clickcode

clickcode may either be an integer value as with the SelChgExit=### command (e.g. ExpandExit=402), in which case the click event will return exitcode -402, or it may use the format of the row-specific exitcodes supported by XTR'KBDSTR as of 6.1.1345, in which case it will return an exitcode specific to the item that was expanded.

For example:

ExpandExit=_xF5RRR

would generate an exitcode of -5003 when the expands item #3.

Notes

• In the case of a click on an inactive XTREE, the ExpandExit and CollapseExit codes supercede the XTR'KBDSTR code.

• The exitcodes are generated for user-triggered expand/collapse events, regardless of whether triggered by a mouse click or keyboard command. However, they are not generated for expand/collapse events which are triggered indirectly by the application, such as via the XTR'EXPANDLEVEL or by setting the focus on an item that requires expanding the parent item so as to make visible).

• The expand-all and collapse-all keyboard commands (CtrlShift+ and CtrlShift-) will act as if taking place on row 0, in case the clickcode uses the current row as part of the exitcode.

History

2013 April, A-Shell 6.1.1347: Added to A-Shell


FixedLayout

Added October 2015

FixedLayout = True

When set, XTREE attempts to handle the specified column in a more "INMEMO-friendly" manner. INMEMO uses a fixed rectangular grid layout, which maps easily on to a 2 dimentional array of R rows by C columns, whereas "normal Windows" multi-line text fields do not typically impose any such concept on the format of the lines. Instead, the only limitation is the total number of characters allowed. Lines may or may not be wrapped according to the font and column display width, and you may also have embedded CRLFs marking hard line breaks. The "normal Windows" method, used by XTREE and INFLD, has various advantages, but is hard to reconcile with legacy printing forms and fixed record layouts.

To use the new option, set XTR'ITEMLINES to the number of lines of text in your multi-line text cells. The width of each line will be inferred from the total width of the column as defined to COLDEF, with any remainder discarded. XTREE will then assume that the data for the cell is arranged accordingly, with each line space padded rather than terminated by CRLF. In addition to converting to and from that format, it will also attempt to prevent the user from exceeding the specified maximum number of lines and columns when editing the cell.

For example, if XTR'ITEMLINES is 4 and the width of the CWDITH value for the column is 100, it will be treated as an array of 4 by 25 characters, and the user will be limited to no more than 4 rows, and no more than 25 characters on any one row.

Notes / restrictions: Not compatible with XTF_VARY or XTF2_UTF8. This is purely a client-side enhancement; no changes needed on the server side, other than to your application to supply the column text in the alternate format.

History

2015 October, A-Shell 6.1.1420: Added to A-Shell


Font

Font=<facename>, <fontattr>

(e.g. Font=Lucida Console,1537) Either part can be omitted to accept the default for that parameter, in which case the comma should also be omitted. Font attribute codes consist of a sum of the following values. (There may not be a meaningful difference between some of the stroke weights – these are just hints to the font mapper.) Note: this table is from AUI...fontattr. Change there and copy here!!!

Symbol | Value | Description
FS_UPRIGHT | &h00 | Normal upright
FS_ITALIC | &h01 | Italic
FS_UNDERLINE | &h02 | Underline
FS_STRIKEOUT | &h04 | Strikeout

Symbol | Value | Description
FA_DONTCARE | 0 | Do not care
FA_THIN | 1600 | Thin
FA_EXTRALIGHT | 3200 | Extra Light
FA_LIGHT | 4800 | Light
FA_NORMAL | 6400 | Normal
FA_MEDIUM | 8000 | Medium
FA_SEMIBOLD | 9600 | Semibold, demibold
FA_BOLD | 11200 | Bold
FA_EXTRABOLD | 12800 | Extrabold, ultrabold
FA_HEAVY | 14400 | Heavy

Note the difference between the FA_xxx symbols used here, and the similar FW_xxx symbols used by the //SETFONT GDI printing directive; the FA_xxx symbols are shifted up 4 bits (16 times) from the FW_xxx symbols.

When associated with a real column, the font defined affects just that column. When associated with a pseudo column (i.e. with cwidth = 0) it just serves to define the font so that it can be referred to by data in a font definition column for applying specific fonts to individual rows (see cformat f in the table above). Also see Scale and Default Font.


Format

Format=<format string>{| <style flags>}

The Format clause provides a way to configure the behavior of the Windows Time and Date Picker control associated with an editable date and/or time column. The clause is local to the column, and thus allows different date editing options for different columns (unlike the InfDef clause, which only allows the option of activating the Time and Date Picker for all columns).

Whenever there is a Format= clause defined for an editable date or time column, the date/time picker control will be used instead of the regular edit control.

The <format string> is made up of the following special characters/fields; any other characters are treated as literals:

Symbol | Meaning | Symbol | Meaning
d | one or two digit day | dd | two digit day (zero padded)
h | one or two digit hour in 12-hour format | hh | two digit hour in 12-hour format
H | one or two digit hour in 24-hour format | HH | two digit hour in 24-hour format
m | one or two digit minute | mm | two digit minute
M | one or two digit month number | MM | two digit month number
t | one letter AM/PM abbreviation | tt | two letter AM/PM
y | one or two digit year | yy | two digit year
yyyy | full four digit year |  |

The optional <style flags> (separated from the <format string> by a "|" character) may be expressed as the sum of one or more of the following options:

Symbol | Value | Meaning
MCS_WEEKNUMBERS | 4 | The month calendar displays week numbers (1-52) to the left of each row of days
MCS_NOTODAYCIRCLE | 8 | The month calendar does not circle today’s date
MCS_NOTODAY | 16 | The month calendar does not display today’s date at the bottom of the control
MCS_NOTRAILINGDATES | 64 | (Vista+) Dates from the previous and next months are not displayed in the current month’s calendar
MCS_SHORTDAYSOFWEEK | 128 | (Vistat+) Short day names are displayed in the header

For example:

Coldef = "1~15~Date/Time~DE~Format=dd/MM/yyyy HH:mm|24~~"

The contents of that column should then look something like this:

08/15/2009 13:21

And the drop-down calendar would neither circle today’s date nor display it at the bottom of the control (due to the style flags combination of 24, i.e. 8 + 16).

Note that in columns containing both time and date, you should use the Cformat code D but not h. (Use h only when the column contains only a time.)

Note that XTREE parses the data in date cells based on the order of the day and month in the Format= clause, rather than on the local LDF setting. This should eliminate problems confusing and/or reversing the day and month when a date cell transitions between display and edit mode (since the transition requires that the cell's text contents be parsed into the sub-fields used by the date picker).

Warning: if you supply date/time data in a format that doesn't match the defined format (including blank data) OR isn't compatible with IDTIM.SBR, the date/time picker will not be able to interpret your data. In such a case, if your InfDef clause contains "O" (for optional), the date/time picker will most likely replace your bad or empty data with the current date/time. Unfortunately this limits the format flexibility otherwise provided by the Format clause. (Future enhancements may allow for some additional time/date formats, but for now you are pretty much limited to numeric date format with slash or dash delimiters. If you need more flexibility than that, stick with the regular edit mode for dates.)


HdrClickExit

HdrClickExit=###

When specified, clicking on this column header causes an exit with the specified exitcode. It returns the XTR'COLUMNSORT and XTR'SORTORDER fields as if a sort had taken place, but it doesn't actually sort.

The intent is to allow applications to implement their own sort logic.

Note that when HdrClickExit=### is defined for a column, that column will not be sorted on entry even if the column appears in the initial XTR'COLUMNSORT array. If you want subsequent clicks on the column header to toggle between ascending and descending, you must leave the XTR'COLUMNSORT set to the specified column on re-entry. Otherwise the initial sort for any unsorted column will always be ascending.


HdrFont

HdrFont=<facename>, <attribute code>

Same format, syntax and concept as Font, except that it affects the font of the header row, rather than the data items. By convention, you would define the HdrFont as part of a pseudo column (i.e. a column whose cwidth = 0) but, regardless of which column this command appears in, it affects the entire header. Currently there is no way to have different fonts in different column headers. If more than one column specifies a Hdrfont, only the last one will have an effect.

Coldef Default applies.


ImgSiz

Specifies the maximum image size, along with the desired image depth and scaling options.

ImgSiz = iwidth, iheight, bpp {,Fit, Stretch, Scaleq, Discrete}

iwidth and iheight are numeric pixel counts for the maximum size image. If the XTF_VARY bit is not set in the flags parameter, then all images must be the same size. (In this case, XTREE will create an "image list" internally, which is the most efficient way to handle a lot of images.) Otherwise, the row height will vary with the actual image height, up to the maximum specified.

bpp specifies the desired bit depth (bits per pixel), which is used as a clue to the various image loading, conversion, and display routines. Supported values are 1, 8 and 24. If in doubt, set it to 24, which will give the best visual results (at a possible cost in memory usage). With 8, you may some color substitutions leading to a posterization effect. With 1, you would get monochrome.

The Fit and Stretch options apply only when the row height (and image size) is variable (i.e. the XTF_VARY bit is set in the flags parameter). Fit causes images that are smaller than the maximum size to be enlarged until they hit the maximum width (iwidth) or height (iheight). Stretch is similar but stretches the images as needed so that they match both the iwidth and iheight. (When XTF_VARY is not specified, the Stretch option is automatic.)

The Scaleq option selects a scaling algorithm (bilinear interpolation) which is somewhat slower but generally gives higher quality results than the default scale algorithm.

The Discrete option causes the images to be stored individually rather than as an internal "image list". This is mostly just a subtle technicality, but is required for icon images when the XTF_VARY option is not specified.

Examples:

ImgSiz=133,100,24,Fit

ImgSiz=75,50,8,Stretch,Scaleq

ImgSiz=16,16,24,discrete


ImgCount

Updated August 2010

ImgCount=<# images to load>, <grow-by value>

Specifies the number of images to be loaded into the XTREE, along with a "grow by" value which is a clue to the image list allocation routine but can generally be ignored (or set to 1). The image count would normally be the same as the maximum number of rows, unless you knew that many rows would not have images. Example:

ImgCount=100,1

History

2010 August, A-Shell 5.1.1189: The "grow-by" value is now automatically adjusted upwards according to usage. Previously, if it was set to 1, and the actual number of images was more than the initial count parameter, it would resize one of the image-related buffers for each new image, resulting in a lot of memory trashing.


ImgDir

ImgDir=dirspec

Specifies the default directory for the images, allowing you to avoid having to specify the complete directory redundantly for each image. The directory may be specified using either AMOS or native (Windows) syntax. ImgDir is ignored if blank, not specified, and for any individual image file name that contains a directory specifier. For example:

ImgDir=appimg:

ImgDir=c:\my documents\my images\app images

An example of a complete image column definition:

COLDEF = COLDEF + "50~25~Images~I~ImgSiz=80,60,24,Fit,Scaleq~ImgCount=150,1~ImgDir=appimg:~~


InfDef

Updated March 2013

Beginning with A-Shell 1104 of 18 Feb 08, the advanced column option InfDef=xxx opens the door to the ability to specify some variations of XTREE editable cell behaviour using INFLD TYPE codes. Currently this only applies globally for all columns in the tree, and only the following TYPE codes are supported:

Type | Description
) | start cursor at end of field, requires e
2 | When cursor is at the start of a field, left arrow navigates to the previous editable cell.
D | In conjunction with a date field (cformat D), causes the field to be edited by the standard Windows Date and Time Picker control, rather than by the standard Windows edit control. See Comments below and also see Format.
e | force non-destructive
||I | Forces overwrite mode during editing (instead of the normal insert mode). You most likely would want to use this feature in conjunction with non-destructive mode (InfDef=||Ie), particularly when FastMax=# is being used. Note that ||I is the INFLD code to force overwrite mode.
|L | Regardless of cursor position within the field, right arrow navigates to the next editable cell.
L | When cursor is at the end of the field, right arrow navigates to next editable cell.
O | Indicates optional field. Mainly of use with dates and times (e.g. InfDef=DO) to add a checkbox to the Date and Time Picker to allow it to be optional.
t | In conjunction with a time field (cformat h), causes the field to be edited by the standard Windows Date and Time Picker control, rather than by the standard Windows edit control.

For example:

Coldef = "1~8~Date~DE~InfDef=D~~"

Note that the InfDef clause is shared by all columns, so this method forces you to treat all editable date and time columns the same way.

In the above example, since the column width is 8, the format will be set to MM/DD/YY (or DD/MM/YY depending on the LDF). Otherwise the year would be returned in CCYY format.

The other method for activating or configuring the date/time picker control is to specify a Format clause.

Comments

Warning about date picker column width: For Windows Vista and later, the width of a column using InfDef=D will be automatically expanded as needed to fit the Windows date picker control (when a cell in the column is edited). But prior to Vista, this does not happen, and worse, if the column width is not sufficient for the date picker, the editing operation may be confusing at best. To avoid this, you may want to specify a DspMin option sufficient to accommodate the date picker. (You'll have to work out the actual minimum width using some trial and error, and/or err on the conservative side, since it changes according to the date format options specified, resolution, etc.)


List

Used in conjunction with cformat code l to define the choices that will appear in the combo box.

List=item1, item2, ...itemn

As a convenience for applications sharing a list with INFLD, you can use the INFLD setdef syntax, which is the same as the above, except that the first character specifies the delimiter character, which is then used to separate the items. In the INFLD format, the list is typically terminated with two of the delimiter characters, although they aren't really necessary here since the list will be terminated by the tilde that marks the end of this and every other advanced coldef option.

Comments

• Warning: if the first character is neither alphabetic nor numeric, and it matches the character in the list, then XTREE assumes that it is the delimiter character. Otherwise, the delimiter is assumed to be a comma. This can lead to unexpected problems in lists of items that have both leading and trailing spaces—or any other non-numeric, non-alpha character. To avoid that possibility, make the delimiter explicit.

• For self-service combos, set the list to three dots (e.g. List="..."). You can still pre-load the cell with a value, and even allow the user to change it (if the E code is specified). But if they try to display the dropdown list (by clicking on the down arrow button or typing Alt+DownArrow, it will exit with Exitcode= 29, so that your application can then display its own list or other control, independent of XTREE.

• The INFLD "List substitution" (type ||L) format is supported via ListX and CellListX.

• For selection-only lists (where the user can only select from the items in the list, as opposed to real combo boxes where a new item may be entered), do not include the E code in cformat. To allow a blank choice in such a case, you must add an explicit blank item to the list definition, i.e. "List=red,blue, ~". Also note that any pre-loaded cell string must match an entry in the list, or else it will be displayed as blank when the cell becomes activated—i.e. turned into a combo box.

• If the List= clause is associated with column 0, it can be shared by multiple columns. Any column which specifies the cformat l (list) option, which does not have its own List= specified, will use the shared list associated with column 0. Note that although this capability overlaps somewhat with the CellList feature when it comes to sharing a single list between multiple columns, List= is easier to use because it doesn't require a special character in every cell to identify the list. But List= lacks the flexibility to allow different lists within the same column.

• To mark an individual cell within a combo box column as being non-editable, insert a vertical bar ("|") as the first character of the cell data. The vertical bar will not display, but the cell will be prevented from gaining the focus.

• There is no limit on the length of an individual combo list (defined with List= or CellList=). A 4K limit in an earlier version of A-Shell has been eliminated.

• See CellList for defining cell-specific combo lists.

See Also

• "Dropdown lists" Mouse and Keyboard.


Mask

Define a numeric formatting mask.

Mask=mask

Supports the same numeric mask options as the BASIC USING clause (e.g. "$###,###", "##.##", "#ZZZZ"). The mask is applied immediately before loading data into each cell, and again just prior to and after editing a cell (if the cell is editable). Note that:

Notes

In most cases, you will want to also specify the column format code > to cause the formatted data to be right-justified in the cell.

Although each column can have a separate mask, the total (combined) amount of mask storage is limited to 1024 characters.

If you want zero values to show as blank cells, rather than formatted according to the mask, set the cformat for the column to string ("S") rather than to numeric ("#").

Examples

Mask=$###,###.##

Mask=#ZZZZZ

Mask=###.##

History

A-Shell 5.1.1107.4 of 12 Apr 08: The new NegFgBg allows control over the color used to display numeric cells with negative values.


NegFgBg

Added April 2008

This parameter allows control over the color used to display numeric cells with negative values:

NegFgBg={fgidx, bgidx}

Examples:

NegFgBg=A

NegFgBg=A,B

NegFgBg=

By default, the foreground color is set to Red. If the above clause is added to the real column definition, or to the Pseudo Column Zero, then the specified fgidx (and optional bgidx) codes will be used to reference previously defined RGBfg or RGBbg definitions by their index codes.

For example:

COLDEF = "0~0~x~H~RGBfg=50,255,80,A~RGBbg=200,60,240,B~~1~10~Amounts~#~NegFgBg=A,B~~"

In the above case, the NegFgBg=A,B clause tells XTREE to display negative cells in the specified column using the foreground RGB color defined with index A (RGBfg=50,255,80,A) and the background color define with index B.

If the optional {,bgidx} background color is not specified, then XTREE uses the default.

If no argument is specified (i.e. NegFgBg=), then the automatic red display of negative numbers is merely disabled; in other words, negative numbers are treated just like positive numbers.


PopupMenu

Updated March 2013; see History

Defines a popup menu (aka "context menu") that will appear when the user right-clicks on a cell. You may define a single popup menu to be used by all columns, and/or you may define popup menus that are specific to individual columns. A PopupMenu definition consists of a series of pairs of text/cmd items with the following syntax:

PopupMenu = text1, cmd1; text2, cmd2;...; textN, cmdN

The <text> fields define what appears on that line of the popup menu, while the <cmd> fields define the key sequence that is transmitted if the user clicks on the option. See Virtual Key Symbolic Names. Also see Notes below for information on certain built-in special menu commands.

To create a horizontal separator bar, set the <text> field to a string of dashes and leave the <cmd> field null (with no spaces between the dashes, the comma, and the semicolon.).

For example, consider this PopupMenu definition:

COLDEF = COLDEF + "0~0~X~S~PopupMenu=Retire,VK_xF101;Visit,VK_xF102;Pass Through,VK_xF103;-----,;Attack,VK_xF104~~"

This would create a popup menu, which, when the XTREE control was right-clicked, would display four choices (Retire, Visit, Pass Through, and Attack) with a horizontal separator between the last two items (in a particularly feeble ergonomic effort to prevent inadvertent war). If the user then clicked on one of the items in the popup menu, XTREE would exit, setting exitcode to -101, -102, -103, or -104 depending on the item. The effect would be exactly as if you had defined buttons which transmitted the same key codes. Here's what it might look like:

In addition to the exitcode, the XTR'TARGETROW / XTR'TARGETCOL and/or XTR'XROW / XTR'XCOL fields in the Xtrctl parameter will be set to indicate the logical row and column where the right-click occurred.

The popup menu defined above would be available to all columns because it was associated with the pseudo column zero (Cpos, Cwidth both set to 0). To define a popup menu that is specific to a column, just associate the PopupMenu specification with a real column, as in these two examples:

COLDEF = COLDEF + "50~15~State/Province~S~PopupMenu="+-----,;Run for Governor,VK_xF105;Check State Tax Rates,VK_xF106;Find State Capitol,VK_xF107~~"

COLDEF = COLDEF + "70~12~Country~S~PopupMenu=Obtain Passport,VK_xF108;Recall Ambassador,VK_xF109~~"

The first of the two column definitions above creates a column titled "State/Province" which has its own popup menu items that are appended to the shared popup menu—i.e. the one defined previously for pseudo column zero. The special character "+" at the start of the PopupMenu definition string is what causes the items to be appended to the shared popup menu rather than replacing it. Here's what the menu would look like:

The second definition creates a column titled "Country" with a popup menu containing two items. Because the definition is for a real column and does not start with the special character "+", it replaces the shared popup menu entirely, resulting in something like this:

Notes

Disabling individual menu items may accomplished by marking them as disabled with a "!" at the start of the item text, i.e.: PopupMenu=!disabled item,VK_xF999; ... See History.

Context menus: Context menus may specify icons. See History, below, and the subtopic Icons.

Updating Popup Menus: On re-entry into an existing XTREE, the PopupMenu definitions are reprocessed for opcodes XTROP_CREATE (0) and XTROP_REPLACE (1), but not for XTROP_SELECT (4). So to modify the popup menu(s) in response to some user input, you must exit from XTREE back to the application, modify your complete coldef definition string, then re-enter with XTR'OPCODE = XTROP_REPLACE. If you want the application to have the opportunity to update the popup menu, before displaying it, whenever the user right-clicks, use ClickExit to define a right-click exitcode. This will override the PopupMenu. Then use the ability to force the popup to display immediately on entrance, as described below.

Forcing Popup Menu to Appear Automatically: You can force a popup menu to appear immediately on entrance to XTREE by setting XTR'XNAVMASK to 64. The position of the mouse will determine which column the popup menu will be requested for. This is the one case where PopupMenu will override ClickExit.

Special menu commands: In addition to the standard kind of menu commands which are made up of literal or symbolic key sequences, certain commands are built-in and recognized by XTREE:

$RESETCFG

Resets the saved column configuration to the default state. This is useful to deal with the possibility of a user accidentally making a disastrous change to their configuration, such as resizing a column to zero width, thus making it disappear entirely. See Saving User Adjustments. For example:

COLDEF = "0~0~x~H~PopupMenu=Reset columns,$RESETCFG~~"

$RESETCFG also resets the text scale adjustment factor—i.e. includes $RESETSCALE. See History.

$CBSET{DEP}

$CBRST{DEP}

$CBUNDO

The above special context menu commands relate to extended Editable checkbox columns, which see for details.

$COPY

Copy to Clipboard the contents of the tree

$EXPCSV and $EXPTSV

Export the contents of the tree to a delimited file

$PRINT

Print the contents of the tree to a delimited file

$RESETSCALE

Resets the overall text scale adjustment factor back to zero; equivalent to Control /.

$SCALE+ and $SCALE-

Causes the fonts to be increased (+) or decreased (-) by about ten percent; equivalent to Control + and Control -.

$SRCHCOL and $SRCHALL

Provide expanded Search options

History

2017 January, A-Shell 6.3.1542: (1) Individual menu items may now be marked as disabled. (2) Sub-menus now supported. (3) Indexed popup menus now supported.

2013 July, A-Shell version 6.1.1357: Added ability to include icons in context menus

2013 Feburary, A-Shell version 6.1.1338: A-Shell now automatically adds "Paste Special" to the context menu when complex clipboard formats are available. Depending on the formats, the menu option will open a submenu with more specific paste options, such as picture, spreadsheet, etc. To customize the wording of the menu option, add or modify the 004,011 message in the SYSMSG.xxx file. All SYSMSG.xxx included in the release package have been updated with rough translations. Note that if you don't want this capability, you can disable it by setting the TXMF1_EDIT_PASTESP (&h00400000) flag in the TXC'MENUMASK1 field.

2010 July, A-Shell 5.1.1188: Added $SCALE+ and SCALE-.

2010 June, A-Shell 5.1.1185: Added $RESETSCALE.

Subtopics

PopupMenu Sub-Menus

Indexed PopupMenus

Export

Search

Print

Copy to Clipboard

Icons


PopupMenu Sub-Menus

Subroutines > XTREE > XTREE Parameters > Coldef > Advanced Coldef Options > PopupMenu

PopupMenu Sub-Menus

Added January 2017

Beginning with A-Shell 6.3.1542 of January 2017, the XTREE PopupMenu supports sub-menus. The syntax is the same as for Hover/Context menus, i.e. set the cmd field (of the text,cmd; menu item pair) to "[SUB]" to mark the beginning of the submenu, and the text field of a subsequent item to "[ENDSUB]" to mark the end of the submenu. For example:

coldef$ += "0~0~ ~SH~PopupMenu=" &

+ "!Retire\tF2,VK_xF501;" &

+ "|arrow_right_green::ashico1|Peacetime,[SUB];" &

+ "|photo_portrait::ashico1|Visit\tF3,VK_xF502;" &

+ "|signpost::ashico1|Pass Through,VK_xF503;" &

+ "[ENDSUB],;" &

+ "-----,;" &

+ "|gear::ashico1|Wartime,[SUB];" &

+ "Attack,VK_xF504;Lay Siege,VK_x507;" &

+ "[ENDSUB],;" &

+ "-----,;" &

...

The codeabove defines a PopupMenu which looks something like this:

Retire F2 (disabled item)

Peacetime (submenu with icon)

Visit F3 (submenu item with icon)

Pass Through (submenu item with icon)

--------------------- (separator)

Wartime (submenu with icon)

Attack (submenu item)

Lay Siege (submenu item)

--------------------- (separator)

...


Indexed PopupMenus

Subroutines > XTREE > XTREE Parameters > Coldef > Advanced Coldef Options > PopupMenu

Indexed PopupMenus

Added January 2017

Beginning with A-Shell 6.3.1542 of January 2017, an enhancement to XTREE provides support for indexed PopupMenus. These allow for column- and/or row- specific context menus to be assembled by concatenating one or shared partial indexed menus. To accomplish these three new variations of the PopupMenu syntax are introduced:

PopupMenu:?=lbl1,cmd1;lbl2,cmd2;...lblN,cmdN

PopupMenu={+}?{???}

PopupMenu={+}###

where each ? is replaced by an alphabetic character A-Z, and ### is replaced by a column number.

The first variation defines a full or partial menu to be indexed by the letter replacing ?. The definition can be attached as an Advance Coldef Option clause to any column definition (zero column or a real column). Unlike the standard PopupMenu definition syntax, the resulting menu is not automatically invoked; it only becomes available for reference via one of the other syntax options associated with a real column.

The second variation may be associated with a real column, indicating that the context menu for that column should be made up of the previously indexed menus associated with the ? character(s). The optional "+" prefix prepends the global PopupMenu to the start of the column-specific menu. For example:

PopupMenu=+AQZ

indicates that the context menu for the column should be made from the global PopupMenu, combined with the indexed PopupMenus A, Q, and Z.

The third variation indicates that the specified column ### (current row) contains the list of indexed PopupMenus to be used for this column, thus allowing the possibility of a different set of context menu items for each cell. Note that the specified column ### would normally be hidden, but it doesn't have to be.

See the EXLIB sample program XTRA21 for an example.


Export

Subroutines > XTREE > XTREE Parameters > Coldef > Advanced Coldef Options > PopupMenu

Export

Updated April 2013; see History

These two PopupMenu system commands are used to export the contents of the tree to a delimited file:

$EXPCSV

$EXPTSV

The first exports the tree to CSV, the second to a tab delimited file (i.e. Tab Separated Values). To automatically open the file after exporting (i.e. to launch your registered spreadsheet program), append "+" to the $EXPCSV or $EXPTSV options, e.g.:

$EXPCSV+

$EXPTSV+

As an alternative to adding explicit export options to each XTREE, you can enable them globally by adding one or both of the following to the miame.ini:

SBR=XTREE_EXPCSV

SBR=XTREE_EXPTSV

To globally set the option to launch after exporting, add the following:

SBR=XTREE_EXPOPEN

The text for these automatically-added context menu options will be taken from SYS:SBRMSG.xxx lines 026,001 and 026,002, which default to the following (for the English version):

026,001,Export (CSV)

026,002,Export (Tab Delimited)

So the above three SBR= commands would be equivalent to adding the following PopupMenu clause to the zero column of each tree:

"PopupMenu=Export (CSV),$EXPCSV+;Export (Tab Delimited),$EXPTSV+"

Note that whenever a PopupMenu option containing a command string starting with "$EXP" appears explicitly in an XTREE definition, the corresponding global options will be ignored for that tree. (This allows you to customize the global option in particular cases and eliminates the problem of redundant menu options in programs where you already implemented the option explicitly.)

You can also disable the global option by adding a dummy PopupMenu item with a "-" in front of the $EXP... command, e.g.

"PopupMenu=xxx,-$EXPCSV"

The description field ("xxx" in the above example) is ignored (since the whole point of the "-$EXPCSV" is to remove the corresponding item from menu).

History

2013 April, A-Shell 6.1.1350: CSV export now uses the list separator defined in the regional/locale settings, rather than comma. And the default file extension for TAB export is now CSV.

2013 April: A-Shell 6.1.1349: Hidden columns are no longer included in the export. This refers to columns that either have the H cformat flag, or which have been reduced to zero width. Columns that are simply scrolled out of view are not considered hidden.

2012 December, A-Shell 6.1.1326: Function added to A-Shell


Search

Subroutines > XTREE > XTREE Parameters > Coldef > Advanced Coldef Options > PopupMenu

Search

Added December 2012

These two PopupMenu system commands are used to provide expanded search options:

$SRCHCOL

$SRCHALL

Both options pop up a standard Windows "Find" dialog in which you can type in the string to search for and check a couple of search related options. $SRCHCOL searches just the column that was right-clicked to bring up the context menu, while $SRCHALL searches all columns of the tree.

To add these search options globally, add the following to the miame.ini:

SBR=XTREE_SRCH

The text for the corresponding automatically-added context menu items will be taken from the SBRMSG.xxx messages 026,004 and 026,005, defaulting to:

026,004,Search Column

026,005,Search All (^F)

The concept here is the same as for the $EXP options previously described. Any explicit definition of a PopupMenu command starting with $SRCH will disable the appending of the automatic options, allowing you to customize the search options on a tree-by-tree basis. You can also disable a globally enabled search by defining an option with the command "-$SRCH", e.g.

"PopupMenu=xxx,-$SRCH"

Note that the search logic normally only matches at the start of each cell (not counting leading spaces). But if you select the "Whole Word only" option in the search dialog, it will match the whole word anywhere in the cell contents.

Also note that as currently implemented, the search operation selects the entire item that the match occurs on, and also makes that column the active one (i.e. depresses the column header button). It does not highlight the cell, out of concern for possible confusion and conflicts with various editable cell configurations.

History

2012 December, A-Shell 6.1.1326: Function added to A-Shell


Print

Subroutines > XTREE > XTREE Parameters > Coldef > Advanced Coldef Options > PopupMenu

Print

Added December 2012

Print,$PRINT

Selecting this option is equivalent to using the XTROP_PRINT opcode, except doesn't require exiting the current tree operation.

To globally add the option to all trees, add the following to the MIAME.INI:

SBR=XTREE_PRINT

The text for the automatically-added menu items is taken from SBRMSG.xxx message 026,003, which defaults simply to:

026,003,Print

If globally enabled, you can disable it by adding the following item to an explicit PopupMenu definition:

PopupMenu=,-$PRINT

History

2012 December, A-Shell 6.1.1326: Function added to A-Shell


Copy to Clipboard

Subroutines > XTREE > XTREE Parameters > Coldef > Advanced Coldef Options > PopupMenu

Copy to Clipboard

Added April 2013

This function provides support for copying selected items to clipboard. To add an option to the context menu to copy selected items to clipboard, add an entry to your PopupMenu containing the new $COPY special command, e.g.

PopupMenu=Copy to clipboard,$COPY~~

Note: this is now automatic when the SBR=XTREE_EXPTSV flag is specified in the miame.ini.

To support the Windows standard keyboard command Ctrl+C to copy the selected items to the clipboard, specify the new flag XTF2_CTRLC_COPY (&h00100000).

Note that in order to copy more than one item to the clipboard, the tree will need to support multiple selections (XTF_MSEL); otherwise only the current item will be copied. Also note that hidden columns are not included.

History

2013 April, A-Shell 6.2.1349: Function added to A-Shell


Icons

Subroutines > XTREE > XTREE Parameters > Coldef > Advanced Coldef Options > PopupMenu

Icons

Added July 2013

Context menus, defined with PopupMenu=, may specify icons, using the same syntax as for AUI_MENU, i.e., by prepending an image specification clause enclosed in vertical bars to the menu text string.

PopupMenu={|imgspec{=size}|}text, cmd; ...

For example:

PopupMenu= "|refresh::ashico1|refresh data,VK_xF502;" + "|delete.png=16|delete item,VK_xF503;" ...

As with AUI_MENU, when no {=size} clause is present, the system default menu icon size will be used (typically 16). Older versions of Windows may also limit the size to 16x16, while newer versions allow 24x24, 32x32 and beyond.


Radio Button Group

Group=###

Associates radio button cells within the current column with a specific radio button group, so as to allow more than one group of radio buttons in a row, or even a set of related cells in the same column to form a group. ### is the group number, 0-252. Columns without a Group= clause are assigned group 0. Groups 253-255 are reserved for vertical groups:

Group | Description
255 | Entire column is a single group
254 | XTF_MLVL: Items with same immediate parent form a group
253 | XFF_MLVL: Items at same level form a group

If the tree is not multi=level, all three of the above act like 255, i.e. only one radio button in the entire column can be selected at a time.

Note that as with horizontal groups, enforcement of the only-one-selected-per-group rule occurs only when you change a radio button during editing. It is up to the application to enforce the rules during loading and display operations.


RGBbg

RGBbg may be used to define precise background colors to be used for columns, rows, or individual cells, as in this example:

If the RGBbg option is specified on a real column definition, then it determines the background color for that column. Otherwise (if specified for Pseudo Column Zero) then it may serve as a way to define a color which will later be referenced by its RGB color index. The syntax is:

RGBbg=r, g, b {,index}

Where r, g, and b are decimal values in the range of 0-255. The optional index is an alphabetic character in the range of A through Z (the RGB color index) provides the means to reference this color for a row or cell.

RGB color specifications can be difficult to visualize, so you may want to take advantage of the A-Shell Settings | Colors dialog which provides a visual tool that displays the RGB values for color samples chosen from the entire color space. (Click on any color in the first part of the dialog, then click the Define Custom Color button. Just cancel once you've found a set of suitable RGB values.):


RGBfg

RGBfg=r, g, b {,index}

RGBfg has the same syntax and semantics as RGBbg except that it defines a foreground (text) color rather than a background color. The screen shot under RGBbg shows a custom foreground color for the first column.

Originally, row colors (see Cformat C and c) were drawn only from the A-Shell palette, and identified by the palette index numbers 0-15. As of build 955, you can define a custom color using RGBfg or RGBbg on the RGB color index and then use it for a row foreground color by specifying the RGB color index.


RGBfgSel and RGBbgSel

RGBfgSel=r,g,b

RGBbgSel=r,g,b

These determine the foreground and background color used to display the selected row(s) in the specified column. The default selection color is white for the foreground and blue for the background. Changing the default color is sometimes useful, either to make selected items stand out against highly colored cell patterns, or conversely, to make selected items blend into the background. The latter is sometimes useful in conjunction with editing, where you might otherwise get an annoying "flash" as the tree switches between cell editing and selection modes.

Also see the Xtrctl table for the parameters XTR’NFSELSTYLE and XTR’SELECTAREA.


Headers and Totals Colors

Beginning in A-Shell 5.1.1123 of 01 Sep 08, four new parameters RGBbgTotals, RGBfgTotals, RGBbgHeaders, RGBfgHeaders are available.

They all take the argument =r,g,b, and their purpose is to establish the base colors for the special data lines at the top and bottom of the tree which have been flagged as headers or totals.

Note that totals line(s) are defined via the XTF_TOTALS flag and/or TotalLines=# coldef parameter; headers lines are defined by the HeaderLines=# coldef parameter.

Also note that "header" lines defined via HeaderLines=# should not be confused with the real column headers, which are not data lines at all and which do not have adjustable colors. The header lines we're talking about here are just data lines that have been designated "headers" so that they remain at the top, regardless of sorting.


ScrollMode

The coldef clause ScrollMode=Tree may be used in conjunction with combo boxes (List=) to cause ordinary Up/DownArrows to move the focus to the previous/next row, rather than to the previous/next item in the list. In other words, it causes ordinary Up/DownArrows to act the same as Ctrl+Up/DownArrows. It also affects ordinary Left/RightArrows in selection-only combo boxes (where they normally act just like up/down).

The intent of this obscure (and somewhat non-standard) 'feature' is mainly to minimize the possibility that users might accidentally change cell values when they were intending to just "arrow around" the grid. (This is much more likely within XTREE, where ordinary cells may turn into combo boxes when they get the focus, than with "normal" combo boxes that may appear in dialogs.

Note that in all cases, when the drop-down list is displayed (via Alt+DownArrow or clicking on the drop-down button), the arrow keys will operate within the list (so it doesn't interfere with the ability to perform all the necessary combo box functions without using the mouse).

The Mouse Wheel operation is similarly affected by the ScrollMode=Tree clause.

As of 5.1.1174, ScrollMode=Tree also affects the operation of XTF_UP and XTF2_DOWN (affecting both editable and non-editable contexts).

Once a ScrollMode command is encountered in the coldef string, it becomes the default for any editable columns subsequently defined. The last encountered ScrollMode statement will determine the behavior in non-column-specific contexts (such as in using the Up/DownArrows in non-editable contexts).

ScrollMode=Tree may be associated with column 0 to make it the default for all columns (rather than having to do it individually for each column containing combos).


CellList

Using this option, shared lists (combo boxes) can be associated with individual cells rather than just entire columns. To implement, first define one or more lists (associated with column 0) using the CellList option:

CellList=id, item1, item2, ...itemN

The format of CellList is identical to List except that it must begin with a single lower case letter, a-z, which serves as an identifier for the list (allowing up to 26 lists to be defined).

To associate one of the predefined lists with a cell, use the cformat code "s" to define the column as being capable of referencing the lists. cformat "s" is similar in concept to B (background cell color) in that it reserves the first character of each cell in the column for the index letters that associate the cell with one of the predefined lists.

Notes

• In addition to the index letters (a-z), which associate the individual cell with a pre-defined list, you can also use the following codes to make the cell non-editable, or to treat it as a normal editable cell.

Code | Description
a-z | ID of a CellList (or CellListX)
| | Marks the cell as display-only. (The remaining characters in the column will be displayed in the cell)
* | Causes the cell to be treated as a normal edit (rather than combo list)
# | Same as * but limited to numeric digits only

• If the column also uses cformat B, then the first character of the column is for the cell color code, and the second character will be for the CellList ID.

• As with cell background colors, the byte reserved for the CellList ID must also be accounted for in the answer array.

• There is no limit on the length of an individual combo list (defined with List= or CellList=). A 4K limit in an earlier version of A-Shell has been eliminated.

• The sample program XTRA5C illustrates some of these variations.


ListX and CellListX

XTREE supports list substitution style (aka INFLD ||L) combo lists via the new ListX= and CellListX= clauses.

ListX = <code>, <descr>, <code>, <descr>,...

CellListX = <idx>, <code>, <descr>, <code>, <descr>,...

e.g.

ListX=1,UPS Ground,2,UPS BLUE,3,Fed Ex,4,Mail"

CellListX=c,AL,Alabama,CA,California,LA,Lower Alabama~~"

ListX and CellListX are just like List and CellList, respectively, except that the list of items consists of <code>,<descr> pairs, where the <code> is what you store in your application (and in the data and answer arrays) while the <descr> is what displays in XTREE. The concept and implementation is essentially the same as the INFLD ||L "list substitution" field type.

See sample programs XTRA5 and XTRA5C in the EXLIB for examples of using these clauses. Also see "Dropdown lists" Mouse and Keyboard.

Also: the following note—see List for others—is deemed sufficiently important to repeat here:

• Warning: if the first character is neither alphabetic nor numeric, and it matches the character in the list, then XTREE assumes that it is the delimiter character. Otherwise, the delimiter is assumed to be a comma. This can lead to unexpected problems in lists of items that have both leading and trailing spaces—or any other non-numeric, non-alpha character. To avoid that possibility, make the delimiter explicit.


Print

Added January 2016

Print=Disabled

This option was introduced to help solve a problem. Previously, specifying the -$PRINT PopupMenu option was removing the print option from the popup menu, but it was not disabling the ability to print/preview using the built-in ^P command. To disable that, this Advanced Coldef Option has been added.

Note that it doesn't really matter what follows the = sign; the only option is to disable, since the default is for printing to be enabled.

History

2016 January, A-Shell 6.2.1423: Added to A-Shell.


SelChgExit

Updated March 2010

SelChgExit=###

This option causes XTREE to exit with exitcode -### whenever the selection changes—i.e. by moving it with the up/down arrows or by clicking on a new row.

This feature can be handy in certain kinds of trees where you want to update some display items as soon as the user moves the selection bar, but beware of conflicts with the following modes and options:

• edit mode (moving from cell to cell might trigger the "selection changed" event, interfering with the normal cell validation logic.)

• XTF_FAST mode (it isn't clear which would take precedence in the case of a single click).

• Context menus (if the user right clicks on a row other than the one currently selected, the change of selection event may or may not preempt the context menu.) (If it does preempt it, you might be able to re-enter immediately and continue though.)

• ClickExit (again, it isn't clear which event will occur first.)

History

2010 April, A-Shell 5.1.1177: When the selection is changed by keyboard action, the exit is delayed (1/3 second by default). This eliminates the situation where the user wants to jump from, say, row 5 to 10, but instead of clicking on row 10, they use the DownArrow to scroll down. Previously, this would have exited on row 6, which was generally wasn't desirable. You can change the default delay by adding it to the end of the SelChgExit clause, separated by a comma:

SelChgExit=exitcode{,delay}~~~

Where exitcode is the numeric value of the exitcode to be generated on change of selection, and delay is the desired delay in milliseconds (default 333 milliseconds).

There is no delay when the selection is changed by clicking.

In the case of changing the selection via the keyboard search feature, the delay is increased by 1 second to allow the operator to more easily type the necessary characters to identify the desired item to be selected.


Tooltip

Added Feburary 2011

ToolTip=<tooltip text>

The limit on text size for any one tooltip is 1023 bytes.

For all trees excluding property sheets, the tooltip will display when the mouse hovers over the column header and the tree is not currently editing a cell. (During cell editing, the only tree-related tooltip that will appear is the tooltip for that cell.)

For property sheets, when not actively editing a cell, tooltips will display when the mouse hovers over a cell whose logical "column" has a tooltip. As with case above, during cell editing, the only tooltip display will be for the cell being edited.

Known limitations:

• Tooltips do not display while "editing" a checkbox or radio button cell.

• There is no way to associate a tooltip with row headers.

History

February 2011, A-Shell 5.1.1205: Function added to A-Shell


Title and Footer

Documentation reorganized and this section added May 2014

Title=<clause>

Footer=<clause>

Title is used as a page head and window title when using the XTREE print function.

Footer allows you to specify a page footer to be used when printing an XTREE through the print/preview mechanism.

Clause can be up to 128 characters. It supports one or two "|" delimiters to separate it into Left|Center|Right. If no delimiters, the text is used as the right title, and the default left title is the date. If one delimiter, it is treated as Left|Right. Clause also supports the following tokens:

Token | Description
%date% | Today's date using the current regional settings, short form.
%longdate% | Today's date using the current regional settings, long form.
%page% | Current page number.
%time% | Current time using the current regional settings short form (without seconds).
%total% | Total pages.


Advanced Syntax Example

To clarify the advanced form of the coldef syntax, consider this example:

COLDEF="0~0~x~H~Font=Playbill~~" ! row font #1

COLDEF=COLDEF+"0~0~x~H~Font=,2048~Scale=200~~" ! row font #2

COLDEF=COLDEF+"0~0~x~H~HdrFont=Times Roman~~" ! Header font

COLDEF=COLDEF+"0~0~x~H~HdrScale=150~~" ! Header scale

COLDEF=COLDEF+"1~1~x~fH~~" ! font column

COLDEF=COLDEF+"2~1~x~cH~~" ! color column

COLDEF=COLDEF+"3~15~PO #~SK~~" ! col 1

COLDEF=COLDEF+"18~10~Order"+chr(13)+chr(10)+"Date~D|~~" ! col 2

COLDEF=COLDEF+"29~12~Amount~#~Dspmin=6~~" ! col 3

COLDEF=COLDEF+"52~40~Notes~SMW3~RGBfg=240,20,50~~ ! col 4"

This defines four pseudo columns (for the purposes of defining two row fonts, a header font style and a header font scale), plus two special controls columns (font and color) which do not display but which do contain data, and four visible data columns.

Note that pseudo column definitions should start with "0~0~x~H~" (position 0, width 0, title "x", type "H"). The title and type specifiers do not actually matter, since the pseudo column is not displayed and contains no data, but they must be non-null, because two adjacent tildes marks the end of the column definition.

Of the visible data columns, the first is supplied by the character positions 3 through 17 of the data source records (array or file), has a title of "PO #", contains string data, (left justified by default) and may not be reordered. The second occupies positions 18-27 of the source data record, has a title of "Order Date" (broken into two lines), contains dates using the format mm/dd/yr (or dd/mm/yr, depending on the language definition), and is center justified. The third occupies positions 29-40 of the source records, has a title of "Amount", contains numeric data (right justified by default), and has a minimum width of 6 standard character cells. The last column comes from positions 52-91 of the source records, has a title of "Notes", contains string data, supports both explicit line breaks (embedded CRLF) and also auto-wrap based.. It also specifies a custom text color RGB(240,20,50). Note that the last column width will always be set to accommodate the longest cell data, so the auto wrap option wo not have any effect, unless the column is moved by the user (via drag and drop on the column header), in which case it can be resized and the wrap will have a significant effect.

Regarding the last column, note that because its definition starts in position 52 of the input data, while the previous column ended in position 40, the input data in positions 41-51 will be ignored (not loaded into the control, even in a hidden column). The display width setting of 20 refers to standard character cells (which are typically larger than the average proportional-font character width) so the column may display more or less than twenty characters for reach record. There is probably not much point in limiting it to twenty in this example, since it is the last column anyway. The only effect of the setting would be to limit how much screen space the column takes up when the control is scrolled all the way to the right. See the xtrctl XTR'ITEMLINES and XTR'TRUNCATED parameters and flags XTF_VARY, which affect how the column will deal with contents that does not fit in the display area provided.


Traditional Coldef Syntax

The traditional syntax applies to single-column lists and consists of an arbitrary string to be used as a title. Unlike the PCKLST prompt parameter, XTREE ignores any bottom prompt (which was specified in PCKLST by inserting a chr(13) in the string to separate the top and bottom portions.) Note that there is one important limitation on the contents of the string: it must not contain any groups of two or more spaces enclosed by non-spaces, since this is how XTREE distinguishes between the traditional and simple multi-column syntax.


Simple Multi-Column Coldef Syntax

The simple multi-column syntax allows simple multi-column lists to be easily defined for GUI mode, in a way that is backwards compatible with text mode. It consists of a simple string containing the column titles spaced to match the actual column spacing in array.

If the XTF_FCOLDEF bit is set in the flags parameter, then the coldef parameter is ignored and the first line of the input data is used in its place. (This is particularly convenient for simple multi-column file based data, since it allows you to keep the column titles with the data itself.)

In order to recognize that a word is the beginning of a new column and not a continuation of the previous column, it must be preceded by two or more spaces. For example:

MAP1 COLDEF,S,100,"Zip City State"

! 12345678901234567890123456"

The above code would define a three-column list. In order for this to work, the layout of the input data (either in array or the file) must match this layout. Note that one limitation of this method of defining the columns is that the actual column width in characters must be at least two columns wider than the column title. For example, if a column is to contain just a Y or N, but you want to display the title "Back Ordered?", then you would have to pad the column with about fifteen spaces to allow the column data to match up with the title string (unless this was the last column.) The Advanced Coldef syntax allow you to transcend this limitation.

The columnar interpretation of coldef presents a possible compatibility issue for existing applications counting on XTREE being upward compatible with PCKLST, namely that any prompt string containing alphanumeric (non-space) characters separated by two or more spaces would be interpreted as a multi-column definition in the new version. The chance of this happening, though, seemed remote enough (and in the case of text mode, harmless enough), that we decided it was reasonable to simply require you to remove the ambiguity in any existing prompt strings by eliminating the contiguous blanks if you are interested in using the GUI mode.


File Mode Coldef Extensions

In older versions of A-Shell, the coldef parameter was ignored in file mode when the XTF_FCOLDEF flag was set. Beginning in A-Shell 5.1.1115 of June 2008, the coldef parameter may be used in that situation to add to or replace the column definition in the file, and optionally to cause the first several lines of the data file to be skipped (i.e. so that header or other meta-data can be included in the file without being interpreted as data by XTREE). In order for the coldef parameter to be treated as significant (when XTF_FCOLDEF is set), it must begin with "+", "-", or "=". Syntax:

{-skipval}+<COLDEF string>

{-skipval}=<COLDEF string>

The optional {-skipval} clause, which must be first if present at all, is used to force lines of the data file to be skipped. If skipval is a number (e.g. "-5"), then XTREE ignores that number of lines at the top of the file (not counting the first line, which is interpreted as a column definition string due to the XTF_FCOLDEF flag). If skipval starts with a character other than 1-9, it is interpreted as a string label (31 chars max); data interpretation will start with the line in the file following the line that starts with the label string. (Warning: the label string should not include "+", "-", or "=".) For example, consider this file:

1~5~Zip~#~7~30~City Name~S~~

bla bla bla

bla bla bla

xtreedata:

06104 Belmont

00922 Puerto Nuevo

<etc>

The file contains a column definition string in the first line, followed by three non-data lines, followed by N data lines. To tell XTREE to skip over those non-data lines, you could set the coldef parameter to one of the following:

COLDEF = "-xtreedata:" ! skip until after "xtreedata:" label

COLDEF = "-3" ! skip 3 lines

Instead of, or in addition to skipping lines, you can also use the coldef parameter to append to, or replace, the column definition string in the file. To append, use "+" followed by a legal coldef definition string. Appending is useful when you want to add something non-data specific, such as a popup menu, which may depend on runtime application logic. To replace, use "=" followed by a legal coldef definition string. Replacement is probably most useful when you didn't really want to put the column definition in the file at all, but needed to in order to use the -skipval feature (since all of these special coldef parameter features discussed here require the XTF_FCOLDEF flag). Some legal examples:

! use column definition from the file, as is.

COLDEF = ""

! skip 3 lines (plus column def line), append popupmenu to col. def.

COLDEF = "-3+0~0~x~H~PopupMenu=Eat,VK_xF100;Drink,VK_xF101~~

! skip to "data:" label, replace col. def entirely

COLDEF = "-data:=1~5~Zip~#~RGBbg=50,100,200~~7~30~City~S~~

Note that column definition string following the "+" or "=" in the examples above must meet all of the normal coldef syntax rules, including ending with ~~.


Exitcode

This output parameter returns a single numeric code indicating how the tree was exited. For the most part, these exitcodes are common to other several routines (INFLD, XTEXT, EVENTWAIT).

Value | Flag | Description
29 |  | Indicates user clicked on drop-down arrow of a "self service" combo cell.
11 | XTR'TIMEOUT | Time out in milliseconds
10 | XTF_CTRLC | Ctrl+C. Note that XTF_CTRLC works even if Ctrl+C has been disabled (see CCOFF.SBR).
1 |  | Escape
0 |  | Normal exit by hitting Enter or double-clicking on an item
-1 thru -16 | XTF_FKEY | F1-F16 (enable with XTF_FKEY)
-35 | XTF_TAB | Shift+Tab. If not enabled for exit, Tab and Shift+Tab may be used in conjunction with editable cells to navigate between them.
-40 | XTF_LEFT | LeftArrow. When editing a cell, left arrow will operate within the cell; use CTRL+LEFT to generate exitcode.
-41 | XTF_RIGHT | RightAarrow. When editing a cell, right arrow will operation with the cell; use CTRL+RIGHT to generate exitcode.
-42 | XTF_UP | UpArrow
-43 | XTF2_DOWN | DownArrow on last row
-44 | XTF_TAB | Tab key
-45 | XTF_HOME | Home key
-46 | XTF_END | End key
-47 | XTF_DEL | Del key
-48 | XTF_ EDITABLE | Indicates exit from a cell for validation. Requires coldef format code X. Note that uX combination (read-only editable) exits for validation on entry into the field; otherwise validation exit occurs on exit from the field.
-51 | (no flag) | Exit on receipt of character defined in ExitChars
-59 |  | Double-click on a read-only editable cell (coldef format code u)
-69 |  | Click on close-tab "x" button in TabX control
(others) |  | A click on any other control which generates a standard virtual key click string (e.g. VK_xF101) will cause XTREE to exit with the corresponding exitcode. You can also define left/right click exitcodes for columns and context menus using the ClickExit= and PopupMenu= Advanced Coldef Options.


Flags

This parameter is used to enable exit keys and other options according to the tables below. Note that although most of the flags are optional niceties, a few are critical to proper XTREE operation. (In particular, XTF_XYXY is required, and XTF_COLDFX is nearly always appropriate.) The parameter can be mapped in one of two ways:

MAP1 FLAGS,B,4 ! (XTF_xxx)

or

MAP1 XFLAGS

MAP2 FLAGS,B,4 ! (XTF_xxx)

MAP2 FLAGS2,B,4 ! (XTF2_xxx)

The second form is required if you want to use any of the XTF2_xxxx flags (i.e. Flags2), but in that case, note that you must specify XFLAGS (i.e. the structure) rather than either FLAGS or FLAGS2 in the xcall parameter list.

WARNING: Versions of A-Shell prior to 5.1.1146 will not recognize the XFLAGS structure format, causing XTREE to fail to understand any of your flags. If that presents a problem, the workaround is to map the flags argument as an array of two B,4 elements, e.g.

MAP1 FLAGS(2),B,4

In that case, pass FLAGS(1) for the flags argument and newer versions of A-Shell XTREE will just assume that you passed an array of two elements, with the 2nd element containing the XTF2_xxx flags, while older versions will just see the first element (containing the XTF_xxxx flags).

ATE, however, does not present any particular compatibility issues. Versions prior to 1146 simply won't see the XTF2_xxx flags. So, if you have only one or a few servers to update, but uncountable ATE clients, then it may be better to update those servers and use the XFLAGS format, since it is more extensible and A-Shell doesn't have to assume that there are at least 2 elements in the array.

To set individual flags, just add (or combine using the "OR" operator) the corresponding symbols or values, e.g. FLAGS = XTF_XYXY or XTF_COLDFX.

flags2 and the XTF2 symbols have their own section here: Flags2. Also see XTR’MISCFLAGS for additional flags and more information.

The symbol definitions come from ashinc:xtree.def.

Symbol | Value | Description
XTF_FKEY | &h00000001 | Allow F1-F16 (returning Exitcodes -1 through –16)
XTF_LEFT | &h00000002 | Enable Left arrow (Exitcode -40)
XTF_RIGHT | &h00000004 | Enable Right arrow (Exitcode –41)
XTF_UP | &h00000008 | Enable Ctrl+Up arrow on first row (Exitcode -42). See "Locating and Selecting Items ... Use the Up/DownArrow keys " in Mouse and Keyboard.
XTF_TAB | &h00000020 | Enable Tab key (Exitcode -44), and Shift+Tab (Exitcode -35)
XTF_HOME | &h00000040 | Enable Home key (Exitcode –45)
XTF_END | &h00000080 | EnableEnd key (Exitcode –46)
XTF_ENTESC | &h00000100 | Controls Escape and Enter keys when in editing mode. Note that INMEMO used this flag value for the "no auto-shrink" option, which isn't applicable to XTREE.
XTF_MODELESS | &h00000200 | Leave list box on the screen after exit from the subroutine.
XTF_TIMOUT | &h00000400 | For the PCKLST (text mode) only, sets a 200 second timeout—i.e., acts as if user had hit Escape. For XTREE, ignored; use XTR'TIMEOUT instead.
XTF_FST | &h00000800 | Fast selection mode. In PCKLST, this means menu items can be selected by entering the minimum number of characters to uniquely identify the item. (Without the XTF_FST flag, Enter would be required to complete the selection.) For XTREE, this means that a single click (completes the selection operation, rather than requiring a double-click or a click followed by Tab).
XTF_FCOLDEF | &h00001000 | Control interpretation of first record.
XTF_XYXY | &h00002000 | Interpret the 1st and 2nd parameters (row, col) as starting row, starting col, and the 8th and 9th parameters (strow, endrow) as ending row, ending col. Mandatory for XTREE, optional for PCKLST.
XTF_SORT | &h00004000 | Allow sorting.
XTF_REORD | &h00008000 | Allow column reordering by drag and drop. (Note that if enabled globally, it can still be turned off for individual columns.)
XTF_MSEL | &h00010000 | Allow multiple selections.
XTF_MLVL | &h00020000 | Multi-level (hierarchical) row support. This will be set automatically if the first column defined in coldef uses the @ code. Sample images here and here.
XTF_COLDFX | &h00040000 | Coldef parameter uses the advanced syntax.
XTF_VARY | &h00080000 | Variable height rows. Calculation is subject to maximum number of text lines per item as set in the xtrctl XTR'ITEMLINES parameter.
XTF_NOSEL | &h00100000 | Exit immediately, rather than waiting for the user to make a selection. (This only makes sense in conjunction with XTF_MODELESS; also see xtrctl XTR'OPCODE)
XTF_DISABLE | &h00200000 | Disable the tree control on exit.
XTF_DEL | &h00400000 | Enable Del exit (Exitcode –47)
XTF_FILANS | &h00800000 | Return result via row number in answer parameter.
XTF_CTRLC | &h01000000 | Causes Ctrl+C to set Exitcode 10 (as in INFLD) instead of 1.
XTF_EDITABLE | &h02000000 | Declares that the tree contains editable text (i.e. one or more columns with column format T or E). Without this flag, edits may appear to work, but the interpretation of the array parameter will probably be wrong, as it must be interpreted in a scope where the coldef parameter is not available.
XTF_TOTALS | &h04000000 | Declare that last line of data contains totals (and thus is not to be sorted).
XTF_NOREDRAW | &h08000000 | Defeats redraw/refresh of data.
XTF_DRAGDROP | &h10000000 | Item drag-drop (within a single XTREE control).
XTF_SPLIT | &h20000000 | Activates split or dual-pane mode.
XTF_NOZEROEX | &h40000000 | Prevents XTREE from exiting with EXITCODE 0.

Hex-Decimal Values

Jump to Flags2 table.


XTF_ENTESC

Affects the operation of the Escape and Enter keys when in editing mode. Normally, Escape 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, Escape 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.

History

2005 December, A-Shell 4.9.947: Function added to XTREE


XTF_MODELESS

Leave list box on the screen after exit from the subroutine. In GUI mode, this also leaves the control defined, for possible re-entry or refresh later. (See XTF_NOSEL and xtrctl XTR'OPCODE.) (The symbol name, XTF_MODELESS, is meant to represent "modeless", since this makes the pick list act something like a modeless dialog, i.e. a dialog that allows you to click back on the main window without first closing it, as opposed to the normal "modal" dialog.) Also see XTF_DISABLE.


XTF_FCOLDEF

For file mode, this flag indicates that the first line of the file contains the Coldef specification. If XTF_COLDFX is not specified, then the line is assume to be in the Simple Multi-Column Coldef Syntax. Otherwise—i.e., XTF_COLDFX is specified—then it is assumed to be in the Advanced Coldef syntax.

See File Mode Coldef Extensions for further related information.


XTF_SORT

Allow sorting (by clicking on a column header). Note that sorting only affects the display; it does not affect index of the selected items returned in array mode. (In other words, if sorting causes the first row of the array to be sorted to the end, and it is selected, answer will still be returned as 1.)

As of A-Shell 5.1. 1136, string (S) columns now sort using the Natural Sort algorithm.


XTF_MSEL

Allow multiple selections. The operator accomplishes this by holding down the Ctrl key while clicking to make a selection (or Shift while clicking to select a range). In this mode, the answer parameter must be mapped as an array of one byte strings, which will be returned representing the status of each row ("1"=selected).


XTF_NOSEL

When a call using XTF_NOSEL follows a click on the inactive tree, it returns the location of the click in the XTR'TARGETROW and XTR'TARGETCOL fields. This is useful in the following scenario:

Your program is waiting in some state other than XTREE (perhaps INFLD), but there is a visible (inactive) XTREE control on the screen. The user clicks on a cell in the XTREE. This returns the exitcode defined by XTR'KBDSTR to whatever routine is waiting on input. Your program sees that the exitcode is from clicking on the inactive XTREE, but you want to know what cell was clicked. So you call the XTREE, with opcode XTROP_RESELECT and with the XTF_NOSEL flag set (for an immediate exit). On exit, your program can get the location of the click from XTR'TARGETROW / XTR'TARGETCOL.

Note that this operation only makes sense in conjunction with XTF_MODELESS; also see xtrctl XTR'OPCODE .


XTF_DISABLE

Disable the tree control on exit. Only makes sense if XTF_MODELESS also set. This might be useful to either visually make it clear to the user that the control is not active, or to eliminate the need to process a keyboard click string for when the user clicks on the control outside of the confines of XCALL XTREE. See XTR'KBDSTR.


XTF_FILANS

In single-select file mode, return result (and select default) via row number in answer parameter, rather than row text in array parameter. Selected row data is still returned in the array parameter though. Identifying the selection via the row number rather than the row data eliminates ambiguities when portions of the row data are common to more than one row, as well as when columns using the right justification format option, but not right-justified in the file data, get stripped.


XTF_NOREDRAW

When used with XTR'OPCODE 4 (select from existing control), defeats all redraw/refresh of data, which makes for a "cleaner" re-entry, assuming that none of the parameters which might affect the display have changed. Without this flag, re-selecting from an existing control will reset the columns, possibly adjust the vertical scroll, etc. The sample program XTRA3 demonstrates this.

Note that it is possible to use the XTF_NOREDRAW flag along with opcode 4 (reselect) even when you are updating data in the editable cells prior to the reselect. In early versions of XTREE, XTF_NOREDRAW disabled the updating of the editable cells from the ANSARY parameter on reentry. XTF_NOREDRAW might be useful in this circumstance to eliminate unwanted display adjustments taking place during the reentry process.


XTF_DRAGDROP

Updated and reviewed March 2012

XTREE supports item drag-drop, within a single XTREE control, as a means of allowing the user to re-order the rows and to communicate the new order back to the application. (For drag/drop between XTREEs, see XTF2_DRAGDROP2.) For example, you may want to present a list of fields available for export and allow the user to determine the output order by rearranging the list using drag/drop. Or you may want to load up an XTREE with a list of all of your illegally downloaded MP3 tunes and use the drag/drop feature to create ordered play lists.

To enable the feature, specify the XTF_DRAGDROP bit in the FLAGS parameter, and insert two fields at the start of the ANSWER array, along the lines of how you would set up the ANSWER array for editable cells. The first field is a four-character string to return the original row number for the given display row, and the second field is a one-character item selection flag (just as you would have for multi-selection).

For example:

MAP1 ANSWERX

MAP2 ANSARY(MAX_ROWS)

MAP3 ORG'ROW,S,4 ! original row number of this display row

MAP3 SELECTION,S,1 ! selection flags

MAP3 CB,S,1 ! a checkbox column

MAP3 EDATA,S,8 ! a 8 character editable column

<etc>

Note that the ORG'ROW field must be first, followed by the SELECTION field, followed by any editable checkboxes, followed by any other editable cells. (In the example above the ORG'ROW and SELECTION fields would be mandatory while the CB and EDATA fields would only apply if you happened to have one editable checkbox column and one editable text column.)

The SELECTION field is treated just as it would be when multi-select is enabled (i.e. SELECTION(I)="1" if item I is selected, or "0" if not.) Note that the presence of a SELECTION array usually indicates that multiple selection is supported, but in this case it does not necessarily imply that. In fact, the drag-drop operation currently only works for one row at a time, although you can still allow multi-selection for reasons independent of drag-drop. In normal (single selection) case, all of the SELECTION() entries will be "0" except for the one selected item.)

The ORG'ROW field is formatted as a decimal number of up to 4 digits with leading spaces. (This imposes a maximum of 9999 rows when using drag-drop, which is a reasonable limit since drag-drop becomes somewhat impractical anyway when you have more than several dozen items.)

Since the array used to load items is not returned by XTREE, and all other related return data specifying row numbers is coded relative to the original order of the rows (as opposed to the last display order), the ORG'ROW() array provides the only way for the app to determine what the last display order was. (This might even motivate you to enable drag/drop just for the purpose of being able to easily process the array data according to the way the user sorted it.)

The ORG'ROW() array is ordered according to the display order of the rows, unlike all the other arrays within the ANSWER array, which are ordered according to the original array order. As an example of using ORG'ROW(), the following code would print the original array data according to the display order (resulting from drag/drop and/or column sorting):

FOR I = 1 TO MAX_ROWS

J = VAL(ORG'ROW(I))

IF (J > 0) PRINT ARRAY(J)

NEXT I

See Also

XTF2_DRAGDROP2 for drag/drop operations involving more than one XTREE control.

The entry for DragDropProtect in the table of Advanced Coldef Options.


XTF_SPLIT

This flag enables a split (or dual-pane) mode, allowing two sets of columns to be scrolled horizontally independently. This is typically useful when you have a lot of columns (so horizontal scrolling is needed) but you want one column, or perhaps a few columns, to always be visible. By putting those columns in the left pane, they will be immune to the horizontal scrolling taking place in the right pane. Two fields in the XTRCTL structure, XTR'LEFTPANECOLS and XTR'LEFTPANEWIDTH, are used to control column size and spacing; see those topics for related inforamtion.

In most respects, the dual pane mode should act just like the regular, single-pane mode. Both panes remain vertically synchronized at all times. However, in editable mode, there is currently an assumption that you would probably confine the editable cells to the right pane, and thus the editable cell navigation operates on this principle, although you could still select an editable cell in the left pane with the mouse.

Two sample programs are available: XTRA2S is a variation of XTRA2, with the zip column in the left pane by itself. XTRA5 has been upgraded to offer an option of how many columns, if any, to put in the left pane. (If none, it works as before in single-pane mode.)

Sample image here.


XTF_NOZEROEX

This flag prevents XTREE from exiting with EXITCODE 0. This would mainly be useful in conjunction with XTF_EDITABLE where you wanted to only exit for validations and explicit click operations as opposed to a spurious Enter key that slips in while the tree is selection mode (between editable cells).


XTF_COLDFX

In XTREE, indicates that coldef parameter uses the advanced syntax.

In PCKLST, indicates that the prompt parameter is actually an XTREE advanced Coldef syntax specification, rather than simply a title string. However, because of the limited capabilities of PCKLST, it pays attention only to the cwidth and ctitle fields for the first column. (cpos should be 1, and cformat should be S). ctitle is used for the PCKLST top title. All XTREE Advanced Coldef Options are ignored except SelChgExit. Using this format doesn't provide a lot of advantages in the PCKLST context, but it does allow programs that work in both PCKLST (text) and XTREE (GUI) modes to take advantage of a wider range of XTREE features when operating in the GUI mode without breaking compatibility with PCKLST in the text mode. For example:

prompt = "1~14~Pizza Menu~S~DefaultScale=120~ExitChars=01~SelChgExit=103~~"

The above string indicates that the width of the elements in the array is 14, that "Pizza Menu" should be used as the top title/prompt, and that the routine should exit with exitcode -103 whenever the selection bar is moved. The DefaultScale and ExitChars options are ignored by PCKLST (but would be valid for XTREE).


Flags2

Updated January 2011

This parameter is a continuation of the flags parameter, providing additional bits for additional options. Note that both flags and flags2 are passed to the xcall as a single structure containing both sets of flags. See Flags for details on how this must be mapped. Also see XTR’MISCFLAGS for additional flags and more information.

Symbol | Value | Description
XTF2_HOME_CTRL | &h00000001 | Exit on <Home or End> without Ctrl+. See XTF2_HOME_CTRL and _END_CTRL.
XTF2_END_CTRL | &h00000002
XTF2_NAVCOL | &h00000003 | Combo of above for editing and navigation.
XTF2_PORTRAIT | &h00000004 | Portrait or landscape printing.
XTF2_LANDSCAPE | &h00000008
XTF2_AUTOEXPCOL | &h00000010 | Auto expand columns.
XTF2_CSV | &h00000020 | Support for CSV format.
XTF2_PGUPDN | &h00000040 | Enable PgUp/PgDn (exitcodes 4, 6).
XTF2_DOWN | &h00000080 | Enable Ctrl+Down on last row (exitcode -43). See "Locating and Selecting Items ... Use the Up/DownArrow keys " in Mouse and Keyboard.
XTF2_NORESPONSE |  | Eliminates return of any response information for a particular XTREE call.
XTF2_CLRDEFER | &h00000100 | Tells XTREE to ignore any previous inactive click and to clear any secondary events associated with it. See discussion of Clicks on Inactive XTREEs. Also tells XTREE to discard any unprocessed keyboard characters at the start of the start of the XCALL operation (so that the session starts out waiting for new keyboard and mouse events, rather than processing ones that occurred prior to the XCALL).
XTF2_PROPSHEET | &h00000800 | Property sheet (aka "vertical") mode.
XTF2_ANSEQDATA | &h00001000 | Used to indicate that the layout of the answer array is the same as that of the data array.
XTF2_DRAGDROP2 | &h00002000 | Drag/drop between trees.
XTF2_SAVRES | &h00008000 | Causes PCKLST to save the screen area.
XTF2_POPUP | &h00010000 | Causes the tree control to be created as a popup rather than as a child control.
XTF2_ENTERNAVDOWN | &h00020000 | Alters the default cell editing navigation response to the Enter key, provided there is no EnterGoto option defined for the current column. When specified, instead of acting like Tab and moving to the next editable cell to the right, Enter acts like DownArrow, except that from the last row it wraps back up to the top.
XTF2_PIXCOORDS | &h00040000 | Causes the coordinates units to be treated as pixels. Equivalent to MBF2_PIXCOORDS in AUI_CONTROL.
XTF2_ITEMICONS | &h00080000 | Specify "item icons."
XTF2_CTRLC_COPY | &h00100000 | Enables use of Ctrl+C to copy selected item(s) to clipboard. See Copy to Clipboard.
XTF2_UTF8 | &h00200000 | Provides support for UTF8.
XTF2_AUTOEXPROW | &h00400000 | Adds extra space to each row to fill out the allotted vertical area of the tree.

Hex-Decimal Values


XTF2_AUTOEXPROW

Added August 2015

Flag XTF2_AUTOEXPROW works analogously to XTF2_AUTOEXPCOL to add extra space to each row to fill out the allotted vertical area of the tree. It only applies to trees with fixed height rows—i.e., XTF_VARY flag not set. It is normally accompanied by the XTMF_INTHEIGHT flag (in XTR'MISCFLAGS) which has a similar/related purpose. While XTMF_INTHEIGHT by itself (without XTF2_AUTOEXPROW) cause the height of the tree to shrink slightly, so as to avoid having a partially visible row at the bottom, XTF2_AUTOEXPROW causes the row heights to expand slightly, avoiding the partial row at the bottom but also avoiding the need to shrink the tree height.

Note that while XTF2_AUTOEXPCOL may seem to make XTMF_INTHEIGHT superfluous, the requirement of making each row the same height may result in a small pixel remainder after dividing the extra space between the rows. The XTMF_INTHEIGHT flag will then eliminate that by making a small adjustment to the overall height.

History

2015 August, A-Shell 1315: Flag added to A-Shell


XTF2_UTF8

Added November 2013

You may display and edit non-Latin1 characters (Cyrillic, Greek, Korean, etc.) in XTREE by specifying the XTF2_UTF8 flag and then using the UTF8 encoding for special characters in the data array, file, and/or ansary. If you don't specify the XTF2_UTF8 flag, XTREE will assume that any characters > chr(128) are Latin1-encoded (as it has in the past).

Note: the column widths specified in the coldef parameter remain in units of 8-bit bytes, so if you expect a column to contain UTF8-multi-byte-encoded characters, make sure to expand the column width accordingly.

See the EXLIB sample program XUTF8A.BP.

History

2013 October, A-Shell 1365: Flag added to A-Shell


XTF2_HOME_CTRL and _END_CTRL

The XTF_xxxx_CTRL flags, as their names hopefully suggest, affect the behavior or need for the combination of the Ctrl key with the xxxx (Home or End) key. When set, and assuming that the corresponding XTF_HOME and/or XTF_END flags are also set, then these bits reverse the behavior of the Ctrl key in conjunction with the Home and End keys. Thus, Home and End without the Ctrl key will be interpreted as exit keys, while Ctrl+Home and Ctrl+End will be interpreted as navigation keys (to jump to the first/last row).

Historical note: prior to 5.1.1133, Home and End navigated to the first/last row of the tree, unless you used the Ctrl key with them (and the XTF_HOME and/or XTF_END flags were set), in which case they acted as exit keys. Between 1133 and 1146, they acted as exit keys even without the Ctrl key. Then starting with 1146, the original behavior was restored (and the XTF2_xxxx_CTRL flags were introduced to allow you to choose between the two behaviors).


XTF2_NAVCOL

The XTF2_HOME_CTRL and _END_CTRL flags, when used in an editable tree where XTF_HOME and/or XTF_END are not set, allows Home and End to, in some types of editable cells, navigate to the first / last editable cell on the current line. By "some types" we mean essentially any kind of editable cell except one that allows you to directly edit the contents of (i.e. a standard editable text cell), since in the latter case, Home and End are captured by the edit box itself to move the cursor to the beginning and ending of the cell, rather than to move between cells. But for checkboxes, radio buttons, read-only cells, etc., these new keys provided yet another navigational shortcut for power users.

Note that for convenience and perhaps clarity, a symbol has been defined in XTREE.DEF:

define XTF2_NAVCOL = &h00000003 ! (XTF2_HOME_CTRL+XTF2_END_CTRL)

Also note that these flags have no effect in non-editable situations, provided the keys are not enabled as exit keys (via XTF_HOME / XTF_END). If they are enabled as exit keys, then the XTF2_NAVCOL flags reverse the action of the simple keys and the keys with Ctrl+. In other words, when set, Ctrl+Home will navigate to the first row, while Home will exit; otherwise, Ctrl+Home exits and Home navigates.


XTF2_AUTOEXPCOL

This flag will auto-expand the columns to fill the width of the tree control, eliminating the blank space that will otherwise appear when XTR'CLOSEDENDED is 1 and the overall tree control is wider than it needs to be for the current data.

define XTF2_AUTOEXPCOL= &h00000010 ! Auto Expand Columns to fill control

The expansion operation increases the width of the visible columns by a uniform percentage rather than by a fixed number of pixels, thus preserving the relative widths. The last column will pick up any extra pixels left over from rounding and if there is no vertical scroll bar.

The flag is ignored in split (XTF2_SPLIT) and open-ended (XTR'CLOSEDENDED=0) controls.

History

A-Shell 5.1.1176 of 16 March 2010: XTF2_AUTOEXPCOL no longer automatically overrides the wrap option in the last column. If any columns have the wrap attribute, it assumes that there will be a vertical scroll bar and calculates the column width expansion accordingly, leaving the wrap settings in place. The only downside of this change is that if there are not enough items to require a vertical scroll bar, you could end up with a vertical white strip on the right edge, where the vertical scroll bar would have gone.


XTF2_CSV

Updated August 2015

Setting this flag allows you to use a CSV file as the input for the XTREE. There are several variations on how columns and other attributes can be defined:

· If you do not specify a column definition string in coldef (XTF_COLDFX), XTREE will auto-define columns based on the number of fields in the first row of the CSV file. (Currently it sets them all to a generic string type, although perhaps in the future an attempt will be made to auto-detect numeric and date columns). In the typical case, XTREE assumes that the first row of the CSV file contains the column names, which will be used to build the XTREE column headers. If your CSV does not contain such a header row, you can specify XTR'HIDEHEADER=1 (in xtrctl), in which case the first row will be treated as data, and there will be no column headers.

· You may specify your own column definitions using the standard coldef syntax, either in the CSV file itself (in which case set both the XTF_FCOLDEF and XTF_COLDFX flags), or in the coldef parameter (in which case set XTF_COLDFX as you would normally). However, note that if any real columns are defined, then only those columns will be properly recognized during the load operation. You may choose to define only pseudo-columns (with cpos=0 and cwidth=0, i.e. "0~0~x~H~...~~") in order to define other attributes, such as colors, fonts, popup menus, etc., in which case the actual column definitions will be auto-generated as in the first case described above. Note that whenever any real columns are defined using the advanced coldef syntax (in either coldef or in the file), it is assumed that there is no other header row in the file. If there is, use the skip syntax described below to skip over it.

· When defining real columns, set cpos to the column number and cwidth to 1. It doesn't actually matter what you set them to, as long as they are both greater than zero, but this is a reasonable convention to minimize confusion later.

· To skip over lines at the top of the file, you can begin your coldef parameter with a {-skipval} clause as documented with 5.1.1115. Note that when XTF2_CSV is specified, the {-skipval} clause does not require XTF_FCOLDEF (i.e. doesn't require any column definitions in the data file), and it doesn't have to be followed by "+" or "=" and a valid coldef definition. So in other words, you can skip lines by starting the coldef parameter with a {-skipval} clause, whether or not you use any other coldef features.

Examples

Assume the CSV file looks like this and that we are specifying the XTF2_CSV flag in all cases:

Account, Name, TrxDate, Amount

12345,"Smith,Fred",08/15/09,999.12

12346,"Jones,Jane",08/16/09,100.00

If coldef ="", and neither the XTF_COLDFX nor XTF_FCOLDEF flags are set, XTREE will recognize and display 4 columns of data, creating headers from the first line.

If XTR'HIDEHEADER=1, then it would treat the first line above as data, rather than as headers, and no header bar would be created.

If XTF_COLDFX is set and coldef ="-1", then it would skip the first line. (When skipping, even if XTR'HIDEHEADER=0, there will still be no header bar unless the coldef string contains real column definitions.)

If coldef ="0~0~x~H~HdrScale=200~~" (and XTF_COLDFX set), then the header scale will be set to 200, but the headers and column information will still be taking from the file (because the coldef does not define any real columns).

If coldef ="-1=1~1~Acct#~#~~2~1~Name~S~~3~1~Date~D~4~1~Amount~#~~", then the first line of the data file will be skipped (due to the "-1=" at the start of the coldef, and the columns will be defined by the coldef string in the normal way, except that due to the XTF2_CSV flag, the cpos and cwidth parameters do not matter (but must be >0). By convention, we have specified cpos values which equate to the field number, but there is currently no way to rearrange the columns with this technique.

If we replaced the standard CSV header line at the top of the CSV file with a coldef string, as follows:

1~1~Acct#~#~~2~1~Name~S~~3~1~Date~D~4~1~Amount~#~~

12345,"Smith,Fred",08/15/09,999.12

12346,"Jones,Jane",08/16/09,100.00

Then we could specify XTF_FCOLDEF and XTF_COLDFX to have XTREE retrieve the column definitions from the file. Optionally, we could add to the column definitions by setting the coldef parameter to "+" followed by a legal set of column definitions (presumably pseudo-columns in this example).

See Also

· XTRCSV.BP example in [908,21] of EXLIB.

History

2015 August, A-Shell 6.1.1515: You may now use the notation "\n" to embed a CRLF within a field, provided the cformat format column contains the "M" (allow embedded CRLFs) option. This avoids complications with parsing CSV files containing line breaks inside of fields.

2013 May, A-Shell 6.1.1351: XTF2_CSV now automatically disables the hidden text feature—i.e., it now treats backslash as a normal data character. The feature was causing more confusion than it was worth, and is only being preserved for traditional file mode.

2009 August, A-Shell 5.1.1157: Added to A-Shell


XTF2_NORESPONSE

Added December 2010

This flag may be specified to eliminate the return of any response information for a particular XTREE call. This is purely of interest in the ATE environment as a performance enhancement, since the return of response information causes the application to have to wait for the network turnaround time, which is small but adds up. In order to be effective, it must be used along with the XTF_NOSEL flag (which is used when you want to display some data without waiting for a user section or editing action).

Warning: do not use this flag along with XTR'CTLNO = -1, since in that case you won't get back the updated tree control number, which could make it difficult to reference the tree on subsequent calls.

History

2010 December, A-Shell 5.1.1198: Added to A-Shell


XTF2_ANSEQDATA

Updated September 2011

This flag may be used to indicate that the layout of the answer array is the same as that of the data array. The main limitation is that it does not support drag/drop or multi-selection. (It may be extended in the future to the more general case). The current primary motivation is to permit the use of same array (or identically formatted ones) for both the answer and data in trees involving checkboxes. (You were already allowed to use the same array for both parameters, but it wouldn't have worked with checkboxes due to the normal rule requiring checkboxes to be placed at the start of each row in the answer array.)

The flag is set automatically when you pass the same variable for both the answer and data parameters.

History

2011 September, A-Shell 5.1.1231: XTF2_ANSEQDATA can now be used even when the array contains fields that are not editable, or possibly not even defined. Previously, if the array width didn't match the sum of the widths of the editable columns, the data layout got out of sync with the tree layout.

2011 January, A-Shell 5.1.1202: Flag to A-Shell


XTF2_PROPSHEET

Added January 2011

Sample image here.

A "property sheet" is a control made up of two columns and a variable number of rows; the first column contains labels (attributes); the second column contains the data corresponding to the labels (attribute values).

In earlier versions of A-Shell (before 1202 of January 2011), there was nothing stopping you from implementing such a structure with a two-column XTREE. But it was difficult, if not impossible, to support a variety of different data formats (checkboxes, radio buttons, different widths of editable text, lists, etc.), since in the property sheet configuration, they would all be in the same column and the XTREE configuration scheme tends to limit each column to a single data format.

The XTF2_PROPSHEET option addresses this by effectively rotating the tree 90 degrees so that the columns (according to the coldef) are displayed as rows. The column titles become the row headers or labels.

Property sheet mode also supports multi-level. To configure this, specify the cformat code "@" for each "column" (i.e. each item) that should appear at level 1. Columns (i.e. items) without this code will appear at level 0. To designate an item at level 2 or below, add additional "@" codes (one per level). For example:

coldef = "1~1~Shipping Info~S~~" ! Level 0 (no "@")

coldef = coldef + "2~30~Address~SE@~" ! Level 1 (one "@")

coldef = coldef + "32~30~City~SE@~" ! Level 1 (one "@")

...

Here are some points and limitations to keep in mind:

• You are limited to a single row of data (which appears as a column). In fact, rather than specify an array of one item, you can just specify a singular structure (whose fields line up with the column definitions.) Since the usual object is to edit this structure, you can specify a copy of the same structure for the answer parameter (remember to set the XTF2_ANSEQDATA flag), or specify the same variable for both parameters.

• You cannot define any hidden columns. (This includes the columns that would be needed to support any row-oriented features like row color, row font.

• None of the following are supported: XTF_MSEL, XTF_DRAGDROP, XTF_REORD, XTF_SORT, XTF_MLVL, XTF_SPLIT.

• Column colors (RBGbg, RGBfg) are not (yet) supported. But you can assign background colors to individual cells using cformat B.

Comments

• If you are using anything but left justification, and if there is any possibility of cells extending logically beyond the control width, you should XTR'CLOSEDENDED mode and XTF2_AUTOEXPCOL. Otherwise, you may end up column data that doesn't appear unless you use the horizontal scroll bar to scroll to the right.

• If Dspwid=# is specified for an editable cell, it determines the width of the edit box when a cell is being actively edited. This provides an alternate method (besides cformat "_") to adjust the width of the edit box to be more appropriate for the maximum number of characters allowed in that cell. If Dspwid is not specified, then the cformat "_" logic is used, and if that isn't specified, the edit box width will be the same as the column width. Note that in the property sheet case, the units of Dspwid are taken to be characters, rather than grid units (as in the non-property sheet case.)

See the EXLIB sample program XTRA15.BP for an example of property sheet mode.

History

2011 January, A-Shell 5.1.1202: Added to A-Shell


XTF2_DRAGDROP2

Added January 2011

This flag enables drag/drop operations between different XTREE controls. To enable, set the flag in the source tree, and specify the advanced coldef option, DragDropClick=###, in the destination tree. ### is the negative exitcode to be generated when an item (or items) from the source tree is/are dropped on to the destination tree. For example, DragDropClick=150 will generate exitcode -150.

Notes

• This form of drag/drop (inter-tree) does not require any special mapping of the answer array (as is required with the intra-tree drag/drop activated by XTF_DRAGDROP).

• Both forms of drag/drop are essentially independent (you can have either one or both).

• No distinction is made regarding the exact position of the drop within the target control. The only information returned to the application will be the selection information for the source tree, and the DragDropClick exitcode from the target tree.

• It is left to the application to complete the operation signified by the drag/drop action. Typically this would involve copying the selected items from the source tree to they destination tree, and perhaps removing them from the source tree.

The sample program XTRA4.BP in [908,21] has been completely rewritten to demonstrate a simple shopping cart application using this capability.

See Also

XTF_DRAGDROP for drag/drop operations within a single XTREE control.

History

2011 January, A-Shell 5.1.1203: Added to A-Shell


XTF2_SAVRES

Added June 2011

This flag causes XTREE/PCKLST to save the screen area unless the XTROP_DELETE opcode is used, in which case it causes PCKLST to restore the area previously saved. Note that PCKLST will automatically save and restore the area of a pop-up, without using this flag, provided that the XTF_MODELESS flag is not set. If XTF_MODELESS is set, then you can set the XTF2_SAVRES flag (in 2nd 4-byte flag word, i.e. flag2) in the first call to create the list display, and again in the final XTROP_DELETE call to remove it. The flag currently does not affect XTREE (GUI mode), which does something like this automatically already.

History

2011 June, A-Shell 5.1.1221: Added to A-Shell


XTF2_POPUP

Added June 2011

This flag causes the tree control to be created as a popup rather than as a child control. This is mainly useful when creating an XTREE in the main window (rather than in a dialog) that may overlap other controls, and where you want those other controls to remain visible. Normally, XTREE will save and then remove any overlapping controls when it is displayed in a main window, because otherwise those controls may "bleed" through (interfering with the visual and operation aspects of the XTREE control). The feature was added primarily to improve compatibility with the text mode of PCKLST when it is used to create multiple overlapping "pick lists". That always worked fine in text mode; now it works fine in GUI mode as well.

The flag is defined in XTREE.DEF as:

define XTF2_POPUP = &h00010000 ! implement as popup rather than child

Note that the new mode constrains some of the more advanced behaviors of XTREE, so it should probably only be used in simple "pick lists" (as you have when XTREE is called by PCKLST). In particular, popup mode is incompatible with editable tree mode.

History

2011 June, A-Shell 5.1.1221: Added to A-Shell


XTF2_ITEMICONS

Added March 2013; see History

XTREE's item icons are similar to the existing cell images (cformat type "I") except:

• Item Icons are associated with items (one per item) rather than cells.

• Item Icons are always displayed at left edge of the item row.

• For multi-level trees, you can define a set of three item icons (in the 'zero column') corresponding to the three types of multi-level items (expandable, expanded, and leaf). In this case the icon will automatically change when an expandable item is toggled between expanded and collapsed.

• To specify individual icons for specific rows (rather then use just the expandable/expanded/leaf icons), you create a column using the new cformat code "i" to hold the icon spec. (Unlike the "I" image column, which can contain both an image spec and display text, the "i" column only contains the image spec. Also, unless you want to display the image spec as text, the "i" column should be hidden, i.e. "iH".)

Note that despite the terminology difference (icons versus images), you can use either type of image in either case (i.e. discrete image files, including .ico files, and icons embedded in a DLL, e.g. folder::ashico1). We use the term "icons" here to clarify that these images are meant to act like icons (i.e. be small, fixed in size, and symbolize some attribute of the item).

To activate item icons, specify the new flag XTF2_ITEMICONS in the flags2 parameter. By default, XTREE will use the following images for the icons:

%MIAME%\icons\FldCls_16.png (16x16 closed folder)

%MIAME%\icons\FldOpn_16.png (16x16 open folder)

<internal blank icon> (no icon for the leaf items)

You can override the choice of icons by specifying an advanced coldef option containing image specifications (any A-Shell supported type) for the three types of multi-level items:

ItemIcons=closed-img,opened-img{,leaf-img}

Note that if the tree is not multi-level, all of the items are considered leaf items and thus would receive the icon corresponding to the leaf items; the icon specified for expandable and expanded items would be ignored.

Three additional new Advanced Coldef Options may also be associated with ItemIcons:

ItemIconDir=<default image directory>

ItemIconSiz=iwidth,iheight,bpp

ItemIconCount=<# icons to load>,<grow-by-value>

These are analogous to the ImgDir, ImgSiz and ImgCount options associated with "I" image columns, except here they are all optional.

The default for the ItemIconSiz option is 16,16,24 (i.e. 16x16 image size and 24 bpp).

The ItemIconCount option is only applicable when you are have an "i" column in order to specify individual item icons (beyond the three defined in the ItemIcons option).

A blank cell within an "i" column will default to using the icon for that type of item (defined explicitly or implicitly by the ItemIcons option). In order to override the default icon with a blank icon, you can use the special icon specification "#".

The EXLIB sample program XTRA2I illustrates a number of variations of ItemIcons.

The standard distribution now includes FldCls_16.png, FldOpn_16.png and Leaf_16.png icons in the icons subdirectory.

History

2013 March, A-Shell 6.1.1340: Function and documentation added to A-Shell


File

This specifies a sequential file to be used for input instead of the array parameter. When non-null, the interpretation of array, addcnt, and answer parameters changes as follows.

If neither the multiple selection (XTF_MSEL) nor XTF_FILANS flags are set, then array becomes an ordinary string, which is used to pass in the default selection (text) and to get back the item chosen by the user, and answer is ignored. Note that here the default selection mechanism works only on the first column; if its cells are not all unique, you may not end up with the desired item selected. The workaround is to use XTF_FILANS to select the default by row number, or to add a first column that is unique.

If XTF_MSEL is not set but XTF_FILANS is set, then array is still treated as an ordinary string which returns the text of the item chosen, but answer is used exactly as in array mode (to return the row number of the selected item, and to pass in the default row number).

If the multiple selection flag (XTF_MSEL) is set, then array is ignored and answer is treated as an array of one byte selection flags, exactly as for multiple-selection array mode. addcnt should be set to 0 to load the entire file, or else set to the number of records (lines) to be loaded.

The default selection process (in single-selection mode) works only on the first column. If the cells in the first column are not all unique, then you may not end up with the desired item selected. The only workaround is to add a first column that is unique, or to switch to the array mode, which identifies selections by the array index. Also note that XTREE supports the PCKLST "hidden text" feature, which allows you to pass hidden text in the last column of the data by preceding it with a \. Although this technique is useful for associating control information with list items without having to display it, a better way to do this with XTREE is to just define a hidden column. The \hidden text feature is preserved just for compatibility with PCKLST.

XTREE supports the PCKLST "hidden text"feature, which allows you to pass hidden text in the last column of the data by preceding it with a backslash ("\"). Although this technique is useful for associating control information with list items without having to display it, the feature is support merely for backward compatibility with PCKLST and is otherwise deprecated. The preferred approach to embedding hidden data with XTREE is to define a separate hidden column. Note that in CSV mode (a variation of file mode; see XTF2_CSV), the special treatment of the backslash applies to every column, not just the last. To treat the backslash as a normal data character, use the advanced Coldef feature XTF_COLDFX and add the "\" code to the Cformat specification for any column.


Mmoclr

As in PCKLST, may be used to specify colors for various parts of the pick list, although in the GUI mode, the interpretation of color –1 is slightly different. Instead of specifying the current foreground or background color, it specifies the Windows default color for that particular part of the pick list display. (This will result in a typical-looking list box with black text on a white background, while the column headers are gray buttons.) The format of MMOCLR is:

MAP1 MMOCLR

MAP2 BFCLR,B,1,-1 ! Border Foreground (NA in GUI mode)

MAP2 BBCLR,B,1,-1 ! Border Background (NA in GUI mode)

MAP2 TFCLR,B,1,-1 ! Text Foreground (default black)

MAP2 TBCLR,B,1,-1 ! Text Background (default white)

MAP2 AFCLR,B,1,-1 ! Arrow Foreground (NA in GUI mode)

MAP2 ABCLR,B,1,-1 ! Arrow Background (NA in GUI mode)

MAP2 PFCLR,B,1,-1 ! Title Foreground (default black)

MAP2 PBCLR,B,1,-1 ! Title Background (default gray)

MAP2 WFCLR,B,1,-1 ! Warnings & messages Foreground (NA in GUI)

MAP2 WBCLR,B,1,-1 ! Warnings & messages Background " "

MAP2 SFCLR,B,1,-1 ! Orig. Status line Foreground " "

MAP2 SBCLR,B,1,-1 ! Orig. Status line Background " "

MAP2 RFCLR,B,1,-1 ! Reserved (unused) Foreground " "

MAP2 RBCLR,B,1,-1 ! Reserved (unused) Background " "

The individual fields within MMOCLR are shown above initialized to -1, which is what you must do to get default colors, since color 0 is black. (Specifying MMOCLR with all the fields un-initialized will result in a not-very-interesting black on black display.) Note that the colors for individual columns can be overridden using the advanced form of the coldef parameter.

Since the XTREE color scheme is largely standardized by Windows conventions, and may be customized by coldef options, in most cases the MMOCLR parameter is superfluous and may be replaced by a literal 0 in the parameter list, e.g.:

xcall XTREE,srow,scol,answer,array,count,coldef,exitcode,erow,ecol,flags,file,0,xtrctl


Xtrctl

This is a structure containing various extended parameters and options. If omitted, suitable defaults will be supplied, although that will severely limit the capabilities of the tree control. For those parameters which are essentially Boolean options, 0=false and 1=true. Most of the fields in XTRCTL are input-only, but a few, such as COLUMNACTIVE are updated as well, and some are output-only; these are indicated with "[in/out]" or "[out]" in the following table, which lists the structure members alphabetically for easy reference. To use the XTRCTL structure in your program, include the xtree.sdf and xtree.def files and then map an instance of the structure for each XTREE in the program, e.g.:

map1 xtr, XTRCTL ! define instance of XTRCTL structure named xtr

...

xtr.OPCODE = XTROP_CREATE

xtr.CTLNO = -1

etc.

Or include the xtree.map file which includes actual map statements for XTRCTL (rather than a structure definition); in that case, members would be assigned as follows:

XTR'OPCODE = XTROP_CREATE

XTR'CTLNO = -1

etc.

Note that the first method (declaring an instance of the defined structure XTRCTL and using the structure dot member notation) has the advantage of making it easy to define and maintain separate copies of the structure for multiple XTREEs.

Symbol | Type | I/O | Description
XTR'CLOSEDENDED | B,1 | in | Set size of last column to "open ended" or fixed.
XTR'COLORDER (31) | B,1 | in/out | Provides rearranging of the display order of the first (up to) 31 columns
XTR'COLUMNACTIVE | B,1 | in/out | Col # with focus (for kbd search)
XTR'COLUMNSORT (3) | B,1 | in/out | First, second, third sort columns
XTR'CTLID | B,1 | out | Returns standard control ID of XTREE control (allowing access by AUI_CONTROL)
XTR'CTLNO | B,1 | in/out | Specifies which XTREE control to use.
XTR'DELCTLID | B,4 | in | Ctl to delete.
XTR'EXPANDLEVEL | B,1 | in | 0=collapse, #=expand through level # (9 max)
XTR'FLYBY | B,1 | in | Fly-by highlighting? 0=no, 1 = first column, 2 = entire row.
XTR'FOOTERSTYLE | B,1 | in |
XTR'GRIDSTYLE | B,1 | in | 0=vert solid, 1=horz solid, 2=both, 3=vert dotted, 4=horz dotted, 5=both. See XTR'SHOWGRID.
XTR’HEADERSTYLE | B,1 | in | Column header style flags
XTR'HIDEHEADER | B,1 | in | Hide headers? (0=no)
XTR'ITEMLINES | B,1 | in | Display lines per item.
XTR'KBDSTR | S,10 | in | Click code.
XTR'LEFTINDEX | B,1 |  | Left-most visible column
XTR'LEFTPANECOLS | B,1 | in | Number of columns in left pane.
XTR'LEFTPANEWIDTH | B,1 | in | Width of left pane.
XTR’MISCFLAGS | B,1 | in | Misc flags (overlays xtr’truncated, which is now deprecated)
XTR’NFSELSTYLE | B,1 | in | Determines how selected item(s) are highlighted, mostly when tree is inactive
XTR'OPCODE | B,1 | in | Opcode.
XTR'PARENTID | B,2 | in | ID of parent of control (e.g. a dialog). To specify parent by its alphanumeric control name, set xtr'parentid to zero and add the ParentID=<name> clause to any column; see Advanced Coldef Options.
XTR'ROWHDRSTYLE | B,1 | in | Options related to row headers. See XTR’SHOWROWHDR.
XTR'SCROLLTIPS | B,1 | in | Show scroll tips (0=no)
XTR’SEARCHMODE | B,1 |  |
XTR'SELECTAREA | B,1 | in | Clickable area and style.
XTR'SHOW3D | B,1 | in | Use 3D style? (0=no).
XTR'SHOWBUTTONS | B,1 | in | Show expand/collapse buttons for level 0. These "buttons" are in addition to the standard clickable +/- indicators.
XTR'SHOWBUTTONS0 | B,1 |  | No longer used. See XTR'SHOWBUTTONS.
XTR'SHOWFOOTER | B,1 | in | See XTR'FOOTERSTYLE.
XTR'SHOWGRID | B,1 | in | Show grid lines (0=no, 1=yes). Sample image here.
XTR’SHOWROWHDR | B,1 | in | Determines whether row headers are displayed.
XTR'SKEY | S,10 | in | Search key.
XTR'SORTORDER (3) | B,1 | in/out | 0=ascending, 1=descending
XTR'TARGETCOL | B,1 | in/out | Column of "target" cell; see XTR'TARGET...
XTR'TARGETROW | B,4 | in/out | Row of "target" cell; see XTR'TARGET...
XTR'TIMEOUT | B,4 | in | Timeout (ms)
XTR'TOPINDEX | B,4 | in/out | Force the initial display vertical scroll position.
XTR'TREELINESTYLE | B,1 |  | Style of lines linking child lines to parent: 0=none, 1=solid, 2=dotted
XTR'TRUNCATED | B,1 | in | Show dots if text truncated? (deprecated, replaced by XTR’MISCFLAGS)
XTR'USECOLORDER | B,1 | in | Use COLORDER() to reorder?
XTR'USETHEMES | B,1 | in | Use Windows themes? (0=no)
XTR’USRCFG | B,1 |  | Used for Saving User Adjustments.
XTR'XCOL | B,1 | in/out | Column of last cell to have the focus. (see xtr'xrow and xtr'targetcol)
XTR'XNAVCOD | B,1 | in/out | Used in cell editing
XTR'XNAVMASK | B,1 | in/out | " " " "
XTR'XROW | B,4 | in/out | Row of last cell to have the focus. See XTR'TARGET...
XTR'XVALIDATE | B,1 | out |


XTR'OPCODE

XTR_OPCODE determines the operational mode, from one of the following choices. See ashell.def for the symbol definitions.

Symbol | Value | Description
XTROP_CREATE | 0 | (0) Normal usage. Create a new control.
XTROP_REPLACE | 1 | (1) Use existing control but replace data within it
XTROP_APPEND | 2 | (2) Append data to an existing control
XTROP_DELETE | 3 | (3) Deletes an XTREE control, and is only necessary when the control was created with the XTF_MODELESS flag (otherwise it is deleted automatically). Note that you can also delete the XTREE control (like any other control) by clearing the screen with Tab(-1,0).
XTROP_RESELECT | 4 | (4) Reselect from an existing control
XTROP_DELSEL | 5 | (5) Delete selected rows
XTROP_PRINT | 6 | (6) Print and print preview via APEX


XTROP_CREATE

Updated March 2011

In this, the "normal" usage mode, a single XCALL XTREE causes the control object to be created and loaded with data. Unless the XTF_NOSEL flag is specified, the control will then receive the focus and wait for the user to perform an action that causes it to exit. On exit, unless the XTF_MODELESS flag is set, the control is deleted. If both XTF_NOSEL and XTF_MODELESS flags are set, the operation is essentially display—i.e. create the tree if necessary, configure it, load the specified data, display it, and return.

You may specify the XTREE control number (0-31) in XTR'CTLNO or or set it to -1, in which case the next available XTREE control control number will be used (and returned in XTR'CTLNO). If an XTREE control already exists with the specified number, the opcode will effectively be converted to XTROP_REPLACE, except that certain optimizations will be adjusted to work better for the case of a complete replacement of the tree contents (whereas XTROP_REPLACE is normally optimized for the case where only some of the data elements are changing).


XTROP_REPLACE

Updated March 2011

The XTROP_REPLACE operation allows you to replace the contents of an existing tree, without actually deleting the tree and recreating it. This is similar to XTROP_CREATE, except that it is optimized for the case where the new tree contents are similar to the old (same layout with minor additions/deletions/changes, as opposed to a complete new tree configuration). If the changes are particularly minimal, you can specify the XTF_NOREDRAW flag to minimize the visual "flash" that otherwise may occur when the various visual attributes are recreated and re-optimized.

ATE Notes

When using opcode XTROP_REPLACE in array mode, the server side of XTREE compares the new data Array with the old and applies two optimizations designed to minimize the amount of data sent between the server and ATE client. If the data is completely unchanged, it switches to XTROP_RESELECT, which eliminates the need to transmit or re-load the new data array entirely. Otherwise, if only a few rows have changed, then only those rows are transmitted and re-loaded. These optimizations are mostly useful in situations where cell-to-cell movement causes an exit and reentry, and you are obligated to use XTROP_REPLACE rather than XTROP_RESELECT because you have to make minor changes (such as updating a few other cells in response to a cell editing change), or you can't be sure if the data actually changed because you have to recreate the data from primary sources. A multi-user appointment scheduler would be an example of the latter, where you have to reload the schedule data from the database because you don't know if another user made a change in the meantime.

These optimizations have evolved over the period from edits 1150 to 1200, the server and client coordinate with each other to use only the optimizations that both understand, but work best when both sides are at the newest level.


XTROP_APPEND

The append operation is just like replace, except that the data passed in the source array or file is appended to the existing data in the control. In the case of array mode, the best way to handle this is to define an array large enough for all the items. For example, you might plan on a maximum of 1000 items, but initially load only 50. If you then append another 75, put them in the array positions from 51 to 125, and specify ARRAY(51) as the Array parameter and 75 for the Itemcount parameter. This way, your array continues to correspond to the current state of the list, so that you can make sense of the returned selection information.

Warning: XTROP_APPEND is incompatible with cell editing. If you want to append rows to a tree that has editable cells, you should do it in two steps:

• Do the append with the XTF_NOSEL flag added, which will cause the operation to exit immediately without waiting for a selection or for any cell editing.

• Use XTROP_RESELECT to resume editing the expanded set of rows.

The alternative would be to just add the new rows to your data and answer arrays, then use XTROP_REPLACE with Itemcount set to the new total number of rows. As a result of various optimizations to XTROP_REPLACE since XTROP_APPEND was first introduced, the overhead of the replace operation is probably little different from the append anyway.


XTROP_RESELECT

The XTROP_RESELECT operation is used to re-enter (i.e. put the focus on) an existing (modeless) tree. It is similar to the create, replace, and append operations except without the overhead of recreating/reconfiguring the control or reloading the data. The Array or File parameter is ignored. For editable trees, the Answer array is processed though, allowing you to make changes to the context or attributes of the corresponding cells. For example, after the user makes changes to one cell, causing the tree to exit, the application may make additional changes to related cells prior to putting the editing focus on the next cell.

For non-editable trees, the initial selection(s) is/are typically determined by the Answer parameter. For editable trees, the XTR'TARGETROW, XTR'TARGETCOL, XTR'XNAVOD and XTR'XNAVMASK parameters in the Xtrctl structure typically determine the position of re-entry. The primary exception to the typical case is when the last event for the tree in question was a click that generated an exitcode when the tree was inactive/unfocused, the location of the click will take precedence over the answer or XTR'XXX parameters. The scenario is as follows. Imagine that some control has the focus, say, an input field. The user then clicks on an XTREE that was inactive. This generates an exitcode (based on the XTR'KBDSTR field of the clicked-on tree), causing the input field to exit. The user's expectation would be that the tree would become active, with the row or cell clicked on being selected. The application can tell from the exitcode which control (or which tree) was clicked, but it can't tell which row or cell was clicked, so it can't set up the answer or XTR'XXX parameters to start with that row or cell selected. However, the tree itself has local memory and can remember the the fact and location of the prior click event; it uses that information to override the selection coordinates passed by the application. In cases where you don't want that feature, you can set the XTR2_CLRDEFER bit in the Flags2 parameter.

The XTRA4 and PCKMNU programs in the EXLIB library illustrate this.


XTROP_DELSEL

This opcode deletes just the row(s) identified by the Answer parameter. It acts similarly to XTROP_RESELECT, not loading any new records. But instead of selecting the row(s) identified by answer, it deletes them. It then waits for a new selection, unless the XTF_NOSEL flag is set, in which case it exits immediately. Note that the original data rows are not internally renumbered, so if you are trying to keep your internal array synchronized with the control, you should only mark the items deleted but not compact the array. For example, if you delete item #2, then reselect from the same array, item #3 will appear in position #2 on the screen, but if you select it, it will still be identified as item #3.

XTROP_DELSEL will mainly be of use in situations where you have a large number of items, making it inefficient to delete and reload the entire control each time you want to get rid of one. This would be particularly true if you did not really need to keep track of the items being deleted within the context of the original array. (For example, you might start with a list of possible items to choose from, and then as you choose them, they are deleted from that list and moved to another list, like in a shopping cart application. You do not really need to keep track of the state of the original list, because when the order is confirmed, you would work from the list of chosen items, rather than from the list of available items.)

See the sample program XTRA4 for an illustration of moving items between two XTREE controls.


XTROP_PRINT

Added November 2007

This option invokes a variation of the APEX Print/Preview facility to allow the contents of the specified XTREE to be printed, with an initial print preview mode. Sample image here.

Unfortunately this cannot be invoked in such a way as to allow the XTREE data to be merged with other application-generated data in the same report, but may still be a useful utility function. Note that you can also invoke the operation from the special control dialog reachable via Ctrl+Shift+Double-Right-Click.

Notes

Normally, XTROP_PRINT is used to print an existing TREE control, which is referenced via the XTR'CTLNO parameter. In this case, the print-related options will already have been established when the tree was created, and the coldef parameter passed with the XTROP_PRINT call will not be processed. Thus, any print-related flags such as XTF2_LANDSCAPE, and coldef options, such as Title need to be established when the tree is created, not when it is printed.

If you want to adjust the tree configuration prior to printing, it is best to set XTR’CTLNO to -1 to create a new instance of the control just for printing. In this case, all of the parameters will be processed, just as they would with XTROP_CREATE. This method requires 5.1.1156+.

The printing logic ignores columns that do not fit within the width of the page. (In order to print additional columns, you would need to recreate the tree using the technique mentioned above, with alternate column layouts.)

To adjust the page headers and footers when printing from XTREE, see the Advanced Coldef Options topics "Footer" and "Title.".

History

2007 November, A-Shell 5.1.1100: Added to A-Shell


XTR'CTLNO

Updated & Reviewed November 2010

When multiple XTREE controls are in simultaneous use, specifies which one (range is 0 to 31) to use for this call. If XTR_OPCODE = XTROP_CREATE, you can set XTR’CTLNO to –1 to have XTREE automatically assign the next available control number. (If the control is modeless, you will need to save the returned XTR’CTLNO value for referencing it in subsequent calls.)

Note: XTR'CTLNO enumerates/identifies only the XTREE controls, using a numbering scheme only meaningful to XTREE. See XTR'CTLID for the standard control ID (which can be specified in the AUI_CONTROL ctlid parameter) to perform standard control operations on the XTREE control (aka hide, move, etc.)

Here is an illustration of multiple XTREEs on the screen at once, for which you absolutely need to keep unique XTR'CTLNO values.

History

2009 January, A-Shell 5.1.1134: The range of XTREE control IDs has been extended from 0-9 to 0-31. In other words, you can now have 32 trees defined at once. (Believe it or not, the previous limit of 10 was cramping some programmers' style, although in some cases, the issue wasn't so much the need to have more than 10 XTREEs in existence at the same time, but the desire to use hard-coded reference numbers for them.)


XTR'ITEMLINES

Updated June 2013; see History

For XTREE controls with variable height items (XTF_VARY), specifies the maximum number of lines of text that will be displayed for a single item. For fixed height items (i.e. when then XTF_VARY flag is not specified), XTR'ITEMLINES determines the display height of every row. Sample image here.

Value | Description
-1 or 255 | Produces a row height equal to that needed for editable cells, which is typically about one and a half rows high. (This is automatic when the tree contains editable cells.)
-2 | Adjust row heights to largest row font (+4 pixels leading)
-3 | Same as -2 but with only 3 pixels of leading
-4 | Same as -2 but with only 2 pixels of leading
-5 | Same as -2 but with only 1 pixel of leading
-6 | Same as -2 but with no extra leading
-8 | See history

History

2013 June, A-Shell 6.1.1354: Add support for -8. Although -6 theoretically provides no extra leading, it turns out that when using the XTF_VARY flag, the rows are more tightly spaced than XTR'ITEMLINES = -6 (without XTF_VARY); XTR'ITEMLINES = -8 comes closer to the emulating the XTF_VARY spacing.

2012 April, A-Shell 6.0.1248: Add support for -3, -4, -5, -6

2011 September, A-Shell 5.1.11233: Add support for -2


XTR'SELECTAREA

This field actually encodes two separate parameters for related sets of options. One defines the area in which you may click to make a selection, and the other defines how the selection is highlighted. Choose one from the Area options and one from the Style options:

Area Options

Symbol | Value | Description
XTRSEL_AREA_ANY | &h0000 | Anywhere on row, including tree lines, row headers
XTRSEL_AREA_CELLS | &h0001 | Any cell of row
XTRSEL_AREA_CELL1 | &h0002 | Only first cell of row
XTRSEL_AREA_CELL1T | &h0003 | Only text in first cell of row

Style Options

Symbol | Value | Description
XTRSEL_STY_ALL | &h0000 | Highlight entire row
XTRSEL_STY_CELLS | &h0010 | Highlight all cells of row
XTRSEL_STY_NONE | &h0020 | Eliminates the blue selection bar, in which case the only indication of which is the current item will be a dotted outline around the contents of the first cell. Why would anyone want to make the selected item hard to see? Because in trees which operate more as grids, the blue highlighted cell in the first column may be confusing or aesthetically incongruous. Note that this only applies to single-select trees.
XTRSEL_STY_CELL1 | &h0030 | Highlight first cell only
XTRSEL_STY_CELL1T | &h0040 | Same as XTRSEL_STY_CELL1 but highlight only the text (rather than the entire cell).
XTRSEL_STY_ALL_GRD | &h0050 | STY_ALL + gradiant; see Note 1, below
XTRSEL_STY_CELLS_GRD | &h0060 | STY_CELLS + gradiant; see Note 1, below
XTRSEL_STY_CELL1_GRD | &h0070 | STY_CELL1T + gradiant; see Note 1, below
XTRSEL_EDIT_KEEP | &h0080 | Keep the first column selection indicator (blue bar) on during editing. Depending on the tree layout and other factors, you may find this more aesthetically pleasing. (In particular, it reduces the "flash" when cell-to-cell movement requires exit/re-entry.)

Note 1: These are equivalent to the existing options (without the _GRD suffix) except that if the version of Windows supports the GDI+ subsystem, the selection bar is turned into a gradiant with a dotted outline. (Eye candy)


XTR'KBDSTR

Updated April 2014

This field may be used to specify a click string (see Virtual Key Symbolic Names) to generate an exitcode when the XTREE control is clicked while inactive, e.g. "VK_xrF401". Since the field is only ten characters long, to allow for longer forms of the click string to be used, the initial "VK" may be omitted, e.g. "_xrF401".

For standard click strings, although the exitcode does not capture information about the specific location of the click within the control (i.e. row and col), this information is made available internally to the target control so that when the application activates it, the control has the possibility of responding to the location, for example, to select the row clicked on. For single-selection trees, in order for this to work, you must set the answer parameter to 0, otherwise the specified answer value will override the clicked row to determine the new selection. For multi-selection trees, the clicked row will be added to the existing selections. An extended from of the click string (described below) allows the exitcode to be customized to indicate the row and/or column where the click occurred.

Coordinates on Inactive Trees

You may also use XTR'KBDSTR to retrieve row and/or column coordinates of click events on inactive trees, by coding the XTR'KBDSTR field as follows:

_x{r}{d}F##{R..R}{C..C}

In other words, using the standard Virtual Key Symbolic Name syntax, except with the leading "VK" removed, and with some of the numeric digits at the end replaced with a string of zero or more "R" characters (representing row digits) and zero or more "C" characters (representing column digits). For example:

_xF1RRRC

The above format would return exitcodes in the range of -10000 thru -19999 where the last digit represented the column clicked on (1-9) and the next three digits to the left represent row clicked on (1-999). So -10493 would indicate that the user clicked on row 49, column 3. -10000 would indicate some kind of click event that wasn't specifically on a particular cell.

_xrF2RRRR

The above would be useful in cases where you just wanted the row number, and would return exitcodes from -20001 to -29999 for rows 1 thru 9999. As with standard extended virtual key codes, the "r" in between the "_x" and "F" indicates that right clicks will be distinguished by returning a positive exitcode value rather than negative.

_xF5CC

The above example returns exitcodes -501 thru -599, representing clicked columns 1 thru 99.

See Also

• Clicks on Inactive XTREEs

• Sample program XTRA4.BP in the EXLIB.

History

2013 October, A-Shell 6.1.1383: An inactive right-click on a tree now always sends the standard left-click exitcode, regardless of whether the XTR'KBDSTR field contains an "r". Normally an "r" is required, e.g. "VK_xrF101", to support right click, and in that case the exitcode is positive rather than negative. But in this case, the only logical application response is to XCALL XTREE in either case, so making a distinction was just leading to application bugs.

2013 March, A-Shell 6.1.1345: Add ability to retrieve row and/or column coordinates of click events on inactive trees. Eliminated 16-bit bottleneck that limited exit codes to the range of +/- 32K. If using ATE, both the server and client must be at least 6.1.1345.0 in order for XTREE to handle an inactive click exitcode from another XTREE, outside the +/- 32K range.


XTR'SKEY

If this field is non-null, and the current XTREE is in single-select mode, and the XTR'COLUMNACTIVE parameter is not zero, then the initial selection is established by searching the active column for the specified string (overriding the ANSWER parameter, which normally sets the initial selection). Note that:

• SKEY does not require a trailing null

• A match will succeed as long as the contents of SKEY matches the start of the data in the column (i.e. "Ab" will match "Abbey Road").

• SKEY is not cleared or set by XTREE


XTR'TOPINDEX

Updated August 2010

This field may be used to force the initial display vertical scroll position. To activate the feature, set XTR'TOPINDEX to the desired first visible row (1=first). Once set, it will be updated on exit, so that a subsequent re-entry will enter in the same position. To disable the feature, set it to 0. Note that this will override the default logic which normally tries to position the vertical scroll so that the initially selected row is visible.

XTR'TOPINDEX may be set to -1 on input in order to tell XTREE to return the new topindex on exit, but not to attempt to set it on entrance. This applies only when re-entering an existing tree with XTROP_RESELECT or XTROP_REPLACE with XTF_NOREDRAW set, and with XTR'TARGETROW=0.

XTR'TOPINDEX is not returned relative to an inactive XTREE when the inactive tree is clicked while another tree has the focus. This was conflicting with the new-and-improved logic for handling clicks on inactive trees. The optimum way to respond to a click event on an inactive XTREE is to set XTR'TOPINDEX, XTR'TARGETROW, and XTR'TARGETCOL all to 0 before entering the clicked-on tree (using XTROP_RESELECT).


XTR'DELCTLID

This field may be used to specify the ID of a control that should be deleted just before XTREE updates its display and starts waiting for user input. This is handy for deleting "in progress" displays (see Animated Graphics) that you create prior to calling a large or complicated XTREE that may take more than a couple of seconds to load. See the sample program XTRA7 for an example of this.

Note that XTEXT has an analogous field (txc'delctlid) in its txtctl parameter. All of the comments in this topic relating to XTR'DELCTLID and XTREE apply equally well to txc'delctlid and XTEXT.

This field is declared as B,4 rather than the usual B,2 used for storing control IDs to allow for the possibility that the control you want to delete when XTREE becomes active, was actually created externally. In that case, it would not have an A-Shell control ID, but it would have a standard window handle, which you can place in this field instead of the control ID. See MX_FINDWINDOW for one possible method of determining the window handle of an externally-created 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 will not 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 bit to its ctype. Since modeless dialogs do not automatically become the parent of controls with no explicit parent of their own, the XTREE will remain independent.

• Do not 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'EXPANDLEVEL

This field allows you to control the expanded/collapsed state of the items when the tree is created or re-entered. Set the field to a value between 0 and 9, indicating the maximum level to expand (0=all items collapsed so that only the level 0 items are visible, 9=all items expanded). You may optionally specify one of the two flags listed below:

Symbol | Value | Description
XTEXPF_SAVE | &h40 | Save current expand/collapse status on exit
XTEXPF_RESTORE | &h80 | Restore saved status (on XTROP_REPLACE reentry)

Notes

XTEXPF_SAVE can be used with any of the level values (0-9) in XTR'EXPANDLEVEL to start out with the specified uniform level of expansion but save the user-modified status on exit. But XTEXPF_RESTORE overrides all other options (unless there was no previously saved status, in which case XTEXPF_RESTORE is ignored).

XTEXPF_RESTORE assumes that the order of the rows has not changed since the previous exit from that tree. Since the expand/collapse status is associated only with the row numbers as displayed, changing the sort order on reentry would result in the wrong items being expanded or collapsed.


XTR'COLORDER

This field provides a means of rearranging the display order of the first (up to) 31 columns. As background, if the XTF_REORD flag is specified (and the cformat K is not specified on the columns in question), XTREE allows users to re-order the columns by dragging and dropping the column headers. This, combined with the horizontal scroll capability, may lead to a situation where, in order to satisfy different user desires, an application loads an XTREE with many more columns than can be seen at once, figuring that users can always scroll, or even drag the columns around as desired. But after the initial thrill wears off, the users tire of this routine and would be much happier if they could preserve their own preferred column order. The XTR'COLORDER array, along with the XTR'USECOLORDER field/option, makes this nearly trivial to support. Just set XTR'USECOLORDER to 1 and XTREE automatically saves the updated column arrangement in the XTR'COLORDER() array. All the application needs to do then is to save those 31 bytes in a user preferences file so that it can be recalled the next time the user wants to see this particular XTREE.

Notes

XTR'COLORDER(1) specifies the "real" column which is displayed in the first position; XTR'COLORDER(2) specifies the "real" column displayed in the second position, etc. If the user shrinks a visible column to zero width, effectively making it hidden, this will be noted in the array by adding +128 to the column number.

If you are manually using XTR'COLORDER to set a column order, you do not have to specify all the columns. For example, if there were 10 columns defined, you could determine which of the 10 displayed in the first three positions as follows:

xtr'colorder(1) = 5 ! real column #5 will be displayed first

xtr'colorder(2) = 8+128 ! real column #8 will be second (but will be invisible)

xtr'colorder(3) = 2 ! real column #2 will be displayed third

xtr'colorder(4) = 0 ! remaining columns will retain their natural

! order, i.e. 1,3,4,6,7,9,10

(The first zero in the XTR'COLORDER array effectively terminates the forced part of the ordering, with the remaining columns using "natural" ordering.)

Unless you set the XTF_REORD bit in the flags parameter, the user will not be able to reorder the columns by drag-and-drop, but that would not stop the application from using XTR'USECOLORDER and XTR'COLORDER to override the natural (or "real") column ordering.

Changing the display order of the columns does not affect the way columns are numbered in any of the other parameters (such as XTR'COLUMNSORT, XTR'COLUMNACTIVE, etc.) In other words, the application does not need to be "aware" of how the columns are ordered.

See Also

• Saving User Adjustments

Update: A-Shell 958.3.1 - 27 June 06

XTREE now allows you to hide a column by using the mouse to shrink its width to 0. (Actually, you could always have done this, but now, if XTR'USECOLORDER=1, XTREE sets the corresponding entry in the XTR'COLORDER array to <position>+128, which effectively causes the column to remain hidden on subsequent calls to reselect from the tree.

This can be demonstrated easily in the XTRA3 sample program: use opcode 0 and set the modeless option to create/display the tree; then manually shrink one or more of the columns to become invisible. Then exit the tree and re-enter it with opcode 0 or 1 to verify that the column remains hidden. (Use the popup menu option to unhide them.)


XTR'TIMEOUT

The timer is reset after each keystroke and after each mouse event. (So you can avoid the timeout by just wiggling the mouse.)

If the timer expires, XTREE will return EXITCODE=11 (like INFLD timeout).


XTR'LEFTINDEX

Added March 2015; see History

This field allows the application to control the horizontal scroll position on entering the tree.

The field acts analogously to XTR'TOPINDEX, substituting the left-most visible column for the top-most visible row. When set by the application, XTREE will attempt to set the horizontal scroll so that the specified column (first column = 1) is visible at the left edge of the display window. This however will be overridden if necessary to make the target column (XTR'TARGCOL) visible, or if it is simply impossible to accommodate.

As with XTR'TOPINDEX, if the XTR'LEFTINDEX field is non-zero on entrance, it will be updated on exit to indicate the left-most column that is partially or wholly visible on exiting the tree. Since the field resolution doesn't support fractional columns, this may result in a partial-column shift when exiting and re-entering. You can avoid that by either setting the field back to zero, or specifying the XTF_NOREDRAW flag.

History

2015 March, A-Shell 6.1.1306: Field added to A-Shell


XTR'LEFTPANECOLS

This specifies the number of columns to be in the left pane. Note that this counts physical columns that have a non-zero data width, whether or not the column is hidden, and it is based on the order in which they are defined in the coldef parameter (not necessarily the order they appear in the physical input data.) So columns which use cpos and cwidth of 0 do not count, but all other columns do (including the special column needed for multi-level support, hidden color columns, etc.)


XTR'LEFTPANEWIDTH

This may optionally specify a display width for the left pane, using the same column units used by the dspwid parameter (for defining column widths). If zero, then XTREE will try to determine the optimum width by adding up the optimum display widths of the initially visible rows. You can also set it to -1 (or 255) to put the splitter bar separating the panes exactly in the middle of the XTREE.

If you specify a size that is too wide, the left pane will initially occupy the entire XTREE but the user will still be able to move the splitter bar from the right edge to make the right pane visible.

If you specify a negative value (other than -1), it acts the same as if it had been positive, except that the left pane horizontal scroll bar will be based on the specified width. This generally has the effect of initially graying out the scroll bar, which is usually desirable.


XTR'CLOSEDENDED

Revised June 2012

This field in XTRCTL allows toggling between the open-ended and closed-ended modes for the last display column. In the default open-ended case (XTR'CLOSEDENDED=0), the last column expands automatically as needed for the longest cell contents, or to fill the width of the tree, whichever is wider. This effectively disables wrap on the last column, since when adding text, you never hit the right edge. A horizontal scroll bar will be added automatically if the contents of the open-ended last column results in the combined column widths being greater than the tree display width.

In the closed-ended case (XTR'CLOSEDENDED=1), the final column width is calculated in the same way that all the other column widths are calculated, which may result in empty space between the end of the last column and the edge of the tree. To eliminate that empty space and distribute it amongst the columns,specify the XTF2_AUTOEXPCOL bit.

Examples

XTR'CLOSEDENDED=1, without XTF2_AUTOEXPCOL:

XTR'CLOSEDENDED=1, with XTF2_AUTOEXPCOL:


XTR'XVALIDATE

Modified October 2015; see History

Value | Description
1 | Value will be set to 1 if the cell indicated by XTR'XROW and XTR'XCOL needs validation. Previously you had to rely on exitcode -48 to identify when validation was needed, but this is not adequate when the event which terminates an editable cell operation is a click on another control that generates its own exitcode. In that case, the exitcode returned to the application will be that of the clicked-on control, and the XTR'XVALIDATE flag will be handy to indicate that the cell identified by XTR'XROW and XTR'XCOL needs to be validated.
2 | In some cases, the cell which needs to be validated is not the one that last had the focus, i.e. the one referenced by XTR'XROW / XTR'XCOL, but the one which gets the focus, i.e. XTR'TARGETROW / XTR'TARGETCOL. This is often the case with checkboxes, which exit for validation only when checked, and is always the case with read-only editable cells, which exit for validation just before they get the focus. In these cases, XTR'XVALIDATE will be set to 2.
3 | This could have two possible means, depending on the context. One possibility occurs when clicking out of a cell that requires post-validation and into a cell that requires pre-validation or validation-on-click, in which case it means that both the XTR'XROW / XTR'XCOL and XTR'TARGETROW / XTR'TARGETCOL cells need validation. The other possibility is that the user selected the $CBSET, $CBRST, or $CBUNDO command from a PopupMenu to set, reset, or undo the state of all the checkboxes in the current column.
4 | Indicates that the user clicked on a $CBSETDEP or $CBRSTDEP PopupMenu command to set or reset the dependent checkboxes for the current item.
5 | In an editable tree without validation, a value of 5 indicates that at least one cell was changed during the session.

See XTR'TARGET... for some detailed examples of validation scenarios.

History

2013 October, A-Shell 6.1.1363: The PopupMenu options $CBSET, $CBRST, and $CBUNDO now return EXITCODE=-48 and XTR'XVALIDATE=3 when validation (conditional or unconditional) is active for the column. $CBSETDEP and $CBRSTDEP return XTR'XVALIDATE=4.

2015 October, A-Shell 6.1.1420: Add value 5.


XTR'TARGET...

XTR'TARGETROW and XTR'TARGETCOL are used in conjunction with XTR'XROW and XTR'XCOL and cell editing to identify the cell that should next get the focus, or a click on which was responsible for forcing XTREE to exit. If XTR'XVALIDATE = 2 or 3, then this cell should be validated before re-entry. See Typical Cell Editing Scenarios for examples and more information.

When in an XTREE editable cell that requires validation, if you use the mouse on the vertical scroll bar to scroll the row out of view, the returned XTR'TARGETROW value will be set to the top or bottom of the visible range of rows, whichever is closest. This counteracts the "boomerang scroll" effect whereby using the scroll bar when in an editable cell would work only until the mouse was released, after which if XTREE exited for validation, when the app returned, the XTR'TARGETROW would still be pointing to the cell that was being edited, thus snapping the scroll operation back to the original position.

Note that when entering a non-editable multi-select tree, the XTR'TARGETROW establishes which row gets the focus. The focused row will be identified by a dotted line around it, and is not necessarily selected nor even visible, but when you use the DownArrow, the focus and selection will move to the next row below the one that had the focus. XTR'TOPINDEX works in multi-select mode also, to set the vertical scrolling position. Prior to A-Shell 997.3, the first selected row over-rode the XTR'TOPINDEX.


XTR'SEARCHMODE

Subroutines > XTREE > XTREE Parameters > Xtrctl
XTR’SEARCHMODE

The options are defined as follows (in ashinc:XTREE.DEF)

Symbol | Value | Description
XTRSRCH_TOP_ALL | 0 | (dflt) all chars, items, from top
XTRSRCH_TOP_ONE | 1 | one char, all items, from top
XTRSRCH_NONE | 2 | no search
XTRSRCH_TOP_ALLX | 3 | like TOP_ALL but skip collapsed deps
XTRSRCH_TOP_ONEX | 4 | like TOP_ONE but " "
XTRSRCH_NXT_ONE | 5 | like TOP_ONE but start from current item and wrap
XTRSRCH_NXT_ONEX | 6 | like TOP_ONEX but " " "
XTRSRCH_NXT_ALL | 7 | like TOP_ALL but start from current item
XTRSRCH_NXT_ALLX | 8 | like NXT_ALL but skip collapsed deps

Previously, mode 0 (XTRSRCH_TOP_ALL) was always set. The options can be understood as follows:

• "_TOP" vs. "_NXT": Indicates whether the search operation always restarts from the top, or from the current item. In the latter case, it wraps from the bottom back to the top.

• "_ALL" vs. "_ONE": Indicates whether the search is based on all the characters in the cells of the current column, or just the one first character. In the _ALL case, characters typed within 1 second of the previous character are added to the search key; after 1 second, the key is reset. So for example if you type "AB" within 1 second of each other, it will search for items starting with the combination "AB" (not case sensitive). If more than 1 second passed between the "A" and the "B", it restarts the search looking for items beginning with "B". The "_ONE" option effectively sets the timer to zero, so that each character typed restarts the search.

• "X" (_ALLX, _ONEX): The "X" on the end indicates that collapsed child items are skipped. Otherwise, the search considers all items, and if it matches a collapsed child item, that child and all its siblings and parents are expanded.


XTR'MISCFLAGS

Subroutines > XTREE > XTREE Parameters > Xtrctl
XTR’MISCFLAGS

Updated May 2015; see History

A collection of miscellaneous on/off options affecting the entire tree:

Symbol | Value | Meaning
XTMF_TRUNCATED | &h01 | Show "…" if cell contents need to be truncated for display. This field overlays the old XTR’TRUNCATED field, which is now deprecated.
XTMF_INTHEIGHT | &h02 | For trees with fixed-height items (see XTF_VARY in Flags), adjusts overall tree height to avoid the partial display of an item at the bottom.
XTMF_INHERITBG | &h04 | Causes the left margin area (if any) to inherit the background color of the first column, rather than the default background color of the tree. See example below.
XTMF_STDPRGBAR | &h08 | Causes a standard progress bar to display during loading of large trees over ATE connections. See "Loading," below.
XTMF_CUSPRGBAR | &h10 | Same as above, but instead of creating a progress bar, uses one created by program. See "Loading," below.
XTMF_LOADABORT | &h20 | Allows user to ESC to abort the loading process; result is same as if user waited until tree was displayed and then hit ESC (exitcode 1). See "Loading," below.
XTMF_EDITONLY | &h40 | Causes XTREE to attempt to remain in cell editing mode, and avoiding selection mode, to the extent reasonable possible. There are still situations and events that will result in XTREE reverting to selection mode, but this option will minimize them.
XTMF_NOEXTARGET | &h80 | This addresses an obscure situation involving dual editable trees. Normally, if the user clicks on Tree #2, row X, col Y while editing Tree #1, the return value of XTR'TARGETROW and XTR'TARGETCOL will be set according to clicked cell in the external Tree #2. XTR'XROW / XTR'XCOL will be set to the cell Tree #1 that was last active at the time of that external click. If the XTMF_NOEXTARGET flag is set, the location of click in the external tree is ignored and the returned XTR'TARGETROW / XTR'TARGETCOL will be set the same as XTR'XROW / XTR'XCOL, i.e. to the cell last active before the click. A rationale for this subtle feature may be found in this A-Shell Forum post.

Examples

Here are examples of the effect of the XTMF_INHERITBG flag. In the left image the flag is set, in the right image it is not:

inheritbg1

inheritbg0

Loading

The three loading-related flags provide options to improve the user interface during loading of large trees over ATE connections, which might take several seconds and therefore leave the user wondering if the process died or something went wrong.

If using the custom progress bar option (XTMF_CUSPRGBAR), you must create your own progress bar with a control id of "xtrProgBar". Optionally, you can embed it inside of a container dialog, along with other controls. If you want the container dialog deleted when the tree is ready to display, it must have the control id "xtrProgDlg".

Note that the progress bar/dialog option probably supersedes the XTR'DELCTLID feature, although they are not mutually exclusive. The progress bars are handled exclusively on the client side during the data transfer to ATE, while the XTR'DELCTLID feature is handled on the client side.

History

2015 May, A-Shell 6.1.1409: Add XTMF_NOEXTARGET

2013 May, A-Shell 6.1.1352: Add XTMF_EDITONLY

2013 April, A-Shell 6.1.1349: Add XTMF_STDPRGBAR, XTMF_CUSPRGBAR and XTMF_LOADABORT to help with time problems when loading data over telnet connections. See "Loading" above.


XTR'NFSELSTYLE

Subroutines > XTREE > XTREE Parameters > Xtrctl
XTR’NFSELSTYLE

This flag determines how selected item(s) are highlighted. All but the last option apply only when the control does not have the focus.

Symbol | Value | Meaning
XTNFS_GRAY | 0 | Gray selection bar (when inactive)
XTNFS_BLUE | 1 | Blue selection bar (when inactive)
XTNFS_FRAME | 2 | No selection bar (when inactive)
XTNFS_NONE | 3 | No selection bar (when inactive)
XTNFS_NOFOCRECT | &h80 | No selection bar (when inactive)

See Also:

• XTR'SELECTAREA


XTR'HEADERSTYLE

Subroutines > XTREE > XTREE Parameters > Xtrctl
XTR’HEADERSTYLE

This field supports flags relating to column header style. The style flags are:

Symbol | Value | Meaning
XTHSF_VCENTER | &h00 | vertically centered in header cell
XTHSF_TOP | &h01 | top alignment
XTHSF_BOTTOM | &h02 | aligned at bottom of header cell
XTHSF_NOHIGHLIGHT | &h20 | headers are buttons, but don't get auto-highlighted when the column is active.
XTHSF_BTNSTAY | &h40 | header buttons stay down when clicked (if not =NOHIGHLIGHT)
XTHSF_DISABLED | &h80 | header disabled, cannot be clicked

The _VCENTER, _TOP and _BOTTOM flags control the vertical alignment of the header text. The default is XTHSF_VCENTER.

The _NOHIGHLIGHT flag causes the column headers to act/look like ordinary text cells, rather than as buttons. This will eliminate the highlighting of the column headers in editable trees, which is sometimes distracting.

The last two flags are somewhat obscure, but are documented here for completeness:

The _BTNSTAY flag causes the header buttons to stay in the down position when clicked. (Only effective when not sorting, so this is of minimal value also.)

The _DISABLED flag disables the click-sensitivity of the headers (which effectively disables sorting, so is more or less subservient to the XTF_SORT flag).

Note: In addition to these various options relating to the style of the header, be aware that you can hide the header entirely by setting the XTR'HIDEHEADER field to 1.


XTR'ROWHDRSTYLE

Subroutines > XTREE > XTREE Parameters > Xtrctl
XTR’ROWHDRSTYLE

This field supports flags relating to row header style. The style flags are the same as those used for XTR’HEADERSTYLE .

Sample image here.


XTR'SHOWROWHDR

Subroutines > XTREE > XTREE Parameters > Xtrctl
XTR’SHOWROWHDR

This field determines whether row headers are displayed, and should be set to one of the following options.

Symbol | Value | Meaning
XTRHF_NONE | 0 | no row headers
XTRHF_BTNCNT0 | 3 | display numeric buttons, starting from 0
XTRHF_TITLECNT0 | 4 | display numeric titles, starting from 0
XTRHF_BTNCNT1 | 5 | display numeric buttons, starting from 1
XTRHF_TITLECNT1 | 6 | display numeric titles, starting from 1

The difference between "titles" and "buttons" is that buttons are clickable (as a way of selecting the row item). Also see XTR’ROWHDRSTYLE for options on how they are displayed.

Here is an example of row buttons, with XTR’SHOWROWHDR = XTRHF_BTNCNT1 and XTR’ROWHDRSTYLE = XTHSF_BTNSTAY:


XTR'SHOWBUTTONS

Added December 2010

It is possible to control whether the +/- buttons (used with multi-level mode to expand/contract levels) are visible. Previously, although the (old) documentation suggested that the XTR'SHOWBUTTONS0 and XTR'SHOWBUTTONS fields controlled this, the fields were ignored and the buttons were always made visible.

The interpretation of the two fields has been upgraded to preserve compatibility with existing programs but to now allow the application to hide the top level or lower level buttons, if desired.

Symbol | Value | Meaning
 | 0 or 1 | show the buttons
XTSBF_HIDE0 | +2 | causes the top level buttons to be hidden
XTSBF_HIDE | +4 | causes the lower level buttons to be hidden

History

2010 December, A-Shell 5.1.1197: Added to A-Shell


XTR'FOOTERSTYLE

New, November 2016

You can use the two footer commands, XTR'FOOTERSTYLE and XTR'SHOWFOOTER, to define a footer, which is like a mirror of the header—i.e. a line which remains fixed and is not affected by scrolling or by loading/updating of data or answer lines.

To enable the display of a footer, set the XTR'SHOWFOOTER field to 1. The XTR'FOOTERSTYLE field can be used to adjust the attributes of the footer, using the same options as in the XTR’HEADERSTYLE field for the headers.

To define the display contents of each column in the footer, you can append a clause to the header field of the coldef. The footer clause must begin with a pair of colons (::) followed by a string of text which has follows the same syntax as for the header. For example, the following COLDEF excerpt defines a column starting in position 9, 12 characters wide, with "Qty" in the header and "Total Qty" in the footer...

COLDEF += "9~12~Qty::Total Qty~#EX~~"

In practice, you might want to replace the generic description "Total Qty" with the actual total for that column. To do that, you would need to sum the column in the application (initially, and/or after any changes to the column), and then the COLDEF string would have to be rebuilt with the updated footer definition, e.g.

COLDEF += "9~12~Qty::Total: "+TOT'QTY using "#####"+"#EX~~"

The COLDEF for an existing tree can be updated by just passing the new COLDEF string in an XTROP_REPLACE or XTROP_RESELECT call.

You may also define font, scale, and color attributes using the following new Advanced Coldef Options:

FooterFont= (same syntax as for HeaderFont)

FooterScale= (same syntax as for HeaderScale)

RGBbgFooter= (same syntax as for RGBbgTotals)

RGBfgFooter= (same syntax as for RGBfgTotals)

History

2016 November, A-Shell 6.3.1537: Footers added to XTREE.


Filidx

This optional parameter (B,4) may be specified in conjunction with file mode to create an index to the file while it is being loaded into the array. The index is dynamically allocated and kept in memory and a "handle" to the index is returned in the filidx parameter. The variable filidx cannot be used directly, nor should it be altered by the application. Its only use would be to pass it to the MX_FILEPOS function, along with the desired line number (of the selected item), in order to efficiently seek to the selected item. This is mainly of use with multiple-selection file mode, since the selected items are identified only by line number via the answer array.

See the updated XTRFIL.BP sample program for an example of using filidx.

Note that you should only use one filidx variable within a program, and you should not modify its value. If you follow this guideline, A-Shell will automatically free up the memory used by the index for each new XTREE call and when the program ends.


Xinfo

Added November 2010

This optional parameter, xinfo, may be specified to allow XTREE to return additional information. xinfo must be mapped as a string (fixed or dynamic). Note that if not using filidx, you may specify "" as a placeholder for it.

The only information returned in xinfo is a list of multiple exitcodes that apply to the tree just exited (primarily useful in trees where a single event might logically be associated with more than one exitcode). The format is as follows:

0,exitcode1,exitcode2,exitcode3,...,exitcodeN

e.g.

0,-48,-902

The first byte ("0" in the above case) indicates the format of the remainder of the string. So in order to allow programs to avoid confusion when the format of this string gets updated in the future, it should do something like this:

if xinfo[1,1] = "0" then

<process list of exitcodes>

else

<report error: unsupported xinfo format>

endif

To give an example of where multiple exitcodes might be handy, consider the case of an editable tree that also contains PopupMenu exitcodes. While editing a cell, the user may decide to right-click to see the popup menu, and then select one of the options that generates an exitcode. In this case, you may effectively have two exitcodes: one for cell validation (-48) and one for the PopupMenu selection. In this case, the validation exitcode would probably take precedence as the one returned in the main exitcode parameter. Previously, the other events would have gone without notice. Now, if the xinfo parameter is specified, the other exiticode(s) will be passed back in it, allowing the application to respond appropriately to the multiple events.

History

2010 November, A-Shell 5.1.1196: Added to A-Shell


Clicks on Inactive XTREEs

Added January 2011

When the user clicks on an inactive XTREE, it creates potential complications for the application. Typically, the XTR'KBDSTR parameter of the inactive XTREE will be used to generate an exitcode indicating which control was clicked, and the control currently with the focus will exit with that exitcode. The application would then typically call XTREE for the clicked-on tree. The complications arise when the click event has (or should have) more consequences than simply putting the focus on that XTREE.

For example, if the target tree uses SelChgExit or ClickExit, the click event might logically need to trigger one or both of those exitcodes. In the case of a right-click, if there was a context menu defined, the user would expect it to appear (in addition to the tree getting the focus).

The act of clicking on the inactive tree might also have ramifications for the control that previously had the focus, perhaps INFLD or even another XTREE. For example, in either of those cases, exit validation may be needed, which could potentially put the application the position of having to ignore the original click on the inactive tree, in order to enforce some data entry rules in the previously active tree or field.

The general procedure for dealing with these complications is (and has been) as follows:

• The click on the inactive tree generates the exitcode associated with the XTR'KBDSTR field for that tree.

• The currently active control (presumably being handled by an XCALL) exits with that exitcode.

• The application performs any exit validation or cleanup necessary for the field/control just exited.

• Assuming no problems so far, it then calls XTREE (probably with XTROP_RESELECT) to activate the tree just clicked on.

• Once activated, that tree should try to proceed with processing the secondary events associated with the click that occurred when the tree was inactive. For example, if it was a right-click on a column that had a PopupMenu, it should then display the context menu. Or if the click caused the selection to be moved to another row and SelChgExit was defined, then the tree should exit with the exitcode defined for the SelChgExit. If the inactive click was on a checkbox cell, the contents of the checkbox should now be toggled, and if validating, the tree should exit with exitcode -48. Etc.

• The XTF2_CLRDEFER flag may be specified to disable the post-reentry processing described in the previous paragraph. This would be useful in the case where the operation interrupted by the click on the inactive XTREE wasn't properly completed, causing the application to effectively ignore the inactive XTREE click. But at some point later, the application may decide to call that XTREE again for other reasons, in which case we don't want the tree to then attempt to respond to the deferred events associated with the original click. Note that this is effectively automatic after about 2-3 seconds have elapsed since the inactive click event, so the XTF2_CLRDEFER flag is only really needed when you are calling the inactively-clicked XTREE without much delay.

History

2013 March, A-Shell 6.1.1345: The inactive click may now generate row/column/cell-specific exitcodes (see XTR'KBDSTR)

2010 November, A-Shell 5.1.1196: Added Xinfo parameter added to allow tree to return multiple exitcodes


Initial View Position

If the tree control contains more rows and/or columns than can fit in the space determined by the srow, scol, erow and ecol parameters, vertical and/or horizontal scroll bars will automatically be added. By default, the initial scroll position will be at the top and to the left. Although there is no option to over-ride the scroll position directly, you can do it indirectly by specifying a row (or set of rows) to be selected, a cell to be edited, and/or a column to have the focus. The details for accomplishing this vary somewhat with the type of the tree.

For editable trees, the most direct way to establish the position is to set the XTR'TARGETROW and XTR'TARGETCOL parameters to the cell that you want to edit. This will force the cell to be brought into view (adjusting the vertical and horizontal scroll as needed). If these parameters are zero, then the initial position will be determined as it would for non-editable trees.

For non-editable trees, the vertical position will be determined by the initially selected item(s). For array-based trees, and file-based trees which are either multi-select or have the XTF_FILANS flag, this is determined by the value(s) passed in the answer parameter. For single-select file-based trees without the XTF_FILANS flag, the initially selected row is determined by the string in the array parameter. In all of these cases, XTREE will adjust the vertical scroll so that the selected item (or first selected item in the case of multi-selection) will be visible.

An exception to the above is that the combination of XTR'SKEY and XTR'COLUMNACTIVE may be used to select an initial item by searching for a matching string.

The horizontal scroll position (for non-editable trees, or when XTR'TARGETROW and XTR'TARGETCOL are zero) is determined by the XTR'COLUMNACTIVE parameter.

Note that item numbers and column numbers are always based on the initial order in which they are loaded or defined. Sorting and column reordering will obviously affect the display order, but will not affect the internal numbering. Thus, even if you select the first item and set the first column to be active, this could result in the tree being scrolled to the bottom and far right (or any other position) depending on the sorting and column reordering options.


Mouse and Keyboard

XTREE follows most of the standard Windows keyboard and mouse conventions. The following describes some of the special cases that might not be otherwise obvious.

Printing:

• Ctrl+P invokes the print/previewer (see XTROP_PRINT)

Font Scaling:

• Ctrl+Plus increases the existing font sizes by about 10%

• Ctrl+Minus decreases the existing font sizes by about 10%

• Ctrl+Slash ( "/" ) resets the fonts to the original sizes

Locating and Selecting Items:

• Use the Up/DownArrow keys, or a single LeftClick to move the selection bar. Note that when the XTF_UP and/or XTF2_DOWN flags are specified (to enable exiting the tree with up and/or down arrow), there must be a delay of 1/3 or more seconds prior to the up or down key press in order for the exit operation to take place (so as to minimize the chance of accidentally exiting while rapidly scrolling up or down the items). Note also that the ClickExit clause can be used to cause a single click to exit.

• To locate an item by its text, click once in the relevant column (to make that column be the "active" one), then type the character(s). As you type, it will select the first row whose cell text in the current column matches what you've typed. The match logic resets after a delay of approximately one to two seconds without any characters being entered. Note that clicking on the column header may sort the column (see Sorting). Also note that the default "active" column is established by the XTR'COLUMNACTIVE field in xtrctl.

• Hit Enter or Double-Click to exit with the current item selected.

Multi-level trees:

• The Plus and Minus keys (on the main keyboard or on the numeric pad section) are equivalent to clicking on expand/collapse button for the current level.

• Ctrl+Shift+Plus and Ctrl+Shift+Minus expand or collapse all levels.

• Ctrl+UpArrow and Ctrl+DownArrow moves the selection bar to the prev/next item which is at the same level as the current item, but which has a different parent. If necessary, this will cause the target item to be made visible by expanding its parent(s).

• Provided there is no conflict—i.e. in the absence of XTF_EDITABLE, XTF_LEFT, or XTF_RIGHT—Left/RightArrows act similarly to Plus/Minus (expand/contract) but also move the selection up or down to the next level, allowing rapid navigation of multi-level trees with just the arrow keys. You can force this behavior to override conflicting flags by using the compound cformat code "@@" instead of just "@". Feature added in 5.1.1220.

Multi-Selection Trees:

• Ctrl+A selects all items, Ctrl+B deselects them.

• LeftClick selects current item, clearing all other selections.

• Ctrl+LeftClick toggles the current item, preserving other selections.

• Shift+LeftClick selects all the rows from the previous selection to the current row.

Trees with Editable Cells:

• Tab and Shift+Tab change the focus to the next/prev editable cell, provided the XTF_TAB flag is not set.

• Arrow keys will navigate between cells that do not themselves trap the arrow keys for editing purposes. For example, editable text cells would trap the left and right arrows for editing within the cell. In such cases, you can use Ctrl+Arrow for inter-cell navigation. See Combo Boxes for more details.

• LeftClick on a cell to select it for editing. Note that depending on the cell validation options in cformat, and possibly a ClickExit clause, clicking on another cell may cause XTREE to exit back to the application for validation purposes.

Combo boxes:

• When the focus is on a combo box within a cell, the up/down arrows would normally cycle among the possible selections. But if the ScrollMode=Tree clause is specified, unless the drop-down list is visible, the up/down arrows advance to the prev/next row (as if Ctrl+Up or Ctrl+Down).

• For selection-only combo boxes (where you are limited to selecting one of the predefined choices), if the list of choices includes a blank item, then the Delete key (or Spacebar) will select it. Alphanumeric keys will select the first item that starts with the specified character.

Dropdown Lists:

• When the focus is on a cell containing a dropdown list (which differs from a combo box in that you can only select among the existing choices – see List) typing a character will jump to the first matching item in the list. If there are multiple items which start with the same character, hitting the character again will cycle among them. This can be seen in the XTRA5 example program, where hitting "B" repeatedly while in the Description column will cycle between "Boxer", "Bell Bottoms", and "Black Standard Tee".

Checkboxes:

• Spacebar or LeftClick to toggle the checkbox.

Extended Checkboxes (T+):

• Ctrl+A sets (ticks) all enabled checkboxes in the column, Control=B resets (clears) them.

• LeftClick on an clear box sets it, and if followed by Shift+Click on another clear box in the column, will set all the boxes between them, inclusive.

• Ctrl+Z undoes either of the above actions, if executed while a checkbox in the affected column has the focus and no intervening events have occurred.

• RightClick may display checkbox-specific context menu options if defined (see Editable checkbox)

Popup Menus:

• If a popup (or "context") menu is defined (see PopupMenu), use a single RightClick to display it.

Column Configuration:

• To reorder columns (if enabled via the XTF_REORD flag), use the mouse to drag the columns by their headers. See XTR’USECOLORDER (in xtrctl) and Saving User Adjustments for details on how/whether such column reordering will be automatically remembered.

• To resize columns (if not disabled by the coldef "L" code or limited by the Dspmin in Advanced Coldef Options), click on the right vertical border of the column (when the mouse cursor changes to a double arrow) and drag the column border left or right.

• Ctrl+Plus (Ctrl with the plus key), Ctrl+Minus (Ctrl with the minus key) and Ctrl+Mousewheel will increase or decrease the size of all of the text in the tree by approximately seven percent.

• Ctrl+Slash (the slash may need to be on the numeric keypad) will reset the text to the original size. (Equivalent to the $RESETSCALE special PopupMenu command)

• Ctrl+Shift+Slash (the slash may need to be on the numeric keypad) will reset all of the user-controlled configuration options (text size, column sizes and order) to the original settings. (Equivalent to the $RESETCFG special PopupMenu command).

• To sort the rows of the tree by the values of a column (if enabled by the XTF_SORT flag), click on the column header. Subsequent clicks on the header will cycle through the three possibilities (ascending, descending, and original). To sort by more than one column, start by sorting on the primary column, then for the secondary and tertiary sort columns, hold down the Control key while clicking the column header. Also see Sorting, the following topic, for more details.

History

2011 July, A-Shell 5.1.1225: Using the LeftArrow from a child row now jumps to the parent (provided XTF_LEFT is not set, or @@ is used to override it). Conversely, RightArrow from a parent row whose children are already expanded jumps to the first child (provided XTF_RIGHT not set or @@ is used). With this, plus the expand/contract on left/right feature added in 1220.0, XTREE now matches the handling of the arrow keys in the Windows registry editor.

2011 June, A-Shell 5.1.1221: XTREE refinement: Shift+Right within an editable text cell now marks text rather than advancing to the next cell. (Ctrl+Right advances.)


Sorting

XTREE supports both user-controlled and application-controlled sorting.

User-controlled sorting: To enable user-controlled sorting, specify the XTF_SORT flag. When specified, the user can click on a column header to sort the list based on the data in that column. On the first click, a small up-arrow will appear in the column header, indicating that the column has been sorted with the lowest value items at the top (which is actually descending order). Clicking it again will reverse the order. Multiple-column sorts can be achieved by holding down the Control key while clicking on the column headers. For example, in a tree containing columns for Countries, States, and Cities, you can sort by cities within states by clicking first on the Cities column header, then while holding the Control key down, click on the States column header.

Application-controlled sorting: The application can determine the initial display order of the rows by setting the fields XTR'COLUMNSORT and XTR'SORTORDER. This does not require that the XTF_SORT flag be set. If it is set, then the user can proceed to override the original sort order by the method described above. If the user changes the sort order, the XTR'COLUMNSORT and XTR'SORTORDER will be updated on return, giving the application the ability to later re-display the tree data in the order last specified by the user (or not).

Note the following:

• Whether user- or application-controlled, sorting only affects the display order. It has no effect on the internal order of the data. Any row index indicators passed into or returned from the routine will continue to be relative to the original, physical order of the source data. (For example, if sorting causes the first item of the source data to be repositioned to the end, selecting it will still return answer set to 1.)

• When sorting multi-level trees, the child rows are always kept with their original parents. In other words, the top level rows are sorted, then the children within each parent item are sorted, and so on.

• The sort algorithm is affected by the following codes:

XTF_SORT (enable user-controlled sorting)

XTF_TOTALS (declare last row as a total row so it does not get sorted)

Cformat codes: # (Num), S (String), D (date format), d (another date format), n (empty cells to bottom), ^ (fold)

History

2010 June, A-Shell 5.1.1185: Sorting a column by clicking on the header now cycles between ascending, descending, and original (physical array) order.


Multi-level Lists

These present some additional considerations and complications. Initially on the top level (level 0) items will be displayed. The user can click on the expand/collapse indicator at the left edge of the item to display or hide the lower level items. (See XTR_SHOWBUTTONS.) Sorting the column only sorts the top level (level 0) items. Dependents (lower level items) move with their respective parents, but are not themselves sorted within each group. (If the lower level items are visible at the time of the sort, this may give the impression that the sort did not work.) When adding items to the tree control, lower level items must immediately follow their parents. (There is currently no way to insert a lower level item, chronologically out of sequence with its parent.) Since you can only have one set of column definitions, when using multiple levels, typically the higher levels may have blank columns, and you may need to interpret the contents of the columns differently. In file mode, the level flag (as defined by the @ code in coldef ) is returned with the selection, allowing you to interpret the result appropriately. In array mode, you get back the selected array index(es) and can refer to the original array data to determine the level of the selected item(s). Note that the array index returned will be relative to the array you pass, and is not affected by sorting.


Modeless Operation

In addition to the additional programming required (multiple XCALL XTREE operations using different XTR_OPCODE values), these present the problem of how to respond to the user clicking on the list box when some other input field has the input focus (i.e. when not inside of an XCALL XTREE operation). You can prevent this problem by disabling the control on exit (see flags XTF_DISABLE) or you can define a keyboard click-to-enable string in XTR_KBDSTR, which would be received by whatever input routine had the focus at the time the user clicked on the tree control. This would allow your application logic to take appropriate action, presumably including executing a new XCALL XTREE operation. If you neither disable the pick list when inactive, nor define a click-to-enable string in XTR_KBDSTR, then the user may have the impression of operating on the control, but your program will not be aware of it. (It could, however, retrieve the current selection(s) at some later time by executing XCALL XTREE with XTR_OPCODE set to 4 and flags set to include XTF_NOSEL, which would have the effect of simply returning the current selection information.)

The recommended sequence for XTR_KBDSTR is chr(7)+chr(250)+###. (where ### is the desired EXITCODE number to be returned from the INFLD call which receives the sequence.) For example, to return EXITCODE 175 to INFLD when the user clicks on the pick list (while an INFLD operation is active), set XTR_KBDSTR=chr(7)+chr(250)+"175." (Note the trailing period.)


Appending

When adding items to an existing tree control, care should be taken about the array index numbers. For example, if you initially load a tree control with a ten item array, then append another ten item array to it, the control will know that the second set of ten items should be internally numbered eleven to twenty, but it will be up to your program to realize that item fifteen is really the fifth item of the second set of ten loaded. One way to avoid this confusion is to maintain a single array which matches the contents of the tree control, even if you did not load them all at once. In the example just cited, rather than passing two separate arrays (or worse, overwriting the original array with the second set of items), it might be better to map an array large enough for all the items, and then just add to it as you add to the tree control. The trick here is to specify the appropriate starting array index, rather than (1). For example:

MAP1 ARRAY(50),S,100

FOR I = 1 TO 8

ARRAY(I) = <data>

NEXT I

! now create the control with the first 8 items...

XTR_OPCODE = 0 ! (create)

FLAGS = XTF_MODELESS + XTF_NOSEL

ADDCNT = 8

xcall XTREE, SROW, SCOL, ANSWER, ARRAY(1), ADDCNT, COLDEF, EXITCODE, &

EROW, ECOL, FLAGS, "", MMOCLR, XTRCTL

! now load up an additional 12 items, adding them first to array

FOR I = 9 TO 20

ARRAY(I) = <data>

NEXT I

! append these items to the existing tree control...

XTR_OPCODE = 2 ! (append)

ADDCNT = 12

! note that we pass ARRAY(9) rather than ARRAY(1) ...

xcall XTREE, SROW, SCOL, ANSWER, ARRAY(9), ADDCNT, COLDEF, EXITCODE, &

EROW, ECOL, FLAGS, "", MMOCLR, XTRCTL

ADDCNT = ADDCNT + ADDCNT

Now the 20 items in our local copy of ARRAY() match up with the contents of the tree control, so that when we receive a selected item number via the ANSWER parameter, we can reference the corresponding item in our local array directly, as ARRAY(ANSWER).

The initial selection(s) are determined (by the answer parameter) in the same way as when creating a new list, except that if you do not specify an initial selection, the default will be the first item appended. If you do specify one or more selections in the answer parameter, they re interpreted relative to the combined list after appending, not relative to the just the appended items. That is, setting answer=2 will select the second row in the table, not the second row appended.


Editable Tree Controls

Updated and reviewed November 2010

XTREE supports editable text columns, combo boxes, checkboxes, and radio buttons. To activate this feature, set the XTF_EDITABLE option in the Flags parameter, and define one or more columns using the E (editable text) or T (editable checkbox) or R (editable radio button) or l (list selection) options in the coldef parameter. (You must use the Advanced Coldef syntax.) You must also map the Answer in such a way to allow the updated text and/or checkboxes to be returned there.) You will probably also want to change the selection style in the XTR'SELECTAREA field of the Xtrctl parameter so that the selection indicator does not highlight the entire row (which makes it distracting to see the editable fields.)

XTREE is a "tree" rather than a "grid" control, so its primary function is to display data and allow the user to select items. It doesn't support individual cell formats or functions, like a spreadsheet would. But its editing capabilities should suffice for a wide variety of scenarios which combine the need to display a lot of data in rows and columns, with lightweight editing capabilities.

As a simple example, consider an application where you have a list of invitees to an event, and you want to check off those that show up. You might have several display columns for each person, with a single column of checkboxes to indicate if they have arrived. In this case, there would be no need for validating the data after each check either, although you might want to allow the operator to double-click on the person's name to print a badge. Another example would be a simple inventory sheet that lists all of the parts and has an editable text column allowing you to enter the amount on the shelf. A more sophisticated example might be a student grade book containing one row per student, and one column per assignment, where the teacher could enter data into any cell.

When the XTF_EDITABLE flag is set, as long as the first column is not editable, you will be able to move the selection indicator up and down with the arrow keys, and select an item by hitting Enter.The left and right arrow keys, however, will move the "focus" to the first editable cell in the appropriate direction, after which the arrows and Tab / Shift+Tab keys will move from editable cell to editable cell.

If the first column is not editable, you can exit from editing mode (back to row selection mode) by clicking on the first column. Unless the XTF_ENTESC flag is set, you can also do this by hitting Escape. (Otherwise Escape exits the tree.) To exit from editing mode and out of the tree entirely (back to the calling program), you can double click on an item (not in an editable column), or use a function key (assuming the XTF_FKEY flag is set in the flags parameter) or click on an external button or control (even another XTREE) programmed to generate an exitcode (see MBF_KBD and XTR'KBDSTR), or any other event that triggers an exitcode. If the XTF_ENTESC flag is set you can also hit Escape (from any cell) or hit Enter from the last editable cell in the tree.

If you need to perform validation of the data on a cell by cell basis (without waiting for the user to exit from XTREE), you can add the "x" or "X" flag to any editable column. The lower case "x" forces XTREE to exit immediately (with exitcode -48) as each editable text cell loses the focus. The application can examine the XTR'XROW, XTR'XCOL, XTR'TARGETROW, XTR'TARGETCOL, and XTR'XNAVIGATE fields (see XTR'TARGET... and XTR'XVALIDATE) for information on which cell(s) need to be validated. The upper case version, "X", is the same except that it only exits if the data in the cell changed. Checkboxes and radio buttons treat both "x" and "X" equivalently, in both cases exiting immediately when the item is clicked (i.e. which changes its value). Read-only editable cells ("u") also treat "x" and "X" the same, as they exit immediately before getting the focus, rather than after losing the focus.

See the Answer parameter for details on how it must be structured in order for editable cells to function properly.

Note that you can cause individual rows (cells) within an editable text column to be ignored (skipped over) by setting the first data character of the corresponding entry in the Answer array to "|". Also see First Position Reserved (cformat "P") which may simplify use of the "|" flag.

The editable option is only supported with array mode (not file mode).

See Also

• The XTRA5 sample program for a good example of editing and validation.

• The XTRA6 sample program for radio buttons and multi-line cell editing.

• The XTRA9 sample program for changing colors of individual cells based on editable contents.

• EL –CFG for a good example of editing only certain cells within an editable column.

Subtopics

Re-entry After Cell Validation

Editable Image Cells


Re-entry After Cell Validation

If you use the X or x column codes to force XTREE to exit to the application for the purposes of cell validation, then you probably want to be able to re-enter the XTREE with a minimum of overhead and visual distraction. Here are few tips to facilitate this:

• The XTR'TARGETROW and XTR'TARGETCOL parameters (see XTR'TARGET...) determine which cell will have the focus on re-entry. But if the specified cell is not editable, then XTREE will revert to selection mode (i.e. the focus will be on an item or row, with the idea of being able to select it, rather than on a cell for the purposes of editing it.) The user can typically proceed from selection mode into editing mode by clicking on the desired cell or by using navigation keys.

• In most cases, the preferred opcode (XTR'OPCODE) is XTROP_RESELECT. The eliminates the re-loading of the data source array into the tree. All editable cells, however, will be updated. So it is possible to update any cells, not just the one that was just edited or that will get the focus.

• To further reduce visual thrashing, set the XTF_NOREDRAW bit in the Flags parameter. This doesn't stop the editable cells from being updated, but does skip all of the positioning and sizing optimization logic that determine how the tree initially appears (particularly the column widths).

• If data outside of the set of editable cells needs to change (rows added, etc.), then you'll need to revert to opcode XTROP_REPLACE. In this case, the XTF_NOREDRAW flag has a slightly different effect: it doesn't stifle any display optimization logic, but it does eliminate the otherwise automatic deletion of the existing data before the new data is added. The main advantage of this is a slight reduction in the visual "flash."


Editable Image Cells

Image cells (editable or not) may contain two text strings: an image file specification and some text to display along with the image in the cell (separated from the file spec by a comma). When updating an editable image cell during re-entry, you can use any of the following formats in the answer array field corresponding to the cell:

Answer | Operation
<blank> | clear text in cell, leave image alone
imgspec | replace existing image, clear text
imgspec, | same as above
text | leave image alone, replace text
,text | delete existing image from cell, replace text
imgspec,text | replace image, replace text

Note that XTREE distinguishes between the "imgspec" and "text" cases by whether the field contains a valid image extension.

On return from XTREE, the answer array cells will contain just the text that displays in the cell along with the image, unless you edit the cell, in which case it will contain exactly what was entered.


Multiple Tree Controls

You may have multiple XTREE controls defined and displayed at once. To do so, you must specify a unique control number (0=first, 1=second, etc.) in the XTR_CTLNO parameter, and use the flags XTF_MODELESS option (so that you can exit the first list without destroying it). This kind of arrangement can be useful for allowing the user to move items between two categories, or to present in one list box a set of possible items, and use the other to store the ones that have been chosen.

See XTR'CTLNO for information on auto-assigning a control number.

See also Scenarios Involving Multiple Trees.


Controls in Container Windows

You may place an XTREE control within a container window such as a Modal Dialog Box or Tab Control. In the case of dialogs, this is automatic. (That is, if a dialog box is active when the XTREE control is created, it will automatically be a child of that dialog, and it is not necessary to set the XTR_PARENTID parameter.) In the case of a Tab control, you must specify the control ID of the Tab control in the XTR_PARENTID parameter. In either case, the coordinates will be interpreted as being relative to the client area of the container window.

If you are going to open an XTREE in the middle of a screen, such that it will overlap other controls, it is highly recommended that you put it inside a dialog. Otherwise, to prevent the controls already present from "bleeding through" the XTREE, A-Shell will automatically save and delete any controls which overlap the XTREE's rectangle, and the restore them on exit. But that effect may seem a bit awkward, whereas a pop-up dialog is not only cleaner looking, but allows the user to move it around to see what is underneath. See the sample programs XTRA2 and XTRA5 for examples of XTREE controls within dialogs.


Destroying Pick Lists

This happens automatically in the normal modal case (i.e. when XTF_MODELESS not set). Otherwise, you must explicitly destroy the tree control using XTR_OPCODE 3, or, since it is just another control object (like buttons, static text, etc.) it may be destroyed using Tab (-1,0). If the XTREE control is within another control (such as a dialog or Tab), then you may also destroy it by using AUI_CONTROL or Tab (-10,20) with opcode 4 and specifying the control ID of the parent.


Typical Cell Editing Scenarios

• If cell (3,5) is being edited, and the user clicks on cell (6,7), and the (3,5) cell requires validation (see coldef codes x and X), then XTREE will exit with XTR'XROW=3, XTR'XCOL=5, XTR'TARGETROW=6 and XTR'TARGETCOL=7. XTR'XVALIDATE will be set to 1 to indicate that the cell identified by XTR'XROW / XTR'XCOL should be validated. The exitcode will be -48 (cell validation). If the application calls XTREE again to continue editing, the operation will start at the cell identified by XTR'TARGETROW / XTR'TARGETCOL. If it doesn't like the contents of the cell that was just edited (3,5), it can force re-entry at that location by setting XTR'TARGETROW and XTR'TARGETCOL to XTR'XROW & XTR'XCOL (or it can just zero out XTR'TARGETROW and XTR'TARGETCOL to accomplish the same thing).

• In the example just described, if, while editing cell (3,5) the user hits a navigation key (such as Tab or Down+Arrow) to move the focus to another cell, then the outputs will be the same as just described, except that XTR'TARGETROW / XTR'TARGETCOL will be set to indicate the next cell to get the focus (based on the navigation key used and the layout of the tree.) XTR'NAVCOD will indicate the navigation key used.

• Another variation of the example just given would be if, while editing cell (3,5) the user right-clicked on a cell that was not editable but which had a context-menu defined. In that case, the context menu would first be displayed, and XTREE would wait for a menu option to be selected. If the user canceled the menu, the editing of cell (3,5) would resume. Otherwise, XTREE would exit with the exitcode corresponding to the chosen menu option, but the XTR'XROW, XTR'XCOL, XTR'TARGETROW, XTR'TARGETCOL and XTR'XVALIDATE fields would be set just as in the first example. If the application tried to re-enter with changing the XTR'TARGETROW and XTR'TARGETCOL, if would enter in selection mode with the focus on that row, rather than in cell editing mode (since the cell was not editable).

• A similar case occurs when the user terminated a cell editing operation by clicking on some control outside of XTREE. In this case, the XTR'XROW / XTR'XCOL will still point to the cell that was being edited, and XTR'XVALIDATE will be set to 1 to indicate whether it needs validation. But XTR'TARGETROW / XTR'TARGETCOL will be 0, since the target location is outside of the context of XTREE. If the application re-enters, since XTR'TARGETROW / XTR'TARGETCOL are 0, XTREE will use the incoming XTR'XROW / XTR'XCOL to set the starting focus.

• A variation of the cased just describe is where the user is editing a cell and clicks on a cell in another XTREE. In this case, XTR'XROW, XTR'XCOL and XTR'XVALIDATE will be set according to the cell that was being edited, just as in the previous case. But XTR'TARGETROW and XTR'TARGETCOL will point to the cell that was clicked on in the other XTREE. The application will be able to identify this case by the fact that the exitcode value will correspond to the other XTREE. It would presumably then want to transfer the XTR'TARGETROW / XTR'TARGETCOL values to another copy of the xtrctl structure (corresponding to the other XTREE) and then re-enter that XTREE.

• When the editable cells in question are not text cells but checkboxes, it works slightly differently. Since checkboxes change value immediately when clicked, if they have the X or x code for validation, they will exit immediately at that time (rather than when the focus is moved to another cell). So if we go back to the first example above but imagine that the two cells in question, (3,5) and (6,7) are checkboxes, then if the user clicked on the (6,7) checkbox while the (3,5) checkbox had the focus, the return codes would all be the same as in that example, except that XTR'XVALIDATE would be set to 2 to indicate that it is the XTR'TARGETROW / XTR'TARGETCOL cell that needs validating.

• If the focus is on an editable checkbox, and the user then clicks it, or uses the space bar to toggle the checkbox, if the column is coded for validation, XTREE will exit with both XTR'XROW / XTR'XCOL and XTR'TARGETROW / XTR'TARGETCOL pointing to that same cell. In this case it doesn't really matter whether XTR'XVALIDATE is returned as 1 or 2, since in either case, it is the same cell that needs validation.

Note that XTR'XVALIDATE=1 means that the xtr'xrow/XTR'XCOL cell (i.e. the one we just left) needs to be validated; while 2 means that the XTR'TARGETROW/XTR'TARGETCOL cell needs to be validated (the one we just clicked or are navigating to). In the case of checkboxes, they exit for validation only when the checkbox value changes, which occurs immediately when you click, rather than when you move the cell focus (as would be the case with a normal editable cell). So if you are focused on a checkbox at 5,7 and you click another checkbox at 3,9 then XTR'XROW/XTR'XCOL will be returned as 5,7, while XTR'TARGETROW/XTR'TARGETCOL will be returned as 3,9. But the checkbox that has changed is the one at 3,9 (the one clicked), so it is the one that should be validated.


Saving User Adjustments

Updated August 2011

XTREE provides two built-in methods for preserving display adjustments (column sizing, ordering, sorting, etc.) between calls. The first involves the use of the XTR'COLORDER array to return the size and position of the columns to the application so that it may save it and recall it later. The second method is somewhat more powerful and requires no application involvement other than the following changes to the code calling each XTREE:

• Use the new advanced coldef directive TreeID to give the tree a unique identity, so that any user-directed modifications can be associated with just that one tree. See notes below.

• Assign the XTR'USRCFG field (in xtrctl) to one of the following, based on which user-configuration options should be allowed to override the application-supplied values:

Symbol* | Value | Description | Other Parameters Over-ridden
XTUCFG_COLWID | &h0001 | Column widths | Dspwid (coldef)
XTUCFG_COLSRT | &h0002 | Sort order | XTR'SORTORDER, XTR'COLUMNSORT
XTUCFG_COLORD | &h0004 | Column order | XTR'USECOLORDER, XTR'COLORDER
XTUCFG_FONT | &h0008 | Text scale adjustment | See Mouse and Keyboard
XTUCFG_COLACT | &h0010 | Active column | XTR'COLUMNACTIVE
XTUCFG_SRTORD | &h0012 | Sort & active col | XTR'COLUMNACTIVE, XTR'SORTORDER, XTR'COLUMNSORT
XTUCFG_ALL | &h0100 | All |

*from XTREE.DEF

The TreeID may consist of an alphanumeric name, with an optional :# suffix where # is the version of the tree (an integer value). The idea of the version is so that if you modify the tree layout during an application update, XTREE will know not to apply previously saved configuration details to the new tree layout.

The TreeID (maximum 32 chars) may also contain "%p" which will be replaced at runtime by the name of the current program. The feature is mainly useful for XTREEs that are implemented within SBX routines that might be called by multiple programs, where you want to allow the user to maintain a separate configuration in each case. So for example, you might use

TreeID=SelCus-%p:1

For ATE, see History notes below.

User configuration adjustments are saved in the Registry automatically, provided that TreeID is defined. (If XTR'USRCFG is zero, the settings will be saved on exit, but not restored on entrance, which is one way to force the configuration back to application-specified settings.)

Another way to deal with the possibility that the user accidentally makes a disastrous change to the configuration (like resizing a column to zero width, thus making it disappear entirely), is to define a Popup Menu and add to it the new special command $RESETCFG. For example:

COLDEF=COLDEF+"0~0~x~H~PopupMenu=Misc,VK_xF666;Reset Columns,$RESETCFG~~"

Selecting this option from the menu will cause the tree configuration to be immediately reset back to the way the application had originally intended.

The configuration information is saved in the Registry as:

HKCU\Software\MicroSabio\A-Shell\XTREE\treeid

where treeid is the value specified in the TreeID= coldef clause, but with the version stripped. (The version is saved as a sub-field rather than part of the key, to reduce the proliferation of Registry entries.)

History

2016 October, A-Shell 6.3.1530: Number of columns whose reordering can be maintained between sessions expanded from 31 to the maximum number of columns supported by XTREE (currently 100).

2011 August, A-Shell 5.1.1229: Prior to ATE 5.1.1229, the "%p" code (for program name) did not work at all, and in fact, rendered the TreeID inoperable. As of ATE 5.1.1229, it does work, although subject to the server version. For server versions prior to 5.1.1217, "%p" is translated to "ATE". As of edit 1217, A-Shell on the server began transmitting the program name to ATE, allowing "%p" to be translated to the proper application program name.

2008 October, A-Shell 5.1.1126: Ability for users to save/restore their own adjustments added to A-Shell.

2008 October, A-Shell 5.1.1127: Column configuration now saved even when tree is exited with Escape (since this is a common exit not necessarily considered as "cancel"). The only way to exit without saving is now Ctrl+C.


Scenarios Involving Multiple Trees

Added November 2010

Programs which present multiple XTREE controls on the screen at once require additional consideration in order to deal with the complexities of the user clicking on one XTREE control while another one has the focus. This section will attempt to cover the basic issues involved and look at some specific examples. Note that some of the principles here (particularly the subject of the next section) apply more generally to clicking between any control and XTREE (and not necessarily between multiple XTREEs).

Subtopics

Click on Inactive Tree

Multiple Exitcodes


Click on Inactive Tree

Added November 2010

When one control has the focus (whether an XTREE, INFLD, or some other), and the user clicks on another XTREE, the event is signaled by processing the XTR'KBDSTR parameter associated with the clicked-on tree. This will cause the current control-handling routing (XTREE, INFLD, AUI_EVENTWAIT, etc.) to exit with the corresponding exitcode. The application would then typically invoke an XCALL XTREE operation for the clicked-on tree (as determined by the exitcode) to allow the user to work with that tree.

Obviously in order to be able to identify the clicked-on tree, each tree should have a unique exitcode (i.e. a unique XTR'KBDSTR). While this generally applies to any control for which a click event should result in the application giving the control focus, clicking on an inactive XTREE has additional complications in that it may matter exactly where on the tree the click occurred (i.e. the row and column). For example, if the user clicks on an editable cell at location (3,5), there would be a reasonable expectation that the application would respond by putting the focus on the tree and specifically on that cell, putting it in editing mode. But the click event returns the same exitcode regardless of where the tree was clicked. How can the application identify the specific cell in order to respond as the user expects?

There are two solutions to this problem. The first is that the XTR'TARGETROW/COL fields will be set according to the clicked-on tree (i.e. the previously inactive one), while the XTR'XROW/XCOL fields will indicate the last context of the tree that was active. (This solution only applies when the control which initially had the focus was XTREE.)

A more general solution is that each XTREE control remembers any click events that occur while the tree is not active. The remembered click event can then be automatically processed when the application calls that tree to activate it. In the example just given, the application responds to the click on a particular tree by calling XTREE to activate it (typically in XTROP_RESELECT mode). As soon as it becomes active, that control can then respond to the saved click event (in this case putting the focus on cell (3,5) and going into editing mode. This scheme is particularly useful for events that aren't completely described by the XTR'TARGETROW/COL information (such as a SelChgExit triggered by the fact that the click on the inactive tree moved the selection bar of that tree).

Another example of where the saved/recalled click mechanism comes in handy would be in the case of a right-click on an inactive tree which has a context menu defined (see PopupMenu). Initially, rather than displaying the context menu, the click information is saved and instead the exitcode associated with the clicked-on tree is generated, causing the current control-handling routine to exit. When the application calls XTREE to process the clicked-on tree, XTREE will start by processing the deferred right-click information, causing the context menu to appear. (Assuming no undue delays in the application, this behind-the-scenes processing will be invisible to the user, who will simply see the context menu appear in response to the right-click.)

Both of these mechanisms are automatic. But there may be cases where the application decides it does not want to proceed with the user's intent, i.e. does not want the deferred click action to take place. For example, if the click on the inactive XTREE control occurs while the user was editing a text field (in INFLD, or perhaps in another XTREE), the typical plan would be for the current XCALL routine to return with the clicked-on XTREE's exitcode, so the application could call XTREE to process that event. But maybe the current value of the field violates some application rule, in which case the application may decide to just ignore the XTREE click and instead display a data-entry error message and return to editing the field. At some later point, the application may decide to activate the previously-clicked XTREE, but by then you would no longer want to process the deferred click event. XTREE uses a timer to attempt to determine whether the deferred click event is still relevant, but as of 5.1.1195, a new flag was added, XTF2_CLRDEFER, to force it to ignore (clear) deferred click event information (eliminating any question about the whether the timer expired).


Multiple Exitcodes

Added November 2010

The general A-Shell scheme for handling events relies on a single exitcode for each event. Usually this is sufficient, but with XTREE, a single click might logically be associated with more than one exitcode. (This complication is somewhat independent of the multi-tree scenario, but it is particularly acute here.) For example, consider a dialog with two XTREEs. The first tree has the focus, and the user is editing (changing) a cell (which is coded for validation). Then the user clicks on an item in the second tree. What is the appropriate exitcode? The one indicating the click on the inactive tree, or the one indicating validation required (-48) for the cell just exited? If the former, how does the app know to validate the edited cell? And if the latter, how does it know to activate the clicked-on tree?

To help simplify these kinds of issues, XTREE uses a few simple rules for determining which exitcode to return. First, whenever an XTREE session is terminated by a click on some other control (whether another XTREE or something else), the other control's click exitcode will take precedence. For example, if you click on a button or another XTREE whose click string is "VK_xF101", XTREE will exit with exitcode -101. In any other case, if multiple exitcodes are applicable (for example, cell validation and a custom exitcode from a PopupMenu), the cell validation exitcode (-48), if applicable, will take precedence. Finally, to receive information about multiple exitcodes, you may specify the xinfo parameter, which will be returned with a list of exitcodes. For example, in the case of a PopupMenu exitcode that interrupts a cell editing operation, the main exitcode parameter will contain -48, but xinfo may contain 0,-48,-200. The leading "0," indicates the nature of the information in the xinfo string, in this case, a list of exitcodes. And the -48,-200 indicates that both -48 (cell validation) and -200 (from the hypothetical PopupMenu choice) are applicable. (The first exitcode in the list may duplicate the value in the main exitcode parameter.)

A sophisticated application could then respond to both, i.e. validating the cell editing operation, and responding to the menu event associated with -200.


XTREE Sample Programs

Several sample programs (with source) are available to help you understand and use XTREE controls. The best place to get these and other sample programs is from EXLIB.

Program | Description
TABDLG | Sample Tab control in a dialog, with an XTREE on one of the Tab pages.
XTRARY | Simple three-column list, array mode, using the Simple Multi-Column Coldef Syntax.
XTRA2 | A more sophisticated array-based example, supporting multi-level and multi-select options, and using the Advanced Coldef syntax to define columns with different formats, colors (row,column,cell), popup menus, etc. Also supports option to display the XTREE inside of a dialog frame.
XTRA2A | Variation of XTRA2 illustrating XTR'EXPANDALL options with a 4 level hierarchy, also merge-into and merge-out of options, row fonts.
XTRA3 | An even fancier example demonstrating modeless operation, with options for multi-level and multi-selection. The program also illustrates INFLD checkboxes, buttons, TPRINT, some other GUI features, including tool tips and dialog boxes.
XTRA4 | Simple example of using two XTREE controls at the same time.
XTRA5 | Demonstrates checkboxes and editable text and combo boxes.
XTRA5M | Variation of XTRA5 using multi-selection.
XTRA6 | Illustrates radio buttons, multi-line editable cells, colors.
XTRA7 | Images and multi-line editable text. (A simple application for associating comments with images.)
XTRFIL | File-based example. You supply the file, including the column definitions in the first row. Demonstrates both single and multiple selection options, and also the XTF_FILANS flag.


XTREE Miscellaneous Notes

XTREE vs. PCKLST, Text vs. GUI

XTREE is an upward-compatible variation of the older routine PCKLST. XTREE and PCKLST are actually the same subroutine, so it does not really matter what name you use. We split it into two different names simply to make it easier to document and understand, since the uses of XTREE may diverge considerably from those of PCKLST, and also to avoid the potential confusion of people trying to use XTREE features that are not available in a text environment. Our recommendation is for you to use PCKLST if you need text mode compatibility and are (therefore) going to stick with the PCKLST features and semantics (as documented under PCKLST). Otherwise, if you are committed to the GUI environment and want to take advantage of the maximum feature set, use XTREE.

Depending on how you call it and the operating environment, the subroutine chooses one of two internal implementations. For text environments, it uses the INMEMO menu mode to display the list and allow you to choose an item. (This will only be successful though if you limit yourself to the PCKLST feature set and argument semantics.) For GUI environments, it uses a third-party tree control, which is licensed for A-Shell distribution. It resides in an external module, SftTree_IX86_A_##.DLL, which must be in the same directory where ashw32.exe resides. Samples of XTREE usage in A-Shell are shown below.

Note: The changes listed below are the ones that have NOT integrated into the main body of the documentation. The documenter-in-chief doesn't know where to put them, but didn't want to not include them.

1203 – 02 February 2011

XTREE refinement: Adjust type-ahead logic introduced in 5.1.1197. The new rule is: On calling XTREE, if there is a pending event from clicking on the tree while it was inactive, then any unprocessed keyboard characters are stripped and ignored. In addition, if the XTF2_CLRDEFER flag is set and there is a virtual exitcode sequence pending, it is also stripped. Previously, the virtual exitcode sequence stripping was not dependent on the XTF2_CLRDEFER flag, which made it impossible to use XTREE as a kind of Eventwait handler for click events that had already happened (but which hadn't been detected by the application yet.)

970.0.3 - 31 Oct 06

The XTREE backslash \ character now marks the start of hidden text within a column in array mode, just as it does in file mode. Note that to treat backslash as a normal character, you need to add the \ code to a column definition (any column will do). (WARNING: This may break existing XTREEs that contain backslashes in the array data since previously the \ column code was not necessary for arrays; talk to Herman if you don't like this, or just add \ to your column definitions.)


Residua

Here are a variety of individual topics that were noted in the A-Shell Developments Notes (ashdevnotes), but could not be readily placed in the regular A-Shell documentation. The Dev Notes style has been maintained to enable easy tracking back to the original notes.

Version | Date | Description
1224.0.1 | July 2011 | Enhance keyboard selection of items from within INFLD/XTREE Combo Box.
1211.0.12 | Apr 2011 | ISAM 7 Statements now support dynamic variables.


INFLD/XTREE Combo Box

Combo box enhancement (applies to INFLD and XTREE selection-only combos): Replace the standard Windows single-character keyboard matching algorithm with a multi-character version, thereby allowing direct keyboard selection of items from within combos which share one or more starting characters. Previously, the matching logic reset for each new character, making it impossible to select by anything other than the first character of the item. Now the matching logic resets after a delay of 1 second, or after a failed match or a special key such as Arrows.


ISAM 7 Statements

ISAM 7 statements (get next key and return it) now support dynamic variables. They do not, however, support auto-extension of arrays. So if you want to use an auto-extend array variable, you must first initialize each element; for example,

DIMX IKEY(1),S,0,AUTO_EXTEND

...

! load ISAM keys into an auto-extending array of dynamic elements

DO WHILE ERF(CH)=0

I = I + 1

IKEY(I) = "" ! must initialize element to get auto-extension!

ISAM #CH, 7, IKEY(I)

LOOP


Boolean Arguments in INI Files

INI file options that take a Boolean argument are somewhat internationally minded. The table below shows first-letter responses and A-Shell interpretation as true or false.

True | False
T (True) | F (False,Falso)
Y (Yes) | N (No,Non)
1 | 0
ON | OFF
Sí |
Si (Sim) |
OU (Oui) |
Al (Allineare) |
V (Verdad,vrai,verdadeiro) |

Any other starting letter will be checked against the current LDF (language definition file) to see if it matches the single-character yes or no definitions.


SOSLIB and EXLIB

SOSLIB

The A-Shell Shared Open Source Library ("SOSLIB") is a collection of common definitions and useful routines. It includes the A-Shell core collection of map, structure, and symbol definitions (ASHINC:, [907,16]), common utility functions (SOSFUNC:, [907,10]), and many useful SBX modules. The library is maintained in an online repository where you can obtain details and downloads. All A-Shell developers are encouraged to visit the repository frequently to browse available routines, obtain the latest updates, and contribute to A-Shell's improvement via bug reports, suggestions, etc. In 2015, the examples from SOSLIB were segregated into their own library, the EXLIB.

EXLIB

The A-Shell Example Library ("EXLIB") is a collection of mostly small standalone example programs designed to illustrate or test particular A-Shell features. They are organized into PPNs in the [908,*] range, with each PPN focusing on a particular area. The library is maintained in an online repository where you can access and view individual files or download the entire set. Prior to 2015, the examples were included not in their own EXLIB library but in the more general SOSLIB.


ASHINC Include Files

The ASHINC: ersatz directory (normally DSK0:[907,16]) contains the ++include files supplied with A-Shell. Although these files are not mandatory for programming, they help minimize the confusion and potential for error inherent in the complicated data structures and thousands of opcodes, options and flags which are typically employed in XCALL and function parameters. By referencing the relevant ++include files in your programs, you gain instant access to standardized MAPs, structures, and symbols that make your programs easier to read, write, and share with others, as well as maximizing the utility of our documentation, which is heavily indexed and/or searchable on these same symbols and map/structure names.

The most recent versions of the ASHINC: files can—and regularly should—be obtained from the 907016 folder of the SOSLIB.

The ASHINC: directory contains the following kinds of files, identified by their extension:

Extension | Description
DEF | Symbol definitions (e.g. define MBF_STATIC = &h00040000)
MAP | MAP statements
SDF | Structure definitions
BSI | Actual code (possibly including MAP statements, function/procedure definitions, etc.)

Other than a small version signature (about 40 bytes), DEF and SDF files do not increase the size of the resulting RUN programs. They merely expand the "vocabulary" of the compiler. They do, however, require the COMPIL /X:2 switch. When there is both an SDF and MAP file, the SDF is generally preferable, as it allows multiple copies of the structures to be declared, using your own prefixes. The MAP files represent the older approach used before defined structures were introduced.

Here is an overview of the most commonly used files. New ones are added periodically, typically with names matching the XCALL or subsystem to which they refer.

Filename | Description
ashell.bsi | Code commonly used in LIT programs (e.g. command line processing)
ashell.def | A core set of symbols used in nearly every A-Shell program, especially those containing MIAMEX calls
ashell.sdf | Structure definitions associated with common MIAMEX calls
csidl.def | CSIDL_xxxx symbol definitions (used by MX_BROWSEFOLDER and MX_GETSHELLPATH)
evtmsg.def | Symbols used with XCALL EVTMSG
gtlang.map | Mapped structure used by XCALL GTLANG (get language definition)
hook.def | Symbols used by the file hook mechanism (see MX_FILEHOOK)
http.def | Symbols used by XCALL HTTP
isam.def | Symbols related to ISAM
jobtbl.def | Symbols related to fields in the job table
jobtbl.map | Mapped structure representing JOBTBL.SYS records - see MX_READJCB
msboxx.def | Symbols related to XCALL MSBOXX
regex.def | Symbols related to regular expressions
sql.def | Symbols related to XCALL SQL
trmchr.map | Mapped structure used by XCALL TRMCHR (terminal characteristics)
xcall.bsi | Startup code useful in writing custom SBX routines
xtext.def | Symbols related to XCALL XTEXT
xtext.sdf | Structure definitions for XCALL XTEXT parameters
xtree.def | Symbols related to XCALL XTREE
xtree.map | Mapped structures compatible with XCALL XTREE
xtree.sdf | Structure definitions for XCALL XTREE parameters


ZTERM Escape Sequences

A-Shell emulates some of the more common ZTERM ESC sequences, as described below.

Note that most of the features provided by the ZTERM escape sequences are also available in A-Shell/Windows via a Tab(-10,x) sequence or a subroutine. The advantage of the Tab(-10,x) or XCALL method is that the same code will work under A-Shell/Windows and A-Shell/UNIX with ATE on the client. But the advantage of the ZTERM ESC sequences is that they would work on any server platform (i.e. one that you telnet to) provided the client is ZTERM or ATE. But in the latter case, you should test to make sure you aren't running locally on A-Shell/windows, where the ESC sequences would not make much sense.

ZTERM Esc Seq | Tab(-10) Command | XCALL Subroutine | Comment
27,27,3 |  |  | Enable Serial Passthrough
27,27,4 |  |  | Disable Serial Passthrough
27,12 | 24 | MX_SHELLEX | Execute or print windows file ("shell execute")
27,22 | 23 | HOSTEX | Execute Windows command ("win exec")
27,15 |  | MX_GETIP | Get client IP address
27,1,127 | 22 |  | FTP file transfer
27,13 | 1, 2 | MX_TITLE | Label window
27, 25 | 27 | MX_SHOW WINDOW | Set window state
27,16 | 28 |  | Flash window
27,29 | 29 |  | Set ftp login name/password

Many of the ZTERM ESC sequences use a CHR(0) (aka null byte) as a delimiter. However, if for some reason you have difficulty sending null bytes, you can use CHR(128) as an equivalent alternative.

Examples

Execute or print windows file ("shell execute")

?CHR(27) CHR(12);OP$;FSPEC$;CHR(0);

(OP$ is "O" to "open" or "P" to "print)

INPUT A ! CR for ok, Control-C for error

Execute windows command (aka "win exec")

?CHR(27);CHR(22);CMD$;CHR(0);

INPUT A ! CR for ok, Control-C for error

Get client ip address

?CHR(27);CHR(15);

INPUT "",IP'ADDR$

ftp file transfer

?CHR(27);CHR(1);CHR(127);DIR$;HOSTDIR$;CHR(0); &

HOSTFILE$;CHR(0);PCFILE$;CHR(0);

INPUT A

ATE supports transferring entire directories, in addition to single files, by setting the HOSTFILE$ or filename portion of PCFILE$ to “*”.

Label window

?CHR(27);CHR(13);TITLE$;CHR(0);

! sets title for both normal and minimized window

Set window state

?CHR(27);CHR(25);CMD$ !(CMD$ is M, X, R, or N)

Flash window

?CHR(27);CHR(16);"1" ! start flashing

?CHR(27);CHR(16);"0" ! stop flashing

Set ftp login name/password

?CHR(27);CHR(29);NAME$;CHR(0);PW$;CHR(0);

Subtopics

Serial Passthrough

Extended Example


Serial Passthrough

As of build 946.6 of 26 Novenber 2005, A-Shell/ATE supports ZTERM-type serial passthrough.

Enable passthrough:

? chr(27); chr(27); chr(3); params$; chr(0);

Disable passthrough:

? chr(27); chr(27); chr(4);

params$ is of the form:

"<port#>,<baud>,<parity>,<databits>,<stopbits>"

For example:

"1,9600,E,7,2" (COM1, 9600 baud, even parity, 7 bits, 2 stopbits)

When enabled, input from the serial port is merged into the keyboard channel input. Output characters are not normally sent to the serial port. To enable that, send ^X (ASCII 24); send ^T (ASCII 20) to disable. Note that these are the standard AUX PORT ON/OFF commands for the AM6x emulation, but when they are sent while serial passthru is enabled, they have the effect of sending the output to the defined serial port rather than to the printer port.


Extended Example

The following example uses the login name/password stored in the ATE configuration for the ftp name/password. The function to temporarily set a new name/password has not yet been implemented.

GET ZTERM/ATE ID:

?CHR(27);"?";

xcall GET,BUFFER,0,2,RCVD,1000

IF RCVD<2 goto NOT'ATE'ZTERM

xcall TINKEY,A$ ! extra char?

?CHR(27);"?";

xcall GET,BUFFER,0,3,RCVD,1000

IF RCVD<2 goto NOT'ATE'ZTERM

xcall TINKEY,A$ ! extra char?

?CHR(27);"?";

xcall GET,BUFFER,0,2,RCVD,1000

IF RCVD<2 or BUFFER#"ZT" goto NOT'ATE'ZTERM

?CHR(27);"?";

xcall GET,BUFFER,0,14,RCVD,200

? "VERSION=";BUFFER

Most AMxxx and WYxxx terminals will respond to ESC ? with 2 bytes indicating the (row and col each offset by 32). However, to be more robust, you should allow for the possibility that the terminal will not respond at all to ESC ?, or that it will give you an extra byte (possibly a trailing CR or a leading ^Y for columns > 96). The above code uses GET.SBR with the timeout option to input up to 2 chars, aborting after 1000 ms. It then uses TINKEY to grab any extra character without waiting. This sequence is repeated 4 times. After the 3rd time, ATE will respond with "ZT" (like ZTERM does). After the 4th time, it will return you "AV" following by the version string. (This is where you can distinguish ATE from ZTERM.)


Row and Column Codes

These codes are used to encode numeric control information used by certain Tab functionsinto one or two ASCII bytes. Control values above 96 all use two bytes, with the first byte being Control-Y or ASCII byte number 25.

Row or Col | ASCII | Row or Col | ASCII | Row or Col | ASCII
1 | (space) | 45 | L | 89 | x
2 | ! | 46 | M | 90 | y
3 | " | 47 | N | 91 | z
4 | # | 48 | O | 92 | {
5 | $ | 49 | P | 93 | |
6 | % | 50 | Q | 94 | }
7 | & | 51 | R | 95 | ~
8 | ' | 52 | S | 96 | (del)
9 | ( | 53 | T | 97 | ^Y (space)
10 | ) | 54 | U | 98 | ^Y !
11 | * | 55 | V | 99 | ^Y "
12 | + | 56 | W | 100 | ^Y #
13 | , | 57 | X | 101 | ^Y $
14 | - | 58 | Y | 102 | ^Y %
15 | . | 59 | Z | 103 | ^Y &
16 | / | 60 | [ | 104 | ^Y '
17 | 0 | 61 | \ | 105 | ^Y (
18 | 1 | 62 | ] | 106 | ^Y )
19 | 2 | 63 | ^ | 107 | ^Y *
20 | 3 | 64 | _ | 108 | ^Y +
21 | 4 | 65 | ` | 109 | ^Y ,
22 | 5 | 66 | a | 110 | ^Y -
23 | 6 | 67 | b | 111 | ^Y .
24 | 7 | 68 | c | 112 | ^Y /
25 | 8 | 69 | d | 113 | ^Y 0
26 | 9 | 70 | e | 114 | ^Y 1
27 | : | 71 | f | 115 | ^Y 2
28 | ; | 72 | g | 116 | ^Y 3
29 | < | 73 | h | 117 | ^Y 4
30 | = | 74 | i | 118 | ^Y 5
31 | > | 75 | j | 119 | ^Y 6
32 | ? | 76 | k | 120 | ^Y 7
33 | @ | 77 | l | 121 | ^Y 8
34 | A | 78 | m | 122 | ^Y 9
35 | B | 79 | n | 123 | ^Y :
36 | C | 80 | o | 124 | ^Y ;
37 | D | 81 | p | 125 | ^Y <
38 | E | 82 | q | 126 | ^Y =
39 | F | 83 | r | 127 | ^Y >
40 | G | 84 | s | 128 | ^Y ?
41 | H | 85 | t | 129 | ^Y @
42 | I | 86 | u | 130 | ^Y A
43 | J | 87 | v | 131 | ^Y B
44 | K | 88 | w | 132 | ^Y C

Note: the text for the following section comes from "variables1.doc." Go there to change it.


Virtual Key Symbolic Names

The Virtual Key Symbolic Names provide a convenient notation for specifying certain control characters to be transmitted into the input buffer in response to a click event on the control; See the CONTROL class cmd parameter, the XTREE xtr'kbdstr, the XTEXT txc'kbdstr, etc.) The names all start with VK_ followed by the name of the key as it relates to the keyboard. The names in the table below can also be altered to indicate the SHIFT or CONTROL version by inserting a “^” and/or lower case “s” after the underscore. For example, “VK_^UP refers to the keystroke Control-Up Arrow, “VK_sDOWN” refers to Shift-Down Arrow, and “VK_^sF2” refers to Control-Shift-F2.

Note that the Virtual Key Symbolic Names can optionally be enclosed in percentage signs ("%"), e.g. "%VK_RIGHT%", which act only as syntax delimiters. Such delimiters would be unnecessary and superfluous in most cases, except in the case where multiple Virtual Key Symbolic Names are being combined. For example, to encode the sequence TAB followed by ENTER, you would need to use the format "%VK_TAB%%VK_ENTER%", since "VK_TABVK_ENTER" would not be properly recognized.

Virtual Key | Meaning
VK_BACK | Backspace
VK_DECIMAL | Decimal point on numeric keypad
VK_DELETE | Delete key
VK_DOWN | Down arrow
VK_DIV | Forward slash ( "/" ) on the numeric keypad
VK_END | End key
VK_ENTER | Enter key (same as VK_RETURN)
VK_ESCAPE | Escape key
VK_HOME | Home key
VK_INSERT | Insert key
VK_LEFT | Left arrow
VK_MINUS or VK_SUB | Minus key on the numeric keypad
VK_NEXT | Next Page or Page Down Key
VK_PLUS or VK_ADD | Plus key on the numeric keypad
VK_PRIOR | Prev Page or Page Up Key
VK_RETURN | Return key (same as VK_ENTER)
VK_RIGHT | Right arrow
VK_TAB | Tab key
VK_UP | Up arrow
VK_F1 thru VK_F12 | F1 thru F12 keys
VK_x{r,d}F### | Extended virtual function key codes.
^x | Control x where "x" is any character A-Z or [, /, ], ^, _).

Subtopics

VK_x{r,d}F###


VK_x{r,d}F###

The sequence "VK_x{r,d}F### allows you to generate a wide range of exitcode values in response to various click events for the associated control.
The optional "{r,d}" may be replaced with "", "r", "d", or "rd" (to enable special handling for right click and/or double click events), and "###" is replaced by a numeric string in the range of 1 to 999999 (defining the exitcode value). The actual byte sequence transmitted will be chr(7) + chr(250), followed by the string of digits (corresponding to the ###), and terminated with a period ("."). You can input and interpret such stings yourself using a character-level input routine (such as GET, ACCEPN or the GETKEY function), but many higher level A-Shell routines which wait on operator input events (e.g. INFLD, XTREE, XTEXT, EVENTWAIT, etc.) will do the translation for you automatically, returning the corresponding numeric exitcode value. The following table of examples will help clarify:

Code String

Click Event

Raw Byte Sequence

Exitcode

Notes

VK_xF123

Left Click

chr(7),chr(250),"123."

-123

Left click exitcodes are negative

Right Click

chr(7),chr(250),"123."

-123

Since no "r" in code string, right click same as left

VK_xrF42

Left Click

chr(7),chr(250),"42."

-42

Note: ### values < 100 not recommended since they may overlap other pre-defined exitcode values

Right Click

chr(7),chr(250),"-42."

42

"r" present; right click sequence contains "-" but exitcode is positive

Left DblClick

chr(7),chr(250),"42.",chr(7),
chr(250),"42."

-42,-42

"d" not present; double click is same as 2 regular clicks

VK_xrdF9999

Left Click

chr(7),chr(250),"9999."

-9999

Right Click

chr(7),chr(250),"-9999."

9999

Left DblClick

chr(7),chr(250),"9999.",
chr(7),chr(250),"9999000."

-9999, -9999000

First click generates normal sequence; second (double) click generates extended version with extra "000" (x1000). See comments.

Right DblClick

chr(7),chr(250),"-9999.",
chr(7),chr(250),"-9999000."

9999, 9999000

Same as left double click except with positive values.

Comments

Double-click handling is particularly tricky, since by the time the second click is recognized as being part of a double-click sequence, the first click has already been responded to (by generating the corresponding single-click sequence and exitcode). So in order for this to make sense, the application's response to a double-click has to be a logical extension or continuation of its response to a single click. For example, in a screen full of clickable appointment indicators, the single click event might result in more information being displayed about the appointment, while the double click might launch a dialog to allow editing of the appointment attributes. By contrast, if the single clicked caused the application to change its context, it might then no longer be in a position to properly respond to the double click exitcode.


TAB(-1,x) Functions

Following are lists of the basic Tab(-1,x) or TCRT functions supported by A-Shell. The codes are grouped into tables by type for quick reference. If you prefer a sequential listing of all codes, see the last entry in the table. See Tab() Functions for complete information on Print Tab. Note that most of these functions can be displayed from within VUE by using >HELP TCRT.

Range | Action
0 - 37 | Basic
38 - 53 | Line Draw Characters
64 - 78 | Special Characters
100 - 123 | Mode-style Monochrome Attributes
132 - 147 | AM70-Style Colors
 | All Others
0 - 254 | Numeric List (all)


Basic

Code | Action
0 | Clear screen and set normal intensity
1 | Cursor home (move to col 1, row 1)
2 | Cursor return (move to col 1 without linefeed)
3 / 4 | Cursor one row up / down
5 / 6 | Cursor one column left / right
7 / 8 | Keyboard lock / unlock
9 / 10 | Erase to end of line / screen
11 | Enter background display mode (reduced intensity)
12 | Enter foreground display mode (normal intensity)
13 / 14 | Protected fields enable / disable
15 / 16 | Line delete / insert
17 / 18 | Character delete / insert
19 / 20 | Not supported
21 / 22 | Blinking field start / end
23 / 24 | Alternate char set (line draw) enable / disable
25 / 26 | Not supported
27 | Set terminal attributes
28 / 29 | Cursor on / off
30 / 31 | Underscore start / end
32 / 33 | Reverse video start / end
34 / 35 | Reverse blink start / end
36 / 37 | Screen display off / on


Line Draw Characters

Note that line draw / alternate character mode must be enabled with TCRT code 23 prior to executing the following codes and, after using these codes, disabled with TCRT code 24.

Code | Action | Code | Action
38 / 39 | Top corner left / right | 40 / 41 | Bottom corner left / right
42 / 43 | Intersect top / right | 44 / 45 | Intersect left / bottom
46 / 47 | Line horizontal / vertical |  |
48 | Intersection | 51 | Cross-hatch block
49 / 50 | Block solid / slant | 52 / 53 | Double line horz / vertical


Special Characters

Code | Action | Code | Action
64 | Up arrow | 72 | Cent sign
65 | Down arrow | 73 | One-quarter
66 | Raised dot | 74 | One-half
67 | End of line marker | 75 | Degree
68 | Horizontal tab | 76 | Trademark
69 | Paragraph | 77 | Copyright
70 | Dagger | 78 | Registered
71 | Section |  |


Mode-style Monochrome Attributes

Note that the following apply to mode style emulations (AM65, AM75, PC*), and not field-style emulations (AM62x, WY5*).

Code | Action
100 / 101 | Underscored blinking field start / end
102 / 103 | Underscored reverse field start / end
104 / 105 | Underscored reverse blinking field start / end
106 / 107 | Underscored text without space start / end
108 / 109 | Reverse text without space start / end
110 / 111 | Reverse blinking text without space start /end
112 / 113 | Underscored blinking text without space start / end
114 / 115 | Underscored reverse text without space start / end
116 / 117 | Underscored reverse blinking text w/out space start / end
118 / 119 | Blink without space start / end


AM70-Style Colors

Text | Black | White | Blue | Magenta | Red | Yellow | Green | Cyan
Normal | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139
Reversed | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147


All Others

Code | Action
54 / 55 | Send message to function key line unshifted / shifted
63 | Send message to host message field
80 / 81 | Set terminal width to wide (132 col) / normal (80 col)
82 / 83 | Transparent print mode enter / exit
91 | Block fill with character
92 | Draw a box
93 / 94 | Scroll box one line up / down
120 / 121 | Set cursor to block blinking / not-blinking
122 / 123 | Set cursor to underline blinking / not-blinking
128 | Select top status line without address
129 | End status line (all kinds)
130 / 131 | Select status line without address unshifted / shifted
148 / 149 | Amigos-style area save / restore
158 / 159 | Mouse cursor reporting enable / disable
160 | Insight / AM75 set cursor shape. See Mouse Interaction.
162 | Insight / AM75 define hot spot. See Mouse Interaction.
192 | Insight id (UNIX only)
201 | Tracker save current screen attributes
202 / 203 | Tracker entire screen save / restore
253 | Display Euro symbol (Windows)
254 | Flush Screen Output Buffer


Mouse Cursor Reporting2

Tab(-1,158) must be followed by "C", and then a coded byte indicating the number of lead-in bytes to be sent with each mouse action, followed by the lead-in bytes. The coded byte should be chr(32+number of lead-in bytes). For example, the ESP package uses the following to enable mouse cursor reporting:

PRINT TAB(-1,158); "C"; CHR$(34); CHR$(27); CHR$(30)

This causes the two lead-in bytes, CHR$(27) and CHR$(30) to be sent at the start of each mouse event. These are followed by one byte indicating the row (coded as CHR$(31+row); see ZTERM Escape Sequences in the Appendix), followed by one or two more bytes indicating the column (from the same table), and finally a status code: CHR$(32) = sequence terminated; CHR$(33) = right button pressed; CHR$(34) = left button pressed; CHR$(35) = middle button pressed.

A single click will generate two sets of the above sequences, the first ending with the status code indicating the button (corresponding to the down click) and the second ending with the termination status code (corresponding to the up click). A double click will generate three sets of the above sequences, with the last two both ending with the termination status (as if it were one down click followed by two up clicks). Consequently, you would probably need to use a timed input routine, such as TINKEY.SBR or GETKEY() to determine whether the last part of the sequence was present.

Additional information may be found in the discussion on Mouse Interaction..


Flush Screen Output Buffer

Tab(-1,254) does nothing under AMOS, which doesn’t buffer screen output. But under both Windows and UNIX, A-Shell output is buffered to minimize system overhead. The buffer is flushed after nearly every Tab(-1,x) command and every carriage return, as well as before every input. Under Windows, the buffer is also flushed every half second or so. Usually, the effect is not noticeable. But in some circumstances, you may find it annoying. One case in particular is where a report program displays “life signs” -- either a dot for every few records processed, or a % complete indicator. If the PRINT statement updating this display has a semicolon on the end (to suppress an unwanted carriage return), then instead of seeing a steadily updating indicator, it may appear as if nothing is happening, and then all of a sudden, it goes from 0 to 100% in one jump. Adding a Tab(-1,254); on the end of these PRINT statements (e.g. PRINT “.”;Tab(-1,254);) will make the output display as expected.


Numeric List (all)

Code | Action
0 | Clear screen and set normal intensity
1 | Cursor home (move to col 1, row 1)
2 | Cursor return (move to col 1 without linefeed)
3 | Cursor up one row
4 | Cursor down one row
5 | Cursor left one column
6 | Cursor right one column
7 | Lock keyboard
8 | Unlock keyboard
9 | Erase to end of line
10 | Erase to end of screen
11 | Enter background display mode (reduced intensity)
12 | Enter foreground display mode (normal intensity)
13 | Enable protected fields
14 | Disable protected fields
15 | Delete line
16 | Insert line
17 | Delete character
18 | Insert character
19 - 20 | Undefined, unsupported, reserved
21 | Start blinking field
22 | End blinking field
23 | Start line drawing mode / enable alternate char set
24 | End line drawing mode / disable alternate char set
25 - 26 | Undefined, unsupported, reserved
27 | Set terminal attributes
28 | Cursor on
29 | Cursor off
30 | Start underscore
31 | End underscore
32 | Start reverse video
33 | End reverse video
34 | Start reverse blink
35 | End reverse blink
36 | Turn off screen display
37 | Turn on screen display
38 | Top left corner
39 | Top right corner
40 | Bottom left corner
41 | Bottom right corner
42 | Top intersect
43 | Right intersect
44 | Left intersect
45 | Bottom intersect
46 | Horizontal line
47 | Vertical line
48 | Intersection
49 | Solid block
50 | Slant block
51 | Cross-hatch block
52 | Double line horizontal
53 | Double line vertical
54 | Send message to function key line
55 | Send message to shifted function key line
56 - 62 | Undefined, unsupported, reserved
63 | Send message to host message field
64 | Up-arrow
65 | Down-arrow
66 | Raised dot
67 | End of line marker
68 | Horizontal tab symbol
69 | Paragraph
70 | Dagger
71 | Section
72 | Cent sign
73 | One-quarter
74 | One-half
75 | Degree
76 | Trademark
77 | Copyright
78 | Registered
79 | Not supported
80 | Set to wide (132 column) mode
81 | Set to normal (80 column) mode
82 | Enter transparent print mode
83 | Exit transparent print mode
84 - 90 | Undefined, unsupported, reserved
91 | Block fill with character
92 | Draw a box
93 | Scroll box up one line
94 | Scroll box down one line
95 - 99 | Undefined, unsupported, reserved
100 | Start underscored, blinking field
101 | End underscored, blinking field
102 | Start underscored, reverse field
103 | End underscored, reverse field
104 | Start underscored, reverse, blinking field
105 | End underscored, reverse, blinking field
106 | Start underscored text without space
107 | End underscored text without space
108 | Start reverse text without space
109 | End reverse text without space
110 | Start reverse blinking text without space
111 | End reverse blinking text without space
112 | Start underscored blinking text without space
113 | End underscored blinking text without space
114 | Start underscored reverse text without space
115 | End underscored reverse text without space
116 | Start underscored reverse blinking text w/out space
117 | End underscored reverse blinking text w/out space
118 | Start blink without space
119 | End blink without space
120 | Set cursor to blinking block
121 | Set cursor to steady block
122 | Set cursor to blinking underline
123 | Set cursor to steady underline
124-127 | Undefined, unsupported, reserved
128 | Select top status line without address
129 | End status line (all kinds)
130 | Select unshifted status line without address
131 | Select shifted status line without address
132 | Select black text (AM70-style color)
133 | Select white text
134 | Select blue text
135 | Select magenta text
136 | Select red text
137 | Select yellow text
138 | Select green text
139 | Select cyan text
140 | Select black reverse text
141 | Select white reverse text
142 | Select blue reverse text
143 | Select magenta reverse text
144 | Select red reverse text
145 | Select yellow reverse text
146 | Select green reverse text
147 | Select cyan reverse text
148 | Amigos-style save area
149 | Amigos-style restore area
150-157 | Undefined, unsupported, reserved
158 | Enable Mouse Cursor Reporting
159 | Disable Mouse Cursor Reporting
160 | Insight / AM75 set cursor shape. See Mouse Interaction.
161 | Undefined, unsupported, reserved
162 | Insight / AM75 define hot spot. See Mouse Interaction.
(163-191) | Undefined, unsupported, reserved
192 | Insight id (UNIX only)
(193-200) | Undefined, unsupported, reserved
201 | Tracker save screen attributes
202 | Tracker save entire screen
203 | Tracker restore entire screen
253 | Display Euro symbol
254 | Flush Screen Output Buffer


Limits and Capacities

Update August 2015 (Queue blocks)

Files and Related

Item | Size / limit / capacity / description | Updated in A-Shell build...; old value
Files | none; see File Size Limits. | 948 of Dec 05; 2GB
Filenames | 10+3 characters | 897 of Aug 04; 6+3
Expanded DO file | ~122K | 864 of Feb 04; 62K
Random file record size | No limit. Note, however, that this applies to READ and WRITE operations; there is a 2048 byte limit for SERCH. | 1246 of Apr 12; 64K
ISAM record size | 4K |
ISAM index file | 1 terabyte (theoretical); see ISAM File Size Limits. |
ISMA-A record size | 16K | 988 of Dec 07; 8K
ISAM-A index file | 2 terabytes (theoretical); see ISAM File Size Limits. | 1134 of Jan 09; 2GB
EFS limit of sequential files open at once | 512 (or the FILES= spec in the miame.ini, whichever is less). | 1244 of Feb 11; 30

Other

Item | Size / limit / capacity / description | Updated in A-Shell build...; old value
Print filter SBX names | 10 characters | 6.2.144 of Jan 2016; 6
ATE server side timeout on initial handshake | 6 seconds | 6.2.144 of Jan 2016; 3
Scrollback buffer | 200 lines | 6.2.1422 of Jan 2016; 100
Associative array key | 511 bytes | 6.2.1421 of Nov 2015; 259
Queue blocks | 65,535 |
DEVICE name | Three or four alphabetic characters, followed by one or two numeric digits, with a maximum length of five combined characters. |
Device definitions | 300 for UNIX, 1000 for Windows |
Ersatz name | One to ten alphabetic or numeric characters, starting with an alphabetic character, and immediately followed by a colon. |
Ersatz table auto-refresh | Every 30 seconds |
Ersatz devices allowed | 1000 | 979 of Jan 06; 400
ERSATZ=fspec length | 160 | 1208 of Mar 11; 70
Printer init file line length | 256 characters | 987 of Apr 07; 100
Command line length | 300 characters | 916 of Feb 05; 200
Number of GUI objects that can be defined at any one time | No limit | 1166 of Nov 09; 250
Number of modules that can be loaded into user memory | 96 (per job). Note that subroutines are modules. | 854 of Nov 03; 32
Input CSV line length | 4K | 995 of Sep 07 (mentioned)
++Include levels | 13 | 1131 of Dec 08; 3
Windows printer name | 100 characters | 1148 of May 09; 50
Command line history buffer | 25 lines | 1168 of Dec 09; 10
VUE line length | 4K for new files, 1K+longest of first 100 lines for existing files | 1196 of Nov 10; 2022
Max length of dynamic S or X variable | No limit |
Max ++include'once statements | No limit | 1235 of Oct 11; ~400
HOST.LIT max response capture buffer | 256 | 2.0(105) of Aug 11; 64K
PAD$(expr,len) return expression length | 4096 | 1175 of Feb 10; 257
TAB(col) maximum columns | 4095 | 1105 of Feb 08; 472
Buffer to expand strings containing %env% variables. | Unlimited | 512 bytes; 6.0.1263 of Oct 12
Nested function/procedure calls | Set limit of 99 as a way of reducing the likelihood and severity of problems caused by accidental infinite recursion. | Unlimited; 6.1. 1387 of July 2014

Subroutines

Item | Size / limit / capacity / description | Updated in A-Shell build...; old value
Number of parameters than can be passed to a subroutine | 128 | 1219 of May 2011, 100
Size of subroutine name | Six characters. This is in contrast to general filenames, which can be up to ten characters. Applies to SBX and SBR. |
Maximum size of a parameter passed in or out of a subroutine | 2**24-1 (16,777,215) bytes |
Number of subroutines on disk or called in a single program | No limit |
Number of modules that can be loaded into user memory | 96 (per job). Note that subroutines are modules. | 854 of Nov 03; 32
AUI: maximum number of controls | Unlimited. The control table expands as needed. | 1166.6.1 of 16 Nov 09; 600
AUI: maximum number of menu items | Unlimited. The menu table expands as needed. | 1166.6.1 of 16 Nov 09; 250
AUI_MENU: length of individual menu item command line | 200 |
AUI_MENU: length of individual menu item description | 64 | 1159 of Sep 09; 32
INFLD: length of entry (multi-line field) | No limit | 1159 of Sep 09; 16K
INFLD: maximum SETDEF match length | 300 | 1111 of May 08; 50
INFLD: tooltip maximum characters | 1023 | 5.1.1175, 300
MX_CLIPBOARD: buffer size | No limit | 1194 of Nov 10; 3K
MX_GETOFD: maximum fname parameter length | 256 | 1222 of Jul 11; 80
MX_PWCRYPT: max password length | 128 | 1175 of Feb 10; 24
MX_SHELLEX: parameter length | 1024 individual parameter; 4096 for all parameters combined | 1202 of Jan 11; 500
PCKLST: maximum rows | 32K |
REGEX: maximum submatches: | 100 | 1210 of Mar 11; 20
XTEXT: maximum line length | 1998 characters | 1253 of June 12; 998
XTREE: maximum columns | 100, may be editable or not | 1159 of Aug 09; 80
XTREE: maximum rows | No limit | 1159 of Sept 09;
XTREE: number of trees allowed | No limit | old limit = 32
XTREE: tooltip maximum length | 1023 characters | 1205 of Feb 11


Libraries

A-Shell makes use of several libraries, which are listed here. The "Notes" column in the tables indicates:

• The source of the library: (1) developed by Microsabio; (2) purchased/licensed from external commerical sources; (3) open source modules.

• Whether the library is included with all installations of A-Shell (a), or is included only if needed and/or by special arrangement (b).

Note also that the actual library name may incorporate platform and/or version data into its name. For example, the table below lists "SftTree," while the actual filename of the DLL is "SftTree_IX86_U_75."

Windows

A-Shell uses the following Dynamic Linked Libraries (DLLs).

Name | Notes | ~Size KB | Description
ashico1 | 1, a | 10,480 | A-Shell icon library; see samples here.
ashnet | 1, a | 3,026 | Network-related functions.
ashnet2 | 1, a | 713 | SSH services for ATE.
FTPDLXcall2 | 1, a | 52 | FTP functions used in FTPDLX.
HTS14 | 2, a | 576 | HTML support for XTEXT.
libashmysql | 1, a | 16KB | ASQL interface to MySQL connector.
libxl | 2, a | 6,327 | Spreadsheet functions.
pcre3 | 3, a | 137 | Perl compatible Regular Expressions.
SftPrintPreview | 2, a | 853 | APEX functions.
SftTabs | 2, a | 750 | TABX control
SftTree | 2, a | 620 | XTREE.
spell32 | 2, a | 92 | Spell-checking used in XTEXT.
TER19 | 2, a | 1,680 | XTEXT control.
txml2 | 2, a | 92 | Allows .docx files to be imported to XTEXT.
vic32 | 2, a | 228 | Graphics and images.
victw32 | 2, a | 60 | TWAIN support.
wodFtpDLX | 2, a | 920 | FTP functions used in FTPDLX.

Name | Source | ~Size KB | Description
libashodbc | 1, b | 24 | ASQL interface to OBDC connector.
libashtls | 1, b | 16 | TLS support for TCPX.SBR.
libgnutls | 3, b | 2010 | GNUTLS (required for libashtls)
libtasn1 | 3, b | 160 | GNUTLS.
libgpg-error | 3, b | 110 | GNUTLS.
libgcrypt | 3, b | 1650 | GNUTLS.
ucibv | 3, b | 870 | GNUTLS.
libfcgi | 3, b | 40 | Fast CGI support.

Linux

Name | Source | ~Size KB | Description
libashmysql |  | 40 | ASQL interface to MySQL connector
libashtls |  | 20 | TLS support for TCPX.SBR
libxl |  | 3200 | Spreadsheet functions
libashnet |  | 6180 | CRYPTO.SBR

Subtopics

ASHNET.DLL

ASHNET2.DLL


ASHNET.DLL

This dynamic link library (Windows only) contains support routines for various network-related functions, in particular:

• HTTP.SBR

• PDFX Email Type 4

• CRYPTO.SBR

Update Notes, 2016 November, version 1.8.153, 54

Relink with updated SSL, SFTP and HTTP libraries to incorporate many minor bug fixes and improvements in the underlying libraries over the last 11 months. The DLL is backwards compatible to A-Shell and ATE 6.2.

The properties options introduced in 1.8.153 now apply to the HTTPF_REQGET ("simple get") operation as well as the other operations/modes; previously they were ignored for the simple get. Also, the default timeout parameters (30 seconds on connection, 75 on read) now apply to the HTTPF_REQGET operation even if properties are not explicitly specified. Previously the timeouts were indeterminate, but definitely shorter than the new defaults.

Update Notes, 2014 May, version 1.7.145

Security-related enhancement:

• supports public/private key authentication for SFTP via AG_FTP or FTPDLX.

• fixes problems with SFTP downloads without explicit local paths.

• fixes a bug in CRYPTO.SBR where the dst parameter was being truncated if needed to allow for an explicit trailing null.

• supports new CRYPTO.SBR function to generate public/private key files.

Note: requires ASHW32.EXE 6.1.1385.0+ and should be updated at same time.

Update Notes, 2013 July, version 1.4.137

• Implements support for initial functionality of CRYPTO.SBR

Update Notes, 2013 June, version 1.4.135

• Support new HTTP.SBR arguments certfile and certpw

Update Notes: 2012 October/November, version 1.4.132

• User agent in headers now shows "ashnet 1.4.131."

• Now accepts port specifications embedded in the URL, i.e. http://www.mydomain.com:10080/mypath. Previously it only accepted the port if it was appended to the end of the URL, but that is a non-standard syntax and results in the port not being included in the "Host: domain{:port}" header of a POST request. The syntax shown above, i.e. {scheme}<domain>{:port}{path} is preferable.

• The DEBUG.REQ file (copy of the request) had an extra CR at the end of each line (CRCRLF instead of CRLF). This didn't affect the actual request, but may have confused tech support efforts.

• When the XHTTPF_DEBUG flag is set, in addition to creating the DEBUG.REQ file, it also appends a line to ASHNET.LOG indicating the ashnet.dll version, domain, port, SSL flag and return status, e.g.:

HttpRequest v127 to www.mydomain.com port 10080 (SSL) rc=201 HTTP/1.1 201 created

This serves mainly to eliminate doubts during debugging as to where and how the request (DEBUG.REQ) was sent.

In addition, a new log file, DEBUG.LOG, will be created that combines lower level details about the individual steps performed within the operation, but also a transcript of what is sent and received over the wire.

• Support custom Content-Type prefixes for uploaded files using XHTTPF_REQUPLOAD

• Support separate option to retrieve the HTTP status text using XHTTPF_GETSTSTXT

• If the operation fails to connect to the server, a verbose log of the request details is now written to the file DEBUG.LE (e.g. LastError), which might be helpful in debugging.

• Added XHTTPF_REQGETRAW: like XHTTPF_REQGET (&h0020) but works around a limitation of XHTTPF_REQGET in which certain characters outside the range supported by Latin1/ANSI (e.g. Russian or Chinese) would just be dropped from the response. Can also be used to retrieve binary data containing embedded nulls (such as a file), although you must then use XHTTPF_FILERESP (&h0200) to write the response to a file.


ASHNET2.DLL

ASHNET2.DLL, like ASHNET.DLL, is a wrapper for various third-party library functions, making them conveniently accessible to A-Shell and ATE. In particular, ASHNET2 provides SSH services to ATE which are built around the open source libraries LIBSSH2 and OpenSSL.

Update Notes, 2014 May, A-Shell 6.1.1385, ASHNET2.DLL 2.2.205

Security-related enhancement:

• supports public/private key authentication for SFTP via AG_FTP or FTPDLX.

• fixes problems with SFTP downloads without explicit local paths.

• fixes a bug in CRYPTO.SBR where the dst parameter was being truncated if needed to allow for an explicit trailing null.

• supports new CRYPTO.SBR function to generate public/private key files.

Note: requires ASHW32.EXE 6.1.1385.0+ and should be updated at same time.


General Information

Publisher

MicroSabio

6520 Platt Ave., #104

West Hills, CA 91307 USA

web site: www.microsabio.com

email: info@microsabio.com

voice: 818-710-8437

fax: 818-704-4882

Authors

Jack McGregor has been developing and documenting A-Shell since 1994, and his authorship continues through the date of this publication. Ty Griffin is responsible for editing, formatting, spilling and pulbishing.

Support

MicroSabio provides extraordinarily good support for A-Shell and its other software products.

The first place to go with a question is the A-Shell forum, also known as the "Bulletin Board" (BBS) and the "A-Shell Network." You can search the forum by keyword, quite possibly finding the answer(s) you need. If not, then post your question there; you have to create an account to post a question, but doing so is painless and free. (Email us if you have any problems or questions about signing up.) All of the forums are moderated by MicroSabio, which means that if another user or developer does not answer your inquiry, MicroSabio staff will.

The main MicroSabio web site contains a variety of documentation, utility, and other support pages and downloads.

If you are not getting satisfaction via these support avenues, send MicroSabio an email with your question and it will be answered promptly.

MicroSabio provides free email support for A-Shell operational issues to anyone with a current maintenance contract, and also within the first 90 days of purchasing a license. If you are running a demo copy for evaluation purposes, you can obtain free support on the BBS. If you would like a free pre-sales consultation, please contact MicroSabio. Either of these avenues is also a good way to discuss or initiate a request for more advanced support than what we can provide for free (such as help with developing subroutines, custom enhancements to A-Shell, etc.) We pride ourselves on providing a higher level of support than most other software developers with whom you may be familiar, so don't hesitate to take advantage of it.

Software History

While Under Development |  |  | At Formal Release
 | First Release |  |  | Final Release*
Version | Build | Date | Version | Build | Date
6.5 | 1600 |  |  |  |
6.3 | 1500 | November 2015 | 6.4 | 1545 | March 2017
6.1 | 1300 | Spring 2012 | 6.2 | 1421 | Autumn 2015
5.1 | 1100 | November 2007 | 6.0 | 1270 | Autumn 2011
4.9 | 850 | October 2003 | 5.0 | 997 | Autumn 2007
4.7 | 796 | February 2002 | 4.8 | 833 | June 2003
4.5 | 652 | November 1998 | 4.6 | 712 | December 1999
4.2 | 507 | August 1996 |  |  |
** | 468 | August 1995 |  |  |
4.0 | 463 | August 1995 |  |  |
3.0 | 310 | August 1993 |  |  |
2.0 | 134 | June 1991 |  |  |
1.0 | 100 | February 1990 |  |  |

* Bug fixes continue to be applied past the date of the "final" release.

** John Bown was the original developer of A-Shell, and continued through build 467. With build 468, Jack McGregor took over developer responsibilities.

Documentation History

Version | Date | Version | Date | Version | Date | Version | Date
E02 | 13 Dec 01 | C04 | 13 Jan 97 | B07 | 13 May 94 | A01 | 09 Oct 91
E01 | 20 Nov 00 | C03 | 13 Jun 96 | B06 | 16 Feb 94 | A00 | 01 Oct 90
E00 | 07 Mar 00 | C02 | 20 Feb 96 | B05 | 29 Sep 93 |  |
 |  | C01 | 25 Jul 95 | B04 | 14 Jun 93 |  |
 |  | C00 | 20 Mar 95 | B03 | 30 Mar 93 |  |
D02 | 11 Feb 99 |  |  | B02 | 13 Jan 93 |  |
D01 | 05 Oct 98 |  |  | B01 | 16 Nov 92 |  |
D00 | 20 Aug 98 |  |  | B00 | 23 Jun 92 |  |

In early 2002, a new documentation system and format was adopted, and version numbers for the documentation were abandoned.

Between 2002 and 2010, documentation was published in the CHM format, with PDF and DOC (MS Word) files available on request. Beginning in 2010, all A-Shell documentation has been online in a customized HTML format.


Documentation

Using This Document

The author of this help file says:

● Click on the little books or plus marks next to topics in the table of contents; this will expand/contract the listing of items under that heading.

● Use the Index and Search functions to quickly find topics of interest. See "Using Search" below.

● To copy the URL of the current page, copy from the address bar or click on the email icon at top of the document.

● Use "Previous" and "Next" buttons on the toolbar to go forward and backward through document. The browser's "back" button takes you to the page you last viewed, not to the previous page of the document you're viewing.

● To locate your position in a document after using search or index or links, click on "Content" and then look for the highlight. It may be necessary to scroll up/down through the table of contents.

Available Docs

All published documentation for A-Shell and related topics are listed at the MicroSabio website on the download...documents page. If that page doesn't answer your questions about what docs are available, or if you need historical docs or docs in unlisted formats, contact MicroSabio with your concerns.

Developer documentation—i.e., for more recent versions of A-Shell than have been formally released—may be available from other locations, which will be noted on the documents page.

Using Search

Along with the index, the search function provides the best way to find what you're looking for. The operators AND, OR, NOT, along with quotes, are supported and work as expected.

● Searching for quite useful, or quite and useful, will return all the pages that contain both of the words quite and useful.

● Searching for "quite useful" (with the quotes) will return the pages that contain the phrase quite useful.

● Searching for quite or useful will return all the pages that contain the word quite plus all the pages that contain the word useful.

● Searching for quite not useful, or quite and not useful, will return all the pages that contain the word quite and do not contain the word useful.

Note that many common words (this, that, the, to, for, it, them, etc.) are ignored by search unless they part of a quoted string. Also note that the case of the operators (AND, and) is not significant.

Other Tips

● To get the URL for the page you are currently viewing, copy it from the address bar of your browser or click on the little email icon Email on the right end of the tool bar.

● You can drag the border between the table of contents and the documentation body to create more room for one side or the other.

Updates

The A-Shell documentation is kept very up to date. Jack meticulously documents every change/addition/improvement to A-Shell, writes the text version of ashdevnotes, and posts it with new versions of the software. As mentioned above, you can always find the up-to-the-second release notes with the latest versions of A-Shell.

Usually within hours but no more than a day or two, Ty converts the text version of ashdevnotes into an HTML version, and posts it in the same place. All the new or changed material from ashdevnotes is incorporated immediately into the applicable manual(s) of the main A-Shell doc set, and those docs are immediately published and available.

To read the latest versions of any A-Shell documentation, simply go to the download...documents page and click on the doc that interests you.

Feedback

Just as A-Shell itself is a work in progress, so the documentation is constantly being tweaked, twiddled and improved. Ty works on the docs more or less continuously, and enthusiastically welcomes feedback of all types, particularly:

● identification of language mistakes (typos, misspellinggs, bad sentences, missing words, etc.)

● identification of "real" mistakes, namely saying something that isn't true

● suggestions for better explanations

● suggestions for index entries

If you have any comments, ideas, suggestions or other kinds of feedback, please post them in the "All Other A-Shell Topics" at the A-Shell forum or email them to us.

Subtopics

File Types


File Types

Although web-based HTML help files are recommended for most readers in most circumstances, other file formats may be applicable or needed in some situations. Sometimes, for historical reasons or by special request, the A-Shell documents may be available in other file formats. If you would like to get the documentation in a format you don’t see, it may be available on request. Continue reading for information about document formats and files types, and why you might prefer one or another.

Formats

HTML (aka "Net Help"): These help files are standard web pages, with hyperlinks, tables of contents, linked indexes and search capabilities. They reside on the MicroSabio web servers, are always up to date, and require no downloading step; pages are downloaded on demand—and very quickly. As long as you have a good internet connection, this is the preferred format for help/documentation files.

CHM (Compiled HTML, standard Windows help files): CHM files are compilations of HTML pages into a single document which includes all the features of the HTML documents. CHM files are downloaded to and accessed from your computer, and are the preferred help file format when you do not have a good internet connection. CHM files are opened using built-in components of Windows, so no additional programs are required to view them. If you are running Windows 98 or later, you have what you need in order to read CHM files. If you download them to your Windows computer and then double-click on them, they should be properly opened and displayed in the familiar help-file context. Important note: for security reasons and because they include "active content," CHM files may be blocked from displaying their contents properly by recent versions of Windows. To release the lock and have the files display properly, right click on the CHM file, select “Properties,” and then “unblock” the file.

PDF (Adobe's Portable Document Format): Various A-Shell docs have been available as PDF files in the past, and may be available on request; inquire if you are interested. Files of this type consist of exact replicas of printed pages, just as they appear in a printed manual. If you plan to print a copy of the document, this is the best type of file to download. PDF files are not hypertext documents or pure help systems, but most documents (including all the PDF files on this site) come with an interactive table of contents. This file format and the program(s) needed to read these files are the property of Adobe Systems. If your computer does not already have a copy of Adobe® Acrobat®, which you will need in order to read the files, you may download a free copy from the Adobe Acrobat download page.

PDF Printing - Important note: If you intend to print the PDF documents, be sure that your printer is configured to interpret colors as either black or white; if the printer tries to interpret colors as shades of gray, all the color printing in the document will appear as gray—i.e., light and not very readable black. A-Shell help files do not use a lot of color, but they use some for text formatting and screenshots. On pure black and white printers, configured as black and white printers, the colored material prints fine.

TXT: Text files are universally readable by all computers and all operating systems, so you can download or display them regardless of your system. They do not contain any organizational or text formatting, however, and are therefore the most difficult file type to read.

DOC: This is the native file format of Microsoft Word, and is the original source of most MicroSabio documentation files. We write the docs in Word, in other words, and translate into all the other formats with various types of conversion and authoring programs. So all of the documents are readily available in Word format, either .doc or .docx; if you want them, just ask.

Printing

HTML and CHM files are not particularly well-suited for printing. They are fine if you want to print a few pages or even a full section, but not if you want to print an entire doc/manual for reading and reference. The best format for printing is PDF. If you wish to print the docs, therefore, make sure to get a PDF version of the doc(s) you want to print. If you don’t see them here, contact MicroSabio and ask about a PDF for the doc in question.

Subtopics

CHM Files


CHM Files

CHM files have largely been superseded by HTML in the A-Shell library. CHM files were the best choice in days of limited internet access—and still are the best choice when the internet is not available. Here is some general information on CHM files.

Background Information

● Compiled HTML help ("CHM") is a proprietary format for help files developed by Microsoft. It was first used in 1997 (Win98) as a successor to the even-older WinHelp format, and is still supported through Windows XP, Vista, Win7 and Win8. Microsoft no longer creates CHM files for its own documentation and has moved on to a new format, but CHM will likely be supported for a long time.

● CHM files consist of individual web pages plus a hyperlinked table of contents. The resulting file is compressed using LZX compression, making CHM files rather efficient and relatively small.

● CHM files are created using a free tool from Microsoft called "HMTL Workshop." Many additional tools for creating CHM files, as well as other help-file formats, are on the market. They are collectively known as "help authoring" tools or systems. The help file you're reading right now was created by a combination of Microsoft Word and a help-authoring tool called "Doc to Help."

● CHM files contain "active content"--i.e., the files are executable—and therefore are frequently perceived as being security risks. Gmail, for example, blocks CHM files.

● For more information, see the Wikipedia entry for CHM files (from which some of the above facts were taken).

Problems and Solutions

● For security reasons, CHM files will normally not be displayed properly or at all when you are trying to access them from network drives or remote servers. It is possible to change your security settings to accommodate such files, but the easier solution is just to move the CHM file(s) to a local drive.

● CHM files will not work if their path or filename includes the pound (aka hash) character '#'. The hash character signifies an anchor in HTML so the CHM viewer fails to resolve the path properly and to retrieve the content. If this is your situation, move the file to a path that does not have a hash character in its name. In general, avoid using '#', '?', '&', '+', and other special characters in directory names.

● When you click on an external link inside a CHM file, the web page is opened with Internet Explorer and not with your computer's default browser. Why? Since the CHM viewer itself is a component of IE, or *is* IE operating in some special mode, the program does not issue a conventional call to the PC to use the default browser. Instead, since IE is already running and available, IE simply "tells itself" (?!!) to open the external page. There is no work-around to this "problem."

● Windows (XP/Vista/Seven) security provisions may prevent CHM files from opening. If you get a "cannot display" message in the right pane of the display window, this may be the problem. Solution: right-click on the CHM file and select Properties from the popup menu. Click on the Unblock button immediately below the Advanced button on the General page, then click Apply. Once the CHM file has been unblocked, the Unblock button disappears, and you need only do this once—i.e., not every time you open the file.

● If the ideas and suggestions mentioned above do not resolve your problems opening CHM files, you might want to do a web search for "MJ's Help Diagnostics." This is a program that checks to see if the Windows programs and components needed to display CHMs are properly and completely installed on your (Windows) computer.


Legal Notices

This documentation and the software it describes contain proprietary information belonging to MicroSabio, a California proprietorship owned entirely by Jack McGregor. The software and this related information is provided under the terms of the MicroSabio License Agreement, which contains restrictions on use and disclosure, and is protected by copyright law. This information is confidential between MicroSabio and the client, and remains the exclusive property of MicroSabio.

Due to continued product development, the information contained herein may change without notice. It is believed to be accurate and reliable, at least at the time of its writing. However, no responsibility for the accuracy, completeness or use of this information is assumed by MicroSabio. If you find any problems in the documentation, please report them to the publisher.

No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, electronic, mechanical, photocopying, recording or otherwise, without the expressed or licensed permission of MicroSabio.

Acknowledgments

Digest: Copyright © 2001-2003 Christophe Devine. Used by permission via the GNU General Public License.

Natural sort (used in BASORT, XTREE, SORTIT and elsewhere): Copyright © 2000, 2004 Martin Pool. Used by permission.

FastCGI (used in libfcgi): Copyright © 2004-2017 Free Software Foundation, Inc. Licensed under the GNU Free Documentation License, version 1.3 or later.

LibXL: Licensed from XLWare.

Trademarks

MicroSabio, A-Shell, INMEMO, INFLD and EZ-SPOOL are trademarks of Jack McGregor.

Adobe and Acrobat are registered trademarks of Adobe Systems, Inc . one mention in setup

AIX and Informix are registered trademarks of International Business Machines Corporation.

Alpha Micro, AMOS, and AlphaBASIC are registered trademarks of Alpha Micro Products, Inc.

AlphaLAN is a trademark of U.A. Systems, Inc .

Autolog is a trademark of Bob Rubendunst at Soft Machines .

BackupEDGE is a trademark of Microlite Corporation.

FacetTerm and FacetWin are registered trademarks of FacetCorp.

HP-UX is a trademark of the Hewlett-Packard Company.

Linux is a registered trademark of Linus Torvalds.

Microsoft and Windows are registered trademarks of Microsoft Corporation.

OpenSSL is a trademark of the OpenSSL Project. See OpenSSL Project License.

Red Hat is a trademark of Red Hat, Inc.

SCO is a registered trademark of Caldera Systems, Inc.

Softworks Basic is a trademark of Bob Salita.

Solaris is a registered trademark of Sun Microsystems, Inc.

UNIX is a registered trademark of The Open Group.

WS_FTP is a registered trademark of Ipswitch, Inc.

ZTERM is a trademark of Rod Hewitt at Cool.stf.

All other products, services, companies, events and publications are trademarks, registered trademarks or service marks of their respective owners.

Subtopics

MicroSabio License Agreement

OpenSSL Project License

SSLeay License

DYNCALL Library License

LIBSSH3 Library License

GnuTLS Library


MicroSabio License Agreement

This is a legal agreement between you, acting as an individual on your own behalf or as an authorized agent for your organization, and MicroSabio. By installing the software on your computer(s) or by using the software product for which this license was issued, you are agreeing to be bound by the terms of this agreement. If for any reason you do not agree to the terms of the Software License, delete all relevant files from your computer(s) and return all related physical items (disks, license forms, documentation, etc.) to the point of purchase within 30 days for a full refund.

Software License

Grant of License—Single Computer: MicroSabio grants to you the right to use the accompanying software product ("Software") on a single computer. You may not network the software or otherwise use it on more than one computer.

Grant of License—Multiple Computers: MicroSabio grants to you the right to use the software on the specific number of computers for which the software has been licensed. You may not use the software on more than the specified number of computers.

Grant of License—Multiple Users: MicroSabio grants to you the right to use the software on one or more computers but only for the specific number of users for which the software has been licensed.

Copyright. The software is owned by MicroSabio or its suppliers and is protected by United States copyright laws and international treaty provisions. Therefore, you must treat the software like any other copyrighted material (e.g., a book or musical recording) except that you may either (a) make one copy of the software solely for backup or archive purposes, or (b) transfer the software to a single hard disk provided you keep the original solely for backup or archive purposes.

Other Restrictions. You may not rent, loan, sell or otherwise transfer the software to anyone else unless (a) you permanently transfer all copies in your possession, and (b) the recipient agrees to the terms of this agreement. You may not decompile, translate, reverse engineer or disassemble the software.

Limited Warranty. MicroSabio warrants that the software will perform substantially in accordance with its accompanying written materials and published specifications, when properly installed on a properly configured computer for which it is intended, for a period of 90 days from the date of receipt.

Customer Remedies. MicroSabio's, its suppliers' and its distributors' entire liability and your exclusive remedy shall be, at MicroSabio's option, either (a) return of the price paid or (b) replacement of the software which is returned to the point of purchase with your receipt. This Limited Warranty is void if failure of the software has resulted from accident, abuse or misapplication. Any replacement software will be warranted for the remainder of the original warranty period or 30 days, whichever is longer.

Limitation of Warranty. MicroSabio, its suppliers and its distributors disclaim all other warranties, expressed or implied, including, but not limited to, any implied warranty of merchantability and fitness for a particular purpose. In no event shall MicroSabio. its suppliers or its distributors be liable for any consequential damages whatsoever arising out of the use of or inability to use this product, even if advised of the possibility of such damages.

This Agreement is governed by the laws of the State of California. If you have any questions regarding the license agreement, the limited warranty or any other matters, please write to MicroSabio at the address provided on the "Contact" page of the MicroSabio web site.


OpenSSL Project License

OpenSSL is used in A-Shell by both the ATE SSH2 transport and TCPX.SBR when the TLS or STARTTLS options are used.

Copyright © 1998-2017 The OpenSSL Project. All rights reserved.

The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the OpenSSL License and the original SSLeay License apply to the toolkit. See below for the actual license texts. Actually both licenses are BSD-style Open Source licenses. In case of any license issues related to OpenSSL please contact openssl-core@openssl.org.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. All advertising materials mentioning features or use of this software must display the following acknowledgment: "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)"

4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact openssl-core@openssl.org.

5. Products derived from this software may not be called "OpenSSL" nor may "OpenSSL" appear in their names without prior written permission of the OpenSSL Project.

6. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/)"

This software is provided by the openssl project "as is"' and any expressed or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the opensll project or its contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.

This product includes cryptographic software written by Eric Young (eay@cryptsoft.com). This product includes software written by Tim Hudson (tjh@cryptsoft.com).


SSLeay License

SSLeay is a component of OpenSSL and is used in A-Shell by the ATE SSH2 transport .

Copyright © 1995-2017 Eric Young (eay@cryptsoft.com). All rights reserved.

This package is an SSL implementation written by Eric Young (eay@cryptsoft.com).

The implementation was written so as to conform with Netscape's SSL.

This library is free for commercial and non-commercial use as long as the following conditions are adhered to. The following conditions apply to all code found in this distribution, be it the RC4, RSA, lhash, DES, etc., code; not just the SSL code. The SSL documentation included with this distribution is covered by the same copyright terms except that the holder is Tim Hudson (tjh@cryptsoft.com).

Copyright remains Eric Young's, and as such any Copyright notices in the code are not to be removed. If this package is used in a product, Eric Young should be given attribution as the author of the parts of the library used. This can be in the form of a textual message at program startup or in documentation (online or textual) provided with the package.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. All advertising materials mentioning features or use of this software must display the following acknowledgement: "This product includes cryptographic software written by Eric Young (eay@cryptsoft.com)." The word 'cryptographic' can be left out if the routines from the library being used are not cryptographic related.

4. If you include any Windows specific code (or a derivative thereof) from the apps directory (application code) you must include an acknowledgement: "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"

This software is provided by eric young "as is'' and the author disclaims any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the author or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.

The license and distribution terms for any publically available version or derivative of this code cannot be changed—i.e., this code cannot simply be copied and put under another distribution license (including the GNU Public License).


DYNCALL Library License

The DYNCALL library provides the basis for the A-Shell subroutine "DYNLIB.SBR."

Copyright © 2007-2017: Daniel Adler and Tassilo Philipp <tphilipp AT potion-studios DOT com>

Contact: <dadler AT uni-goettingen DOT de>; <tphilipp AT potion-studios DOT com>

Web resources: http://www.dyncall.org/license

Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

The software is provided "as is" and the author disclaims all warranties with regard to this software including all implied warranties of merchantability and fitness. In no event shall the author be liable for any special, direct, indirect, or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software.


LIBSSH3 Library License

The LIBSSH3 library is used by A-Shell's "libashtls," which is used in turn by TCPX if the TCPXFLG_TLS flag is set.

Copyright © 2004-2007 Sara Golemon <sarag@libssh2.org>

Copyright © 2005, 2006 Mikhail Gusarov <dottedmag@dottedmag.net>

Copyright © 2006, 2007 The Written Word, Inc.

Copyright © 2007 Eli Fant <elifantu@mail.ru>

Copyright © 2009-2014 Daniel Stenberg

Copyright © 2008, 2009 Simon Josefsson

All rights reserved.

Web resources: https://libssh2.org/

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

• Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

• Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

• Neither the name of the copyright holder nor the names of any other contributors may be used to endorse or promote products derived from this software without specific prior written permission.

This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.


GnuTLS Library

The GnuTLS library is used by A-Shell's "ashnet2," which provides SSH2 support to ATE.

Web resources: https://libssh2.org/

The library is licensed for use and distribution under the terms of the GNU Lesser General Public License version 2.1.


1: Window Title Bar

By default, A-Shell shows its own version, and ATE shows the name of the connection. May be changed programmatically using AG_WINTITLE, or semi-automatically in response to changing conditions using the SET.LIT TITLE definition string. The icon appearing in the upper left corner, which by default is the A-Shell icon, may be changed using the command line switch for Alternate Icon (-g) or, in ATE, via an option in the connection properties dialog.


2: Standard Buttons

The standard Windows buttons, minimize, maximize and close, will always appear unless removed. To remove them, use the command line switch Remove Menu Buttons (-mx).


3: Standard Menu Bar

Standard menu bar. May be removed via the command line switch No Menu (-nm), or customized programmatically using AUI_MENU commands.


8: Status Line - Top

This is typically used for auxiliary messages from the host application to the user, sent via the tab(-1,128) or (-1,63) commands. The former always starts from the first position on the line, while the latter takes a position code byte for direct addressable positioning. In either case, use tab(-1,129) to terminate the print operation. Status lines may be enabled and disabled using the Settings > Status Lines menu options, or programmatically via the AG_STATUSLINES command. For ATE they may also be configured using the Connection Properties dialog.


9: Status Line - Bottom

This is similar to the top status line but traditionally used for "function key labeling". There are actually two bottom status lines which toggle visibility depending on whether the Shift key is down. The unshifted line may be written to via the print commands Tab(-1,130) or (-1,54), full line or addressable position, respectively, while the shifted line may be written to via the Tab(-1,131) or (-1,55) commands. As with the top status line, terminate all status line print operations with Tab(-1,129). See top status line notes for enabling/disabling the bottom status line.


10: Status Line - Session

This line is reserved for messages emanating from A-Shell or ATE; for example, notification of a file transfer or print operation. A running session clock is displayed at the right edge of the line. See top status line notes for enabling/disabling.


11: Margin - Left

This is the left margin of the main display grid. The main display area is divided up into a grid (see #13) of a specified number of rows and columns. After dividing the available display area into the specified columns, the remaining pixels are divided in two and used for left and right margins. For example, if the width of the display area is 1000 pixels and there are 80 columns, then each column will be 12 pixels wide (12 x 80 = 960) with 40 pixels left over, which will be divided into left and right margins of 20 pixels each. To minimize the margin area, you can adjust the size of the window by dragging one of the borders. On some monitors, a maximized window may extend slightly beyond the edges of the visible screen, causing the first and last characters of each line to be truncated. To mitigate that problem, you can force a minimum margin for maximized windows, via the Settings > Misc Settings dialog.


12: Margin - Top

This is the top margin of the main display grid. It works the same as the left margin; see #11 for explanation. As with left/right margins, the excess vertical space is divided evenly between the top and bottom margins.


13: Main Display Area

The main display area (grid) is made up of a specified number of rows and columns, usually 24 x 80, but adjustable using the Tab(-5,rows) and (-6,cols) commands (see Set Number of Rows and Set Number of Columns), and/or the SET.LIT Terminal Options. In the case of plain text, each character occupies one grid cell, whose size will determine the standard fixed-pitch font. To make that font larger, you can either increase the size of the display area, or decrease the number of rows and columns, or remove some of the status lines and/or toolbars, which otherwise take away from the space available to the main grid. Graphic objects such as proportional font text, edit boxes, buttons and other controls, as shown in the example above, are positioned using the same grid, but are not confined to the one-character-per-cell scheme used for plain text. For more precise positioning of graphic objects, you can make adjustments using Millirows and Millicolumns. The objects themselves are typically created with the AUI_CONTROL command.


4 - 7: Toolbars

These are the top, right, bottom, left toolbars. They may be created programmatically using the AUI Toolbar Control and winstyle options CCS_TOP, CCS_RIGHT, CCS_BOTTOM, and CCS_LEFT. The thickness of each toolbar is determined by the size of the button images held within, which must all be the same size for a given toolbar but may differ between toolbars. Unlike most other elements of the screen, toolbars do not scale as the window size changes, other than to match the length of the window edge to which the toolbar is attached.


ashell.def

This file, included with A-Shell and normally found in DSK0:[907,16], provides a list of most symbols defined for use with routines embedded in A-Shell. Most applications using A-Shell functions, particularly GUI functions, will want to ++include ashell.def in every program. Note that doing so does not increase the size of the RUN file except for symbols that are actually used. A-Shell routines that have traditionally been distinct from A-Shell have their own symbol definition files (i.e., mmosym.def for INMEMO), and most SBX routines also have their own symbol definition (.def) files. The latest copy of ashell.def can always be found in the SOSLIB:[907,16] .This file, included with A-Shell and normally found in DSK0:[907,16], provides a list of most symbols defined for use with routines embedded in A-Shell. Most applications using A-Shell functions, particularly GUI functions, will want to ++include ashell.def in every program. Note that doing so does not increase the size of the RUN file except for symbols that are actually used. A-Shell routines that have traditionally been distinct from A-Shell have their own symbol definition files (i.e., mmosym.def for INMEMO), and most SBX routines also have their own symbol definition (.def) files. The latest copy of ashell.def can always be found in the SOSLIB:[907,16] .This file, included with A-Shell and normally found in DSK0:[907,16], provides a list of most symbols defined for use with routines embedded in A-Shell. Most applications using A-Shell functions, particularly GUI functions, will want to ++include ashell.def in every program. Note that doing so does not increase the size of the RUN file except for symbols that are actually used. A-Shell routines that have traditionally been distinct from A-Shell have their own symbol definition files (i.e., mmosym.def for INMEMO), and most SBX routines also have their own symbol definition (.def) files. The latest copy of ashell.def can always be found in the SOSLIB:[907,16].


ashell.def

This file, included with A-Shell and normally found in DSK0:[907,16], provides a list of most symbols defined for use with routines embedded in A-Shell. Most applications using A-Shell functions, particularly GUI functions, will want to ++include ashell.def in every program. Note that doing so does not increase the size of the RUN file except for symbols that are actually used. A-Shell routines that have traditionally been distinct from A-Shell have their own symbol definition files (i.e., mmosym.def for INMEMO), and most SBX routines also have their own symbol definition (.def) files. The latest copy of ashell.def can always be found in the SOSLIB:[907,16].


Coldef Default

When the option is associated with the pseudo-zero column, the specified value becomes the default for all subsequent columns. That default may be overridden by specific settings for individual columns, but the default will reassert itself on subsequent, non-overridden columns.

See the additional discussion in the Cpos, Cwidth topic.


CSIDL_xxx identifiers

Here is a listing of the symbols defined in ashinc:CSIDL.DEF.

Symbol | Value | Meaning
CSIDL_ALTSTARTUP | 29 | User's non-localized Startup program group
CSIDL_APPDATA | 26 | Application-specific data
CSIDL_BITBUCKET | 10 | Recycle bin virtual folder
CSIDL_CDBURN_AREA | 59 | Staging area
CSIDL_COMMON_ADMINTOOLS | 47 | Admin tools for all users
CSIDL_COMMON_ALTSTARTUP | 30 | Non-localized startup group for all users
CSIDL_COMMON_APPDATA | 35 | Application data for all users
CSIDL_COMMON_DESKTOPDIRECTORY | 25 | Desktop files and folders for all users
CSIDL_COMMON_DOCUMENTS | 46 | Docs common to all users
CSIDL_COMMON_FAVORITES | 31 | Favorite items for all users
CSIDL_COMMON_MUSIC | 53 | Music files, all users
CSIDL_COMMON_PICTURES | 54 | Image files for all users
CSIDL_COMMON_PROGRAMS | 23 | Common program groups on start menu
CSIDL_COMMON_STARTMENU | 22 | Start menu items for all users
CSIDL_COMMON_STARTUP | 24 | Startup folder for all users
CSIDL_COMMON_TEMPLATES | 45 | Templates available to all users
CSIDL_COMMON_VIDEO | 55 | Video files, all users
CSIDL_CONTROLS | 3 | Control Panel virtual folder
CSIDL_COOKIES | 33 | Internet cookies
CSIDL_DESKTOP | 0 | Windows desktop virtual folder
CSIDL_DESKTOPDIRECTORY | 16 | Desktop
CSIDL_DRIVES | 17 | My Computer virtual folder
CSIDL_FAVORITES | 6 | User's favorites
CSIDL_FONTS | 20 | Fonts virtual folder
CSIDL_HISTORY | 34 | Internet history
CSIDL_INTERNET | 1 | Internet virtual folder
CSIDL_INTERNET_CACHE | 32 | Temporary internet files
CSIDL_LOCAL_APPDATA | 28 | Local (non-roaming) applications
CSIDL_MYDOCUMENTS | 12 | My Documents virtual folder
CSIDL_MYMUSIC | 13 | Music files
CSIDL_MYPICTURES | 39 | Image files
CSIDL_MYVIDEO | 14 | Video files
CSIDL_NETHOOD | 19 | Link objects
CSIDL_NETWORK | 18 | Network Neighborhood virtual folder
CSIDL_PERSONAL | 5 | My Documents desktop item virtual folder
CSIDL_PRINTERS | 4 | Installed printers virtual folder
CSIDL_PRINTHOOD | 27 | Printers virtual folder
CSIDL_PROFILE | 40 | Profile
CSIDL_PROFILES | 62 | Profile folders
CSIDL_PROGRAM_FILES | 38 | Program files
CSIDL_PROGRAM_FILES_COMMON | 43 | Shared components
CSIDL_PROGRAMS | 2 | User's program groups
CSIDL_RECENT | 8 | Shortcuts to recently used docs
CSIDL_SENDTO | 9 | Send To menu items
CSIDL_STARTMENU | 11 | Start menu items
CSIDL_STARTUP | 7 | User's Startup program group
CSIDL_SYSTEM | 37 | Windows system folder
CSIDL_TEMPLATES | 21 | Document templates
CSIDL_WINDOWS | 36 | SYSROOT


EXLIB

The A-Shell Example Library ("EXLIB") is a collection of mostly small standalone example programs designed to illustrate or test particular A-Shell features. They are organized into PPNs in the [908,*] range, with each PPN focusing on a particular area. The library is maintained in an online repository where you can access and view individual files or download the entire set. Prior to 2015, the examples were included not in their own EXLIB library but in the more general SOSLIB.The A-Shell Example Library ("EXLIB") is a collection of mostly small standalone example programs designed to illustrate or test particular A-Shell features. They are organized into PPNs in the [908,*] range, with each PPN focusing on a particular area. The library is maintained in an online repository where you can access and view individual files or download the entire set. Prior to 2015, the examples were included not in their own EXLIB library but in the more general SOSLIB.The A-Shell Example Library ("EXLIB") is a collection of mostly small standalone example programs designed to illustrate or test particular A-Shell features. They are organized into PPNs in the [908,*] range, with each PPN focusing on a particular area. The library is maintained in an online repository where you can access and view individual files or download the entire set.


EXLIB

The A-Shell Example Library ("EXLIB") is a collection of mostly small standalone example programs designed to illustrate or test particular A-Shell features. They are organized into PPNs in the [908,*] range, with each PPN focusing on a particular area. The library is maintained in an online repository where you can access and view individual files or download the entire set.


GDI Printing Directive Equivalent

There are several operators that function both as GDI printing directives and as printer init file commands, although the syntax may be different between the two uses. These operators can be embedded in the print file, or included in the init file, and the effects will be the same. When included in the print file, the command must appear within the top nine lines, and before any lines that generate printed output; any such command (except BIN) farther into the file will either be ignored or will produce undefined effects.


Hex-Decimal Values

Hex | Decimal | Hex | Decimal
0 | 0 | 10000 | 65536
1 | 1 | 20000 | 131072
2 | 2 | 40000 | 262144
4 | 4 | 80000 | 524288
8 | 8 | 100000 | 1048576
10 | 16 | 200000 | 2097152
20 | 32 | 400000 | 4194304
40 | 64 | 800000 | 8388608
80 | 128 | 1000000 | 16777216
100 | 256 | 2000000 | 33554432
200 | 512 | 4000000 | 67108864
400 | 1024 | 8000000 | 134217728
800 | 2048 | 10000000 | 268435456
1000 | 4096 | 20000000 | 536870912
2000 | 8192 | 40000000 | 1073741824
4000 | 16384 | 80000000 | 2147483648
8000 | 32768 | 100000000 | 4294967296


MX_GDICALC Status Codes

Status | Description
-1 | Unable to open printer context (bad printer name or failure to first open printer)
-2 | Bad map mode
-3 | Error setting font
-4 | Insufficient number of parameters passed
-5 | Illegal opcode
-6 | File transfer error (server was unable to transfer file to the ATE client for MXGDI_CALCRECTX processing)
-7 | File spec error - invalid or not present (MXGDI_CALCRECTX)
-8 | This error means that you have specified a rectangle that has zero or negative space. (This error previously displayed a cryptic "Printing Area Too Small" message.)
-15 | ATE failure to respond
others | Negative of the system error number


Natural Sort

The "natural" sort is based on an algorithm by Martin Pool which has spread to various other languages and attempts to mimic how humans would naturally sort strings such as "1 Main St", "10 Main St", "2 Main St". The "natural" thing would be to sort "10 Main St" after "2 Main St", and treat 2 contiguous spaces as one, minimize importance of punctuation, etc., instead of just using the raw byte collating sequence.

The A-Shell implementation deviates slightly from the original version by Martin Pool in that it supports the LDF collating sequence, if available, and doesn't require trailing nulls on the strings.

Natural sort keys should always be of type S (String).


Num

Numeric parameters (documented as "num" or "numeric") may be of any type supporting numeric values, which includes F (floating point), B (binary), I (signed integer), and even S (string). Note that if the parameter contains or may contain a negative value, you should use either F or I. The size of the variable typically just needs to be large enough to handle the required values. If the parameter absolutely must be floating point or a particular size, it will be documented as such.


Num

Numeric parameters (documented as "num" or "numeric") may be of any type supporting numeric values, which includes F (floating point), B (binary), I (signed integer), and even S (string). Note that if the parameter contains or may contain a negative value, you should use either F or I. The size of the variable typically just needs to be large enough to handle the required values. If the parameter absolutely must be floating point or a particular size, it will be documented as such.Numeric parameters (documented as "num" or "numeric") may be of any type supporting numeric values, which includes F (floating point), B (binary), I (signed integer), and even S (string). Note that if the parameter contains or may contain a negative value, you should use either F or I. The size of the variable typically just needs to be large enough to handle the required values. If the parameter absolutely must be floating point or a particular size, it will be documented as such.Numeric parameters (documented as "num" or "numeric") may be of any type supporting numeric values, which includes F (floating point), B (binary), I (signed integer), and even S (string). Note that if the parameter contains or may contain a negative value, you should use either F or I. The size of the variable typically just needs to be large enough to handle the required values. If the parameter absolutely must be floating point or a particular size, it will be documented as such.


Printer Init File Equivalent

There are several operators that function both as GDI printing directives and as printer init file commands, although the syntax may be different between the two uses. These operators can be embedded in the print file, or included in the init file, and the effects will be the same. When included in the print file, the command must appear within the top nine lines, and before any lines that generate printed output; any such command (except BIN) farther into the file will either be ignored or will produce undefined effects,


Pseudo Column Zero

A special XTREE column which has no display attributes but is only used as a convenience for defining options which are not column-specific. See cpos and cwidth.


Raw

Raw parameters, sometimes referred to as unformatted, consist of a sequence of bytes that do not adhere any particular data representation standard. Typically a variable of type X is used to pass such raw parameters, although in the case of overlays, the data type specified by the caller may not necessarily be X; it may also be a MAP1 variable with MAP2 variables beneath it. Because there is no prearranged standard to identify the end of the data, the length must specified, either explicitly (in the routine documentation and/or external parameter), or implicitly (by the size of the variable containing the raw parameter).Raw parameters, sometimes referred to as unformatted, consist of a sequence of bytes that do not adhere any particular data representation standard. Typically a variable of type X is used to pass such raw parameters, although in the case of overlays, the data type specified by the caller may not necessarily be X; it may also be a MAP1 variable with MAP2 variables beneath it. Because there is no prearranged standard to identify the end of the data, the length must specified, either explicitly (in the routine documentation and/or external parameter), or implicitly (by the size of the variable containing the raw parameter).Raw parameters, sometimes referred to as unformatted, consist of a sequence of bytes that do not adhere any particular data representation standard. Typically a variable of type X is used to pass such raw parameters, although in the case of overlays, the data type specified by the caller may not necessarily be X; it may also be a MAP1 variable with MAP2 variables beneath it. Because there is no prearranged standard to identify the end of the data, the length must specified, either explicitly (in the routine documentation and/or external parameter), or implicitly (by the size of the variable containing the raw parameter).


Raw

Raw parameters, sometimes referred to as unformatted, consist of a sequence of bytes that do not adhere any particular data representation standard. Typically a variable of type X is used to pass such raw parameters, although in the case of overlays, the data type specified by the caller may not necessarily be X; it may also be a MAP1 variable with MAP2 variables beneath it. Because there is no prearranged standard to identify the end of the data, the length must specified, either explicitly (in the routine documentation and/or external parameter), or implicitly (by the size of the variable containing the raw parameter).


RGB color index

An alphabetic character, A-Z and a-z (i.e., both upper and lower case, 52 total) used to index an XTREE RGB color definition. The index is defined via Advanced Coldef Options RGBfg and RGBgb, and referenced by cformat codes B, b, C and c. A blank (" ") or "=" may be used to to specify the default color. Blank may be overridden by another explicit color specification affecting the tree component, such as a row or column color, while "=" will always use the XTREE default color for that component.


SBX

Subroutines with file name extensions of "SBX" were written in BASIC and are dynamically loaded from disk as needed, as opposed to being contained in the A-Shell executable file like the SBR routines. The source code for these routines is included with the standard A-Shell release. See SBX Subroutines for information on writing your own.


SOSLIB

The A-Shell Shared Open Source Library ("SOSLIB") is a collection of common definitions and useful routines. It includes the A-Shell core collection of map, structure, and symbol definitions (ASHINC:, [907,16]), common utility functions (SOSFUNC:, [907,10]), and many useful SBX modules. The library is maintained in an online repository where you can obtain details and downloads. All A-Shell developers are encouraged to visit the repository frequently to browse available routines, obtain the latest updates, and contribute to A-Shell's improvement via bug reports, suggestions, etc. In 2015, the examples from SOSLIB were segregated into their own library, the EXLIB.The A-Shell Shared Open Source Library ("SOSLIB") is a collection of common definitions and useful routines. It includes the A-Shell core collection of map, structure, and symbol definitions (ASHINC:, [907,16]), common utility functions (SOSFUNC:, [907,10]), and many useful SBX modules. The library is maintained in an online repository where you can obtain details and downloads. All A-Shell developers are encouraged to visit the repository frequently to browse available routines, obtain the latest updates, and contribute to A-Shell's improvement via bug reports, suggestions, etc. In 2015, the examples from SOSLIB were segregated into their own library, the EXLIB.The A-Shell Shared Open Source Library ("SOSLIB") is a collection of common definitions and useful routines. It includes the A-Shell core collection of map, structure, and symbol definitions (ASHINC:, [907,16]), common utility functions (SOSFUNC:, [907,10]), and many useful SBX modules. The library is maintained in an online repository where you can obtain details and downloads. All A-Shell developers are encouraged to visit the repository frequently to browse available routines, obtain the latest updates, and contribute to A-Shell's improvement via bug reports, suggestions, etc. Note that in 2015, the examples from SOSLIB were segregated into their own library, the "EXLIB."


SOSLIB

The A-Shell Shared Open Source Library ("SOSLIB") is a collection of common definitions and useful routines. It includes the A-Shell core collection of map, structure, and symbol definitions (ASHINC:, [907,16]), common utility functions (SOSFUNC:, [907,10]), and many useful SBX modules. The library is maintained in an online repository where you can obtain details and downloads. All A-Shell developers are encouraged to visit the repository frequently to browse available routines, obtain the latest updates, and contribute to A-Shell's improvement via bug reports, suggestions, etc. Note that in 2015, the examples from SOSLIB were segregated into their own library, the "EXLIB."


String

String parameters may be of a required fixed length (documented like "Str,4" or "S,4"), a recommended minimum length (like "Str,30+"), or an unspecified length ("Str" or "String" without a number). In the latter case, the determination of an appropriate size—i.e., sufficient to accommodate the expected data—is left to the programmer's judgment. If you specify a string variable that is shorter than the number of characters that would otherwise be returned into that variable, the data will be truncated to fit the variable. If the string variable is longer than needed, the data will be null terminated.

When passing variable length string parameters to embedded SBR routines, as a general rule you should allow space for an explicit trailing null byte. This is not an issue for BASIC functions, procedures and SBX routines, which are able to recognize the physical end of the string, but may be an issue for embedded SBR routines that link to libraries written in C, where strings are typically assumed to have trailing null bytes.

In rare cases, which are always explicitly noted, subroutines may be able to auto-expand dynamic (S,0) output string parameters. But unless otherwise noted, you should assume not, and pre-initialize any such output string parameters to the expected maximum size.


String

String parameters may be of a required fixed length (documented like "Str,4" or "S,4"), a recommended minimum length (like "Str,30+"), or an unspecified length ("Str" or "String" without a number). In the latter case, the determination of an appropriate size—i.e., sufficient to accommodate the expected data—is left to the programmer's judgment. If you specify a string variable that is shorter than the number of characters that would otherwise be returned into that variable, the data will be truncated to fit the variable. If the string variable is longer than needed, the data will be null terminated.

When passing variable length string parameters to embedded SBR routines, as a general rule you should allow space for an explicit trailing null byte. This is not an issue for BASIC functions, procedures and SBX routines, which are able to recognize the physical end of the string, but may be an issue for embedded SBR routines that link to libraries written in C, where strings are typically assumed to have trailing null bytes.

In rare cases, which are always explicitly noted, subroutines may be able to auto-expand dynamic (S,0) output string parameters. But unless otherwise noted, you should assume not, and pre-initialize any such output string parameters to the expected maximum size.String parameters may be of a required fixed length (documented like "Str,4" or "S,4"), a recommended minimum length (like "Str,30+"), or an unspecified length ("Str" or "String" without a number). In the latter case, the determination of an appropriate size—i.e., sufficient to accommodate the expected data—is left to the programmer's judgment. If you specify a string variable that is shorter than the number of characters that would otherwise be returned into that variable, the data will be truncated to fit the variable. If the string variable is longer than needed, the data will be null terminated.

When passing variable length string parameters to embedded SBR routines, as a general rule you should allow space for an explicit trailing null byte. This is not an issue for BASIC functions, procedures and SBX routines, which are able to recognize the physical end of the string, but may be an issue for embedded SBR routines that link to libraries written in C, where strings are typically assumed to have trailing null bytes.

In rare cases, which are always explicitly noted, subroutines may be able to auto-expand dynamic (S,0) output string parameters. But unless otherwise noted, you should assume not, and pre-initialize any such output string parameters to the expected maximum size.String parameters may be of a required fixed length (documented like "Str,4" or "S,4"), a recommended minimum length (like "Str,30+"), or an unspecified length ("Str" or "String" without a number). In the latter case, the determination of an appropriate size—i.e., sufficient to accommodate the expected data—is left to the programmer's judgment. If you specify a string variable that is shorter than the number of characters that would otherwise be returned into that variable, the data will be truncated to fit the variable. If the string variable is longer than needed, the data will be null terminated.

When passing variable length string parameters to embedded SBR routines, as a general rule you should allow space for an explicit trailing null byte. This is not an issue for BASIC functions, procedures and SBX routines, which are able to recognize the physical end of the string, but may be an issue for embedded SBR routines that link to libraries written in C, where strings are typically assumed to have trailing null bytes.

In rare cases, which are always explicitly noted, subroutines may be able to auto-expand dynamic (S,0) output string parameters. But unless otherwise noted, you should assume not, and pre-initialize any such output string parameters to the expected maximum size.


xtree.map

This file, included with A-Shell, defines the XTRCTL parameter layout for XTREE.SBR, and should be included in any program using XTREE.SBR. It does not contain the XTREE-related symbols (e.g. XTF_xxx and XTROP_xxx) which are contained in ashell.def.