Application Interface to ANSI Escape Sequences

Next: Introduction [Contents][Index]

# AnsiCmd Class Link Library

Copyright © 2022-2026 Mahlon R. Smith, The Software Samurai This manual describes version 0.0.07 of the AnsiCmd library. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".

`` The AnsiCmd library provides a simple, organized mechanism
`` for controlling the setup of many terminal window functions
`` and display options using ANSI escape sequences and basic
`` terminal configuration utilities.

## Table of Contents

## Introduction

#### What is the AnsiCmd link library?

The `AnsiCmd` class builds to a small, special purpose link library which may be used to configure color attributes for the terminal window foreground and background; text attributes such as bold, italic, and underlined; as well as cursor positioning and text erasure using ANSI escape sequences and ASCII control codes.

In addition, the `AnsiCmd` library can configure the input stream, `"stdin"` for operations such as input echo options, non-blocking read and capture of system signals such as `"break"` (CTRL+C), `"suspend"` (CTRL+Z), and `"quit"` (CTRL+4).
See Terminal Configuration.

`AnsiCmd` captures all (or nearly all) keycodes which are passed from the system as escape sequences, and converts these sequences to ordinary Unicode codepoints. See Soft Echo Options for examples of this conversion.

#### The EarthPoints Test Program

The `AnsiCmd` class library is bundled with a test application, `EarthPoints`, (`epts`), which exercises the full functionality of the library. `EarthPoints` was born as an experiment in how global-positioning systems calcuate distances between points on the planet. It began as a pure command-line application to test the math behind the distance calculations; however, your author is a simple creature, and he was easily distracted by the possibility of using ANSI escape sequences to add color to the output. (Geeks-R-Us :-)

This distraction quickly became a project in itself, and the full list of `ECMA-48, ANSI X3.64` escape sequences is now supported by the `AnsiCmd` library.

#### Other Test Programs

Also included are additional test programs in various states of completion.
These applications demonstrate specific approaches to design of applications based on the `AnsiCmd` library.
See CsvView Demo App, and AcEdit Demo App for more information.

#### The gString Class

The `AnsiCmd` library and the associated test programs make extensive use of the author’s `gString` class. The `gString` class encapsulated most of the smelly (but efficient) C-language string manipulation functions such as `sprintf, scanf` and so on.
Please see gString Text Tool for more information.

#### The WaylandCB Class

Access to the system clipboard is enabled through the `WaylandCB` class. This class in under a conditional-compile directive.
Please see Build Options for additional information on integration of clipboard access into the `AnsiCmd` library.
For a discussion of how system clipboard access is implemented in the library, please see AnsiCmd Clipboard Access.

#### The TFMan Class

Management of temporary files for the `AnsiCmd` library and the demo applications included with the package are handled through the `TFMan` (Temporary File Management) class.
Please see TFMan Class and the TFMTest Demo App for an introduction to the use of temporary files in a Linux application.

── ── ── ── ── ── ── ── ── ── ── ── ── ──

`ANSI` - American National Standards Institute
(ECMA-48, ISO/IEC-6429, FIPS 86, ANSI X3.64, JIS X 0211)
https://en.wikipedia.org/wiki/American_National_Standards_Institute https://www.ecma-international.org/publications-and-standards/standards/ecma-48/

`ASCII` - American Standard Code for Information Exchange.
(ISO-IR-006, ANSI_X3.4-1968, ANSI_X3.4-1986, ISO_646.irv:1991, ISO646-US, IBM367, cp367)
https://en.wikipedia.org/wiki/ASCII

## Invoking

There are three (3) groups of command-line options for invoking the application (invocation menu below). Each option group is independent of the others (with some exceptions). The `'help'` and `'version'` options override all other specified options. When one of the testing options is specified, it overrides any request for application-level (GPS) data.

1. Terminal Configuration Options:
   These options configure the terminal environment for the application.
   Configuration options include color attributes, I/O stream options, “locale”, signal processing, cursor shape and more. All are optional, and if not specified, the default setting for that option will be used.
   Please See Invoking - Terminal Setup.
2. AnsiCmd-class Testing Options:
   These options specify a test of specific functionality within the AnsiCmd library. Because the `EarthPoints` application is primarily a test and demonstration application, the array of available tests is extensive.
   Each test establishes its own terminal environment according to the needs of the specific test, and thus may override the corresponding terminal setup option(s).
   All tests are within conditional compilation blocks (Build Options), so all test code may be disabled without loss of application functionality.
   Please see Invoking - AnsiCmd Tests.
3. EarthPoints Application Options:
   These options provide data for the top-level application functionality; specifically, global-positioning coordinates (latitude/longitude), and related data for calculating the distance between points on the globe.

   To interactively invoke the application’s help menu, at the command-line type:
   `epts --help`
   `epts -h`
   `` or redirect the help menu through the “less” utility:
   `epts --helpless`
   `epts -hl`

   Please See Invoking - EarthPoints for more information.

Invocation Options

### Invoking - Terminal Setup

When invoking the EarthPoint application (epts), terminal setup options are specified through the “`--term`” command-line option:
`epts --term=SETUP_OPTIONS`

Options may be specified in any order and in any combination.
Multiple options may be concatenated, seperated by commas (`','`):
If the argument string contains whitespace, enclose the entire argument string in single- or double-quotes.

# Set stream_Width==wide, Color==red/blue, Locale==French(Canada) epts --term=W:w,C:rb,L:fr_CA.utf8 # Set Locale==from_terminal_environment, Panic_button==user_query, cursor_Style==blinking_underline epts --term="L:e, P:u, S:ub" # Set input_Buffering==unbuffered_no_echo, Ansi_compliant==no, Panic_button==ignore_with_alert, Color==blue/default epts --term='B:ux, A:n, P:ia, C:b'

#### Summary of Options

> OPTION | DESCRIPTION
> --- | ---
> W option | stream Width
> C option | Color attributes
> A option | Ansi compliant
> B option | input Buffering
> L option | Locale name
> P option | Panic button
> Q option | Quit signal
> Z option | suspend ctrl+Z
> S option | cursor Style

–W Stream Width.

The term “Stream Width” refers to the character width for input and output streams for the application. Typically, the character width is either 8-bits (char) or 32-bits (wchar_t).

For console applications, the I/O stream width is established either directly by declaring the width or by locking in the character width with the first data read from, or written to the the I/O streams. Once locked in, the stream width cannot be changed without closing and re-opening the stream(s), which is not as straightforward as it sounds, and is therefore discouraged.

`w -` Use the wide (wcin/wcout) input/output streams. This is the default, and is strongly recommended.
`n -` Use the legacy narrow (cin/cout) input/output streams. The narrow I/O streams are not recommended for modern applications,
`` but may be used for testing the interface.

Example:
`epts --term=W:w` # set Wide stream width

To set this option directly, call the AnsiCmd method: acSetStreamWidth.

–C Color Attributes.

Specify the text foreground, and optionally the background color attribute(s). The foreground color argument is required, and the background argument is optional, and if not specified, the terminal default background will be used.

Within a console application, it is often useful, to use contrasting colors to draw the user’s attention to important information. For applications which include the AnsiCmd library, these color attributes may be specified as a command line option.

The `-C` option is used to specify one of the basic eight(8) colors (or default) for foreground and background.

k : blacK b : Blue r : Red m : Magenta g : Green c : Cyan n : browN y : greY d : Default

Examples:
`epts --term=C:r` # set Red foreground with Default background
`epts --term=C:cb` # set Cyan foreground with Blue background
`epts --term=C:dg` # set Default foreground with Green background

To set this option directly, call the AnsiCmd method: acSetFgBg.

–A Ansi Compliance.

The most popular terminal emulator software, Gnometerm, Konsole and XTerm all support the core set of `ANSI` escape sequences. However, some terminal software may not understand some of the basic commands such as those which reset (disable) certain individual settings.

For terminals with this limited support, the AnsiCmd library functions can substitute the full reset command for the unsupported individual reset commands. While the full reset is slower and less convenient for the application programmer, it provides a way to produce a reliable application interface.

For example, the standard way to reset the Bold attribute is with the `aesBOLD_OFF` sequence:
`acSetMod ( aesBOLD_OFF );`
If this command or similar commands is not supported by the terminal, then the global attribute reset can be called:
`acSetMod ( aesRESET );`
This substitution is done automatically if the internal non-compliance flag is set.

The level of `ANSI` compliance is specified by:
`y -` Yes, the host terminal supports the common `ANSI` escape sequences.
`` This is the default, and should be correct in most cases.
`n -` No, the terminal is unable to handle some of the necessary sequences.
`` Use the reliable reset when disabling an attribute.

To set this option directly, call the AnsiCmd method: acFullReset.

–B Input Buffering.

Specify the buffering options for the input stream (stdin).

By default, keyboard input at the terminal prompt is stored in the stream buffer until the user presses the Enter key; however, application control of the keyboard input stream is, in the author’s view, critical to the success of the application.
(Our opinions are plentiful and provided free-of-charge.)

If your applications would benefit from having full control of keyboard input, then the `-B` option is used to specify the way keyboard input is captured, filtered and presented to the application.

b : Buffered input from stdin is enabled (default). Keycodes are sent to the application when the Enter key is pressed. The terminal automatically echoes printing characters to the display, and processes control codes and other non-printing keycodes using whatever Voodoo rituals the terminal software developers follow. u : Unbuffered input from stdin. Keycodes are available to the application as soon as the key is pressed. Echo of printing characters to the display is specified as a sub-option. Echo sub-options: x : Echo of data from stdin is disabled. This is the default and is assumed if no sub-option is specified. s : Soft Echo. This option automatically echoes printing characters to the display, but captures the so-called "special" (non-printing) keycodes and processes them according to the soft-echo sub-option. a : All "special" keycodes are captured, processed and passed on to the application. This is the default soft-echo option. b : Basic "special" keycode group. This includes the cursor positioning and edit-key groups, but not the text-selection and clipboard-access keycodes. c : Cursor-positioning keycodes are passed to the application. The edit keycodes are discarded. e : Edit keycodes (Backspace, Delete, Insert and Alt+Enter) plus Tab and Shift+Tab are passed to the application. Cursor-positioning keycodes are discarded. (useful primarily for debugging) d : Disable (discard) all "special" keycodes. See Soft Echo Options for more information. Examples: epts `--`term=B:b # Buffering is enabled. epts `--`term=B:ux # Buffering is disabled with echo disabled. epts `--`term=B:usa # Buffering is disabled, echo enabled, and all special keys enabled. epts `--`term=B:usc # Buffering is disabled, echo enabled, and cursor-positioning special keys enabled. epts `--`term=B:usd # Buffering is disabled, echo enabled, and all special keys discarded.

To set this option directly, call the AnsiCmd method: acBufferedInput.

–L Locale Name.

Specify the “locale” to be used within the application.

A locale is the set of rules used to interpret the way text and numeric data are processed and presented. A few examples of locale-dependent data are, currency values, telephone numbers, timestamps and measurements.

Two command-line options are available:

e - Environment: Activate the locale specified in the terminal environment. This is the default and is almost always the the right choice. locale_name - specify a valid filename for the locale to be used. Examples: epts `--`term=L:e # take locale from environment epts `--`term=L:zh_CN.utf8 # specify Zhongwen (China) locale

It is very likely that the terminal environment in which your console application runs specifies the locale via one or more environment variables. At the command line type:
`echo $LANG`
To list the types of formatting handled by the current locale, at the command line type:
`locale`
To list the UTF-8 compliant locales supported by your system, at the command line type:
`locale -a | grep -i 'UTF'`
This should yield a list of filenames such as
`en_US.UTF-8, zh_CN.utf8, es_AR.utf8`

Technical Note: Except for Windoze(tm), the civilized world uses UTF-8 character encoding exclusively. Be sure that any locale specified for use in your application is based on UTF-8 encoding.

Technical Note: If a console application does not explicitly specify a locale, the so-called “C-locale” is used. This is not actually a locale at all but the complete lack of a locale—resulting in a complete lack of coherent data formatting.

–P Panic Button.

The Break Signal, otherwise know as the Panic Button or `Control+C` is the primary method of killing a console application which has locked up or has gone off into the weeds.

By default, the terminal receives the break signal and immediately kills the application, leaving your data in an indeterminate state.

This is fine if you don’t care about your data, but if you actually don’t care about your data, please step away from the keyboard — and pursue a career in marketing. Otherwise, your application may benefit one of these options.

i[a] - Ignore the break signal, that is capture the signal and discard it. Optionally produce an audible alert. e - Exit the application on receipt of the break signal. The shutdown is performed in an orderly way, returning all resources to the system before returning control to the terminal shell. u - User interaction is required. The signal handler prompts the user whether to exit the application or to discard the break signal and continue the application. c - Capture the signal and convert it to an ordinary keycode (wcsCTL_C) which is commonly used by applications as the “copy” command. t - The terminal is allowed to retain control of the break signal. If the user presses the CTRL+C key combination, the application will be terminated immediately, leaving the terminal in an indeterminate state. Although this is the default, it is not recommended. Examples: epts `--`term=P:i # Ignore break signal epts `--`term=P:ia # Ignore break signal and sound an alert epts `--`term=P:e # Exit the application epts `--`term=P:u # User prompt on receipt of break signal epts `--`term=P:c # Copy command conversion epts `--`term=P:t # Terminal handler (default)

Please see Capturing the Break Signal for additional information.

To set this option directly, call the AnsiCmd method: acCaptureBreakSignal.

–Q Quit Signal.

The Quit Signal (or Kill signal) is similar to the Panic Button described above, except that in addition to terminating the application, it also generates a core dump.

A core dump is a file which contains a description of the the application state when it was terminated. This can include the register values, the call stack (addresses and parameters), a table of RAM contents and other information. This can be a large file, and it is recommended that it not be generated unless you actually need it.

The Quit Signal is captured by default during configuration of the AnsiCmd class and its derived classes. When the Quit signal is received, the application is shut down in an orderly manner. Use the ‘Q option’ to disable this functionality.
`epts --term=Q:n`

To set/reset this option directly, call the AnsiCmd method: acCaptureQuitSignal.

–Z Suspend Signal.

The “`Suspend`” signal is generated by the `Ctrl+Z` key combination. This signal suspends the currently-active process (places it into hibernation). The process will not be able to respond to any command other than a command to resume operation. Refer to documentaiton for the ‘fg’ system utility for information on restoring the hibernating process.

While the `"suspend"` functionality is a valuable tool in some contexts, it is merely confusing to the average user when the running application simply freezes and cannot be restarted.

For this reason, the `"suspend"` signal (`SIGTSTP`) is captured by default and is converted to an ordinary keycode, wcsCTL_Z.
The `Ctrl+Z` key combination is often used by applications (LibreOffice, jEdit, etc.) to “undo” a previous action.
`epts --term=Z:n`
`epts --term=Z:y` (default)

–S Cursor Style.

Specify the shape and animation (blinking or steady) of the visible cursor.

d - Default. Use the terminal's default cursor shape and animation. For most environments, a full-cell, blinking block is the default. b[b|s] - Block. The cursor shape is a rectangular block that fills one entire character cell. Sub-options: 'b' - blinking (default) 's' - steady (non-blinking) u[b|s] - Underline. The cursor shape is a thin horizontal bar at the bottom of the character cell. This resembles an underline or the underscore character '_' Sub-options: 'b' - blinking 's' - steady v[b|s] - Vertical bar. The cursor shape is a thin vertical bar at the left edge of the character cell. This is similar, but not identical to the vertical bar character: '|' on the keyboard. Sub-options: 'b' - blinking 's' - steady Examples: epts `--`term=S:u # Underline (with blinking default) epts `--`term=S:vb # Vertical bar, blinking epts `--`term=S:vs # Vertical bar, steady (non-blinking)

To set this option directly, call the AnsiCmd method: acSetCursorStyle. Note that this method may also be used to set cursor as invisible.

Technical Note:

The blinking-cursor options are impacted by the terminal software’s blink timeout value. For Gnome, the default timeout is ten seconds, after which the cursor will stop blinking and become steady state. To adjust this timeout value under Gnome, use either the `'dconf'` editor or the `'gsettings'` utility.

Get the current timeout value:
`gsettings get org.gnome.desktop.interface cursor-blink-timeout`
Get the range of valid values for this option:
`gsettings range org.gnome.desktop.interface cursor-blink-timeout`
Set a new timeout value in seconds:
`gsettings set org.gnome.desktop.interface cursor-blink-timeout 25`

Other desktop schemes will have a similar mechanism for adjusting the cursor blink timeout value.

### Invoking - AnsiCmd Tests

Tests for the AnsiCmd library are specified as arguments to the `"`--test`"` command-line option.
`epts --test=TEST_OPTION`

The specific test within a group of related tests is specified by from one to four characters as detailed in this chapter. The first character indicates the test group. For instance, the letter `'C'` designates the group of color-attribute tests. If a test group is invoked without indicating a specific test, then the menu of available tests in that group will be displayed and the application will exit.
`epts --test=C` will display the color test menu:
`Color Attribute Testing Options:`
`-----------------------------------------------`
`'f' Four-bit Fgnd/Bkgnd color attributes.`
`'b' Background color attribute options.`
`'t' Table lookup, 8-bit color attributes.`
`'r' R/G/B color-attribute matrix (6x6x6).`
`'g' Greyscale color attributes.`
`'a' Aixterm Fg/Bg extensions (non-standard).`
`'d' Decode tracking data for attribute mods.`
`'s' Swap acaExpand foreground/background.`

Similarly, if a test group and a test are specified, but the test requires an argument or arguments, then a menu of available arguments for that test will be displayed and the application will exit.
`epts --test=Cr` will display the RGB color test arguments:
`RGB Test Options:`
`---------------------------------------------------`
`'r' Red : Display full range of red colors.`
`'g' Green: Display full range of green colors.`
`'b' Blue : Display full range of blue colors.`
`'y' greY : Display full range of greyscale colors.`
`'w' Web : Display "web-safe" colors.`

A few test require two(2) arguments, for example:
`epts --test=Tec` Terminal group, Echo test, Cursor keys

If a test and its argument(s) are fully specified, then optionally, the next character indicates the text color attribute to be used for outputting the results of the test. The available color attributes are:
`'k' blacK 'r' Red`
`'g' Green 'n' browN`
`'b' Blue 'm' Magenta`
`'c' Cyan 'y' greY`
`` If not specified, the terminal default color is used.
`` Note: The color-attribute tests will ignore this argument.
Examples:
`epts --test=Eb` — Perform `'E'`rasure test with `'b'`lue text.
`epts --test=Ac` — Perform `'A'`SCII code test with `'c'`yan text.
`epts --test=Tig` — Perform `'T'`erminal `'i'`nput test with `'g'`reen text.
`epts --test=Wddb` — Test `'W'`indow `'d'`ialog, sub-test `'d'` with `'b'`lue text.

#### Summary of Options

> OPTION | DESCRIPTION
> --- | ---
> test C | Color tests
> test P | Positioning tests
> test E | Erasure tests
> test A | Ascii control code tests
> test F | Font switch test
> test `I` | Ideograph test
> test T | Terminal setup tests
> test W | Window tests
> test D | Dialog tests
> test S | Sandbox

Options for testing the functionality of the AnsiCmd-class library.

For options which require arguments, the option must be immediately followed by the EQUAL sign (’=’) which must be immediately followed by its argument. If the argument string contains space characters, enclose it in quotation marks.

Please see Development and Testing or study the `AnsiCmdTest.cpp` source file for more information about how the individual tests are constructed.

–C Color Attributes.

The majority of escape sequences definined in the `ECMA-48 (ANSI)` standard are related to setting foreground and background color attributes. These definitions reflect the evolution of color support on hardware terminals and within terminal emulators from 3-bit (8 colors) to 4-bit (16 colors) through today’s so-called true-color (usually 24-bit) systems.

Each of the color palettes supported by the standard is exercised by one or more of the color-attribute tests listed here.

f : Four-bit color attribute tests (16-color palette) b : Background option tests t : Table lookup tests (8-bit color) g : Greyscale attribute tests a : Aixterm extensions r : Rgb, red/green/blue tests (24-bit color) r : Red spectrum g : Green spectrum b : Blue spectrum y : greYscale spectrum w : Web-safe r/g/b colors d : Decoding and encoding attribute tracking data a : API-level tests (default) b : Basic low-level ANSI escape tests s : Swap/build8Bit/buildRgb - acaExpand class utilities
–P Positioning Tests.

One group of the escape sequence defined by the standard provides various ways to set the cursor position. Some of these sequences set an “absolute” (terminal-relative) position. Others define a move relative to the current cursor position. All the supported variations are used during this test.

–E Erasure Tests.

In the early days of computing, terminals were extremely slow. For this reason, several innovative ways of erasing an area of the display were implemented to increase the speed of display updates. Some of these include erasing part of a line, a whole line, and either the top half or bottom half of the display. It is even possible to “erase” the data which has already been scrolled out of the window. (It was a whole thing....don’t ask :-)

–A ASCII Control Codes, Function Keys and ALT Key Combinations.

`ASCII` Control Codes

`ASCII` control codes (00h - 1Fh) were at one time an important part of systems which relied on serial communication (e.g. Teletype machines) for user interaction. On modern systems, most of these codes are unused by the terminal software and inconvenient for application use.
A few control codes however, are vital to operation. The most common are null(00h), bell(07h), backspace(08h), horizontal-tab(09h), linefeed i.e. newline(0Ah), vertical-tab(0Bh), form-feed(0Ch), carriage-return(0Dh), and of course Escape(1Bh). Others may be used in specialized circumstances.
These keycodes are presented to the application as non-printing byte values, OR as system signals, which if not properly handled can cause chaos within an application. A prime example of this would be the CTRL+C Break signal. For this reason, these byte values and signals are captured by the AnsiCmd library and converted to unique keycodes for use by the application. A common example of these would be `Copy/Cut/Paste` and similar keycodes.

Key Raw Name Of Common Combination Input Keycode Usage ─────────── ────────── ──────── ────────── CTRL+C break(03) wcsCTL_C Copy CTRL+X 18 wcsCTL_X Cut CTRL+V 16 wcsCTL_V Paste CTRL+Z susp(1A) wcsCTL_Z Undo CTRL+A 01 wcsCTL_A Select All CTRL+S pause(13) wcsCTL_S Save CtrL+Q resume(11) wcsCTL_Q Quit Ctrl+4 1C wcsCTL_4 Kill App Ctrl+[ 1B wcsESCAPE Escape

The keycodes in this group consist of the CONTROL key plus one of:
`a-z 4 5 6 7 [ \`
Note that when the CONTROL key is pressed, the system ignores the SHIFT key, so `CTRL+A` generates the same byte code as `CTRL+a`.

Function Key Combinations

The function keys `F01-F12` and their conditioned varients are often assigned to system-level tasks, but the terminal emulator may also be configured to pass these keycodes through to the application level.

All function keys generate escape sequences of between three(3) and seven(7) bytes. There are 48 (12 * 4) Function key combinations available:
`a) F01-12, b) Shift+F01-12, c) Ctrl+F01-12, and`
`d) Ctrl+Shift+F01-12`
Only the first three groups are supported by the AnsiCmd class; (36 sequential codepoints). When received, members of the fourth group, `Ctrl+Shift+Fnn` are silently converted to Ctrl+Fnn equivalents.

The `AnsiCmd` library captures these sequences and converts them to ordinary Unicode codepoints (keycodes) in the range: 0x002000 through 0x002023. Unicode assigns these keycodes to mathematical symbols which will seldom, if ever be generated directly by the keyboard. Some examples of the captured and converted sequences are shown in the table.

Key Escape Name Of Unicode Combination Sequence Keycode Codepoint ─────────── ───────────────── ──────── ───────── F02 1B 4F 51 wcsF02 0x002001 Shift+F02 1B 5B 31 3B 32 51 wcsSF02 0x00200D Ctrl+F02 1B 5B 31 3B 35 51 wcsCF02 0x002019

Please see the `AnsiCmdDef.hpp` source module for the full list.

ALT Key Combinations

The Left ALT key in combination with another key provides what are commonly known as the `GUI` keys. These key combinations are often used as shortcut keys within applications. For instance, `ALT+F, ALT+E and ALT+H` are often used to invoke an application’s “File”, “Edit”, and “Help” menus, respectively.
Because these keycodes are presented to the application as escape sequences, it is necessary to capture the escape sequences and convert them to unique keycodes for use by the the application. For the examples mentioned, these are:

Key Escape Name Of Combination Sequence Keycode ─────────── ──────── ──────── ALT+F 1B 46 wcsALT_F ALT+E 1B 45 wcsALT_E ALT+H 1B 48 wcsALT_H

The keycodes in this group consist of the Left ALT key plus one of:
`a-z ! " # $ % & ' ( ) * + , - . / : ;`
`< = > ? @ \ ] ^ _ { | }`
Note that to avoid clutter, the alphabetic character are processed as case insensitive: `ALT+A` yields the same keycode as `ALT+a`. Also, the numeric combinations `ALT+0` through `ALT+9` are assigned the same keycodes as their shifted equivalents (assumes U.S. English keyboard layout).
`! @ # $ % ^ & * ( )`
`1 2 3 4 5 6 7 8 9 0`

Other Keycodes

The “Special Keys” group of keycodes are also reported by this test.

Please see the `AnsiCmdDef.hpp` source file for a full list of the assigned keycode names. (or run this test)

–F Font Selection Tests.

A “font” is a set of glyphs (visible pictures) which are used to represent the “codepoints” of a character set. The `ECMA-48 (ANSI)` standard defines a method for selecting any of ten(10) fonts to be used for display text.

The "Primary Font" is specified in the aeSeq enumerated type as:
`aesPRIMARY_FONT (decimal 10)`

The "Alternate Fonts" are specified by the aeSeq value of:
`aesALTERNATE_FONT`
with a numeric argument between 1 and 9 (inclusive). These are translated to `ANSI` command codes 11 through 19, respectively.
Please see acSetFont for more information.

Testing thusfar indicates that setting alternate fonts is not supported by the terminal emulators used during development. The font is set in the terminal’s Preferences/Settings and appears to be unavailable to console applications; however, this tests exercises the font commands, and further research will be conducted.

–I Ideograph Tests.

An “ideogram” is technically a symbol representing a concept or and idea, or what today we would call a “meme”. Street signs without words, mathematical-operator symbols or a photo of a cat hanging onto a branch with one paw could be considered as ideograms.

The ideograms defined by the `ECMA-48 (ANSI)` standard appear to have been intended as line-drawing tools or text decorations; however, they seem to have been abandoned before they were completed. As such, they are unlikely to be supported by modern terminals; however, this test issues the associated escape sequences to see what happens i.e. nothing:
`aesIDEO_UNDER //` ideogram underlined
`aesIDEO_UDOUBLE //` ideogram double-underlined
`aesIDEO_OVER //` ideogram overlined
`aesIDEO_ODOUBLE //` ideogram double-overlined
`aesIDEO_STRESS //` ideogram stress marking
`aesIDEO_OFF //` all ideogram attributes off

–T Terminal Configuration Tests.

This test exercises the various terminal configuration options and the internal tracking data related to those options.

i : Input stream capture e : Echo options, with a focus on the "soft-echo" options. a : All soft-echo special keys translated. (incl. clipboard tests) b : Basic set of soft-echo special keys. c : Cursor-movement special keys translated. d : Disable soft-echo special-key translation. e : Edit keys: Backspace/Del/Insert translated. r : Report special key translations. t : Terminal echo of key input. n : No echo of key input. t : Terminal configuration validation of options, including input buffering, cursor style and capture of the break signal. b : Blocking vs. non-blocking read from 'stdin' r : Raw input stream reporting. The data are reported in unmodified form. o : Output, tests handling of multi-byte character data in the output stream. m : Modifiers: Bold, Italic, Underline, Reverse, Overline, etc. f : Formatted output. Test data formatting and output to stdout. Examples: epts `--`test=T # Display the menu of sub-options epts `--`test=Tb # Test blocking vs. non-blocking input epts `--`test=Tec # Soft-echo options, cursor-movement keys Developer's Note: The text-modifier tests are included with the terminal configuration group because the tests include verification of the flags that track which modifier(s) are set at any given time.
–W Window (ACWin) Tests.

The window group consists of `API`-level algorithms which are implemented at a higher abstraction level compared to the basic `ANSI` escape sequences.

At an intermediate level are the line-drawing and box objects which simply draw lines and rectangles to the display. These objects are defined by the acDrawLine method and the AC_Box Class, respectively.

At the higher level of abstraction is the ACWin Class which defines a relatively primitive window object which optionally contains an array of text fields and other user-interface controls (see skForm Class).
See also the next section which describes “dialogs”, which are functionally sub-windows within the main window.

Visually, an ACWin window is simply a rectangle drawn within the terminal window; however, application-level interaction is carefully range-checked and validated to maintain the integrity of the window. This allows the application designer to focus on the project, rather than being distracted with organizing color change sequences, counting text columns and other low-level details.

The tests in this group exercise all the major functionality of defining and managing the ACWin object.

w : Window (ACWin) interactive tests f : Form: skForm class (and skField class) user interface controls t : Automatic text reformatting to fit specified dimensions d : Default AC_Win window constructor s : Save and restore static text written to the window m : Menus and Scrollbox controls. These controls require specialized tests. h : Highlight text. Scan field text for a given token, and highlight it. e : Documentation tool, take a screenshot to insert into documentation. b : Box drawing tests l : Line drawing tests x : eXternal interface tests a : AnsiCmd API-level clipboard tests (tty output) w : Window (ACWin/ACDlg) clipboard tests t : Temporary-file management s : Shell out to command line l : Launch external application Examples: epts --test=W # Display the menu for the window group epts --test=Ww # Interactive test of ACWin configuration epts --test=Wf # User interaction via skForm control group epts --test=Wlg # Line-drawing tests with 'g'reen lines epts --test=Wxw # Clipboard-to-window communication
–D Dialog (ACDlg) Tests.

The dialog tests are a functional subset of the the window tests (see ACWin Class), but because the Dialog is at the highest level of abstraction, a large number of tests are required, so they are grouped separately.

'D' Dialog-oriented tests (application-level functionality). 'q' QuickDialog tests are specified by the letter 'q', followed by the letter or number for the specific test: '1' Basic information dialog (one control) 'e' Basic decision dialog with English pushbuttons 'c' Basic decision dialog with Chinese pushbuttons 'v' Basic decision dialog with Vietnamese pushbuttons 's' Basic decision dialog with Spanish pushbuttons 't' Auto-Timeout dialog, displayed for specified interval only 'p' Dialog dimensions determined by size of Preformatted text. 'w' Fixed-width dialog with text automatically formatted 'h' Fixed-height dialog with text automatically formatted 'r' Repositioned automatically within the parent window. '?' If no test letter is specified, or if an invalid test is specified, the QuickDialog test menu is displayed. 'd' Dialog, full initialization. Tests re specified by the letter 'd', followed by the letter or number for the specific test. -- Dialog invocations with full initialization allow for any _reasonable_ number of customized controls of all defined control types, in any order and in any position. 'a' Preformatted text, Auto-dimensions, Centered horizontally and vertically. 'b' Auto-height, Fixed width, Text reformatted to specified width. 'c' Preformatted text, Auto-width, Fixed height, Centered horizontally and vertically. 'd' Unformatted text, Auto-dimensions, Centered horizontally and vertically. 'e' Unformatted text, Fixed horizontal and vertical offsets, Auto-height, Fixed-width. Text truncated to fit available space. 'f' Unformatted text, Fixed horizontal and vertical offsets, Fixed-height, Auto-width. Text truncated to fit available space. 't' Unformatted text, Centered vertically and horizontally, Fixed height and width specified, with height value overridden, but truncation of text still required. 'w' Unformatted text, Centered horizontally, Fixed height and width, Fixed vertical offset, Text truncated to fit available space. 'h' Move dialog horizontally in increments using preformatted text. Resize dialog as necessary to stay within parent window. 'i' Move dialog horizontally in increments using unformatted text. Resize dialog as necessary to stay within parent window. 'v' Move dialog vertically in increments using preformatted text. Resize dialog as necessary to stay within parent window. 'u' Move dialog vertically in increments using unformatted text. Resize dialog as necessary to stay within parent window. 'z' Dialog demonstrating all features: Pushbuttons, Radiobuttons, Textboxes, static text. '?' If no test letter is specified, or if an invalid test is specified, the full-Dialog test menu is displayed. '0' Display the menu of dialog tests. 's' Sidebar test. This test is unrelated to dialogs. It is included in this group because this group uses an empty ACWin window object which allows for easy testing of the Sidebar functionality. Examples: epts --test=D # Display the menu for the dialog group epts --test=Dq # Display the menu for the QuickDialog sub-group epts --test=Dd # Display the menu for the full-dialog sub-group epts --test=Dqp # Dialog dimensions derived from displayed text epts --test=Ddz # Dialog with samples of all control types
–S Sandbox.

The “Sandbox” is a common name among nerdy types to indicate a work area in which experimental operations may be performed without compromising the platform as a whole.

Invoking the Sandbox executes user-defined functionality created for ad hoc testing. Note that code created in the Sandbox may be affected by the AnsiCmd class initialization as specified by arguments to the “`--term`” command-line option.
See Invoking - Terminal Setup for more information.

Invoking the Sandbox test may include one or two optional arguments which are passed as parameters to the Sandbox method. Each of these optional arguments consists of a single alpha-numeric character, (case insensitive).

Examples:
`epts --test=S` # invoke the Sandbox with no arguments
`epts --test=St` # invoke the Sandbox with one argument
`epts --test=S4c` # invoke the Sandbox with two arguments

The specified arguments will be displayed in the top row of the window as shown, and these parameters may be referenced in the usual way.
(A question mark will be displayed for unspecified argument(s)).

Test ANSI Commands: 'S' '4' 'c' ------------------------------- Welcome to the Sandbox! Example: void AnsiCmd::Test_Sandbox ( wchar_t parmA, wchar_t parmB ) { if ( parmA == L'4' ) this->SolveWorldHunger ( parmB ) ; else if ( parmA == L'5' ) this->MakeScrambledEggs_with ( parmB ) ; else if ( parmA == L'?' ) this->SpendAllDayOnTikTok () ; }

### Invoking - EarthPoints

#### Summary of Options

> OPTION | DESCRIPTION
> --- | ---
> coa option | Specify the first set of global coordinates.
> cob option | Specify the second set of global coordinates.
> file option | Specify a file containing global coordinate pairs.
> formula option | Specify the formula to be used to calculate distance.
> convert option | Convert coordinate-pair format to alternate formats
> color option | Specify color attribute for reporting results.
> verbose option | Display verbose output for results of calculation.
> window option | Display the report within a window object.
> dump option | Display and verify contents of a file of GPS records.
> version option | Reports EarthPoints version number and copyright info.
> help option | Display all EarthPoints and AnsiCmd options
> helpless option | Same as `'--help'` option except pipe through `'less'`

Options may be specified in any order.

For each option that requires one or more arguments, the option name and its argument(s) may be separated by either `'='` or `' '` (space). Note that if the argument contains whitespace, then the entire argument sequence must be enclosed within single-quotes or double-quotes. This prevents the terminal’s shell program from “interpreting” (trashing) your argument formatting.

    Examples:
        --coa=Miami:25.775163:80.208615
        --coa 'Miami: 25.775163 : 80.208615'
        --cob="Buenos Aires: -34 36 12.0 : -58.381666667"
        --file='Europen Capitol Cities - 2007.txt'

Note: As a convenience, the long-form options may be uniquely specified in a truncated form. At least six (6) characters of the option must be specified. This consists of the two `'dash'` characters, plus the first four characters of the option name. Example: The “`--verbose`” option may be uniquely specified as “`--verb`”.

#### GPS Coordinate Records

A GPS coordinate record has the following format:
`[LABEL:] LATITUDE : LONGITUDE`
where:

- `LABEL:` — (optional) city or place name associated with the
  `` coordinates, followed by the colon character (`':'`)
  `` which separates the label from the latitude field.
- `LATITUDE` — (required) Specify the latitude for the record
  `` in degrees or radians.
- `colon (:)` — (required) Separates latitude and longitude values.
- `LATITUDE` — (required) Specify the longitude for the record
  `` in degrees or radians.

Whitespace between fields of the record is optional, and will be ignored.
Whitespace within a coordinate field delimits the tokens within that field:
`Examples: '25 46.50978' _or_ '25 46 30.5868'`
The label field is simple text, and may contain spaces if desired. (Note the trailing colon `':'`).
`Example: "Miami, Florida, USA:"`

Latitude and longitude pairs may be expressed in either degrees or radians.
Within a latitude:longitude pair, each value may take one of the following formats.

1. a decimal degree value

         Examples:
         --coa='Miami: 25.775163 : -80.208615'
         --cob='Buenos Aires: -34.603333333 : -58.381666667'

   Note that positive degree values indicate North latitude or East longitude, while negative values indicate South latitude or West longitude."

2. a decimal radian value

         Examples:
         --coa='Miami: 0.449861R : 4,883281R'
         --cob='Buenos Aires: 5.679243R : 5.264233R'

   Note that the trailing ’R’ character of each value indicates radians. Note also that an arc in radians is expressed as a positive value only.

3. an integer degree value followed by a decimal minutes value

         Examples:
         --coa='Miami: 25 46.50978 : -80 57.948611'"
         --cob='Buenos Aires: -34 36.20 : -58 22.90'

4. an integer degree value followed by an integer minutes value, followed by a decimal seconds value

         Examples:
         --coa='Miami: 25 46 30.5868 : -80 57 56.91666'
         --cob='Buenos Aires: -34 36 12 : -58 22 54.0'

── ── ── ── ── ── ── ── ── ── ── ── ── ──

#### Invocation Options

– –coa Coordinate pair A.

> Specify the record containing the first pair of GPS coordinates.

> Formatting of the record is described in the GPS Coordinate Records section, above.

> Two sets of GPS coordinates are needed to calculate arc length. See the `"cob" option`, below.

> Please see verbose option, below for sample output formatting.

– –cob Coordinate pair B.

> Specify the record containing the second pair of GPS coordinates.

> Formatting of the record is described in the GPS Coordinate Records section, above.

> Two sets of GPS coordinates are needed to calculate arc length. See the `"coa" option`, above.

> Please see verbose option below for sample output formatting.

– –file Filespec of GPS coordinate database.

> Specify a file containing a database of GPS coordinate pairs and identify two specific records from that database. These records represent the endpoints of the arc distance to be calculated.

> The target file is a plain text file containing any number of GPS records. The individual records follow the same format as command-line record specification described at the beginnig of this chapter. An example database file is shown below. (Not that you would ever do anything so foolish, but the filename may not contain the colon ’:’ character.)

> Each target record is specified by its label, either the full label text, or a substring which uniquely identifies the beginning of the record label. The scan is case-insensitive. Specifying the database filename and record labels takes the form:
> `--file='FILENAME:LABEL_A:LABEL_B'`

> The following record specifications are equivalent.
> `epts --file='GPS_Records.txt:Chicago, IL:Miami, FL'`
> `epts --file='GPS_Records.txt:chi:Mia'`

> Alternatively, the records may be specified using the index of of the record(s) within the database using the special token: “LABn” where `'n'` is a zero-based index.

> Examples:
> `epts --file='GPS_Records.txt:Chicago, IL:LAB14'`
> `epts --file='GPS_Records.txt:LAB2:Miami, FL'`
> `epts --file='GPS_Records.txt:LAB2:LAB16'`

> #### Example GPS Record Database

> Each record lives on a seperate line. Note the range of available coordinate formats. Blank lines and lines beginning with the hash character (’#’), are interpreted as comments and will be ignored.

>     # ---------------------------------------------------
>     # The Not Fully United Kingdom.
>     # ---------------------------------------------------
>     #                                              INDEX
>     #                                              -----
>     # London, England                                0
>     London         : 51 30 26.0 : -0 7 39.0

>     # Edinburgh, Scotland                            1
>     Edinburgh      : 55.953056 : -3.188889

>     # Cardiff, Wales                                 2
>     Cardiff        : 0.898525R : 3.086106R

>     # Belfast, Northern Ireland                      3
>     Belfast        : 54.596521 : -5.930578

> Three GPS database files are included with the AnsiCmd package:
> `'US_Capitols.txt', 'UK_GPS.txt' and 'testpoints.txt'`.

– –formula Formula for arc calculation.

> Select the formula to be used for calculation of the arc distance between the two specified GPS coordinates.
> (Three(3) characters are sufficient to uniquely identify the argument.)

> Available formulae:

> lambert The Lambert formula calculates the arc on an ellipsoid. haversine The Haversine formula calculates the arc on a sphere. all Displays the calculations for all supported formulae. Examples: epts --coa='36.1:-14.3' --cob='37.7:-12.4' `--form=lambert` (default) epts --coa='36.1:-14.3' --cob='37.7:-12.4' `--form=haversine` epts --coa='36.1:-14.3' --cob='37.7:-12.4' `--form=all`

> Additional formulae may be implemented in a future release.

– –convert Convert coordinate formatting.

> Convert one(1) latitude or longitude value from the given format to the alternate supported formats and display the results.

> The `'convert'` option takes one argument of the form:
> `--convert=GPS_COORDINATE_VALUE`

> This option is useful primarily for debugging the input-parsing routines; however, it may also be useful for experimenting with the various GPS coordinate value formats.

> Example coordinate values and the report generated:

> `epts --convert='-80 57 56.91666'` Converted Value: dec:-80.965810 decimal degrees (degrees+minutes+seconds) deg:-80.000000 degrees component min: 57.000000 minutes component sec: 56.916660 seconds component rad: 1.728473 radians fmt: vfSec source format identifier (enum valFmt) `epts --convert=4.2579R` Converted Value: dec:-63.959700 deg:-63.000000 min: 57.000000 sec: 34.918520 rad: 4.257900 fmt: vfRad

– –color Specify color attribute for application.

> Specify the foreground and background color attributes for display of the output. The terminal window’s color attributes are used by default.

> If the `--window` option is used, then the window’s border attributes may also be specified. (Border attributes, if specified, are ignored for TTY output.)

> The `'--color'` option may be used to specify alternate attributes. The format of the arguments takes the form:
> `--color=text_fgnd:text_bkgnd[:border_fgnd:border_bkgnd]`

> Each color is specified as one of the following:

> 'black' 'blue' 'red' 'magenta' 'green' 'cyan' 'brown' 'grey' 'dflt' use terminal default attribute (The first four characters of the name uniquely identify the color.) Examples: `epts --color=blue:grey` // blue text on grey background `epts --color=green:dflt` // green text on default background `epts --color=dflt:blue` // default text color on blue background // blue text, grey bkgnd, cyan border fgnd, black border bkgnd `epts --color=blue:grey:cyan:black` // default text fgnd:bkgnd, magenta border fgnd, blue border bkgnd `epts --color=dflt:dflt:magenta:blue`

– –verbose Report verbose results.

> The standard arc-distance report displays the coordinates in both degrees and radians, and then displays the arc-distance in both kilometers and miles, calculated using the specified formula.

> The verbose arc-distance report displays the same information, except that the coordinate values in degrees are broken down into their component parts: Degrees, Minutes and Seconds.

> Standard Report:

>     Miami, FL                         Buenos Aires, AR
>     ======================            ======================
>     LATITUDE    LONGITUDE             LATITUDE   LONGITUDE
>     ----------  ----------            ----------  ----------
>       0.44986     1.74169  Radians      2.53765     2.12264
>      25.77516   -80.20862  Degrees    -34.60333   -58.38167

> `Distance:` `12905.069560 km (8018.838378 mi)`

> Verbose Report:

>     Miami, FL                         Buenos Aires, AR
>     ======================            ======================
>     LATITUDE    LONGITUDE             LATITUDE   LONGITUDE
>     ----------  ----------            ----------  ----------
>       0.44986     1.74169  Radians      2.53765     2.12264
>      25.77516   -80.20862  Degrees    -34.60333   -58.38167
>            25         -80  Deg(int)         -34         -58
>            46          12  Minutes           36          22
>            31          31  Seconds           12          54

> `Distance:` `12905.069560 km (8018.838378 mi)`

– –window Display report in a window.

> By default, the arc-distance report is displayed in the terminal window using common TTY (Teletype) style output. This output is formatted using basic ANSI escape sequences.

> Optionally, the arc-distance report may be formatted within an ACWin-class window object positioned within the terminal window. The ACWin class is derived from the base AnsiCmd class and implements more advanced `ANSI` formatting. It is designed to resemble an `'ncurses'` dialog window.

> Please see ACWin Class for more information.

> By default, the dialog window is positioned with the origin (upper-left corner) at row one(1), column four(4) of the terminal window. However, any position within the terminal window may be specified using parameters of the form: `'row:column'`.

> The row and column are 1-based offsets from the upper-left corner of the terminal window. See cursor offsets for a discussion of 1-based versus 0-based terminal offsets.

> Additionally, specifying a zero (0) value for either parameter indicates that the dialog is to be centered in that dimension. See examples below.

> If the specified position would place any part of the dialog beyond the boundaries of the terminal window, then the position will be automatically adjusted to ensure that the entire dialog is visible.

> Examples:
> `epts --window` // no position specified, use default 1:4
> `epts --window=2:1` // positioned at row 2, column 1
> `epts --window=12:0` // positioned at row 12, centered horizontally
> `epts --window=0:5` // centered vertically, and at column 5
> `epts --window=0:0` // centered both vertically and horizontally
> In the following example, the row specified is beyond the number of rows in the terminal window, so the vertical offset will be automagically adjusted such that the lower edge of the dialog is on the bottom row of the terminal window:
> `epts --window=99:0` // auto-adjusted row, and centered horizontally

> > ┌─┤ EarthPoints v:0.0.03 (c) 2022-2023 The Software Samurai ├─┐ │ Miami, FL Buenos Aires, AR │ │ ====================== ====================== │ │ LATITUDE LONGITUDE LATITUDE LONGITUDE │ │ ---------- ---------- ---------- ---------- │ │ 0.44986 1.74169 Radians 2.53765 2.12264 │ │ 25.77516 -80.20862 Degrees -34.60333 -58.38167 │ │ Distance: 12905.069560 km (8018.838378 mi) │ │ │ │ Press Any Key To Exit... │ └──────────────────────────────────────────────────────────────┘

> Please visit the author’s website to download the NcDialog API, and for a discussion of full-featured dialog windows based on the ncurses library. See By the Same Author for details.

– –dump Dump GPS file contents.

> Display and verify the formatting of GPS coordinate records contained in the specified file.

> A database of GPS coordinate records is a plain text file with a series of records in the form:
> `Phoenix, AZ : 33 26 53.15 : -112 5 49.54`
> consisting of three(3) fields, seperated by colons (’:’).
> `Label : Latitude : Longitude`

> Formatting of the record is described in the GPS Coordinate Records section, above.

> When constructing a database of GPS coordinate records, the syntax of the records should be verified.
> The syntax of each record in the database is verified using the `"--dump"` option.

> Example:
> `epts --dump='US Capitols.txt'`

> The following is the output for the scan of the `'testpoints.txt'` file included in this package.

>     EarthPoints (epts) v:0.0.03 Copyright(c) 2022-2023  The Software Samurai
>     ========================================================================
>     Validate contents of GPS record file: 'testpoints.txt'
>     ------------------------------------------------------
>     00) :25 46 30.5868 : -80.208615                             (OK)
>     01) Miami, FL : 25 46 30.5868 : -80.208615                  (OK)
>     02) Buenos Aires, AR : -34 36 12.0:-58 22.90                (OK)
>     03) Indianapolis, IN : 39.768611 : -86.158056               (OK)
>     04) Lafayette, IN : 40.417222 : -86.878611                  (OK)
>     05) San Francisco, CA : 37.7775 : -122.416389               (OK)
>     End-Of-File

> If a syntax error is found, it will be indicated by a status of “(?)”.
> For example, this record is missing the madatory field delimiter `':'` between the Label and Latitude fields.
> `01) Miami, FL 25 46 30.5868 : -80.208615 (?)`

– –help (or –h) Display command-line help.

> Command-line Help. Display a brief summary of command-line usage and options. (overrides everything on command line except `'--version'`)

>        EXAMPLES:  epts --help
>                   epts -h

– –helpless Display command-line help.

> Display command-line help. Same as the `'--help'` option above except that the help menu will be piped through the `'less'` utility.

>        EXAMPLES:  epts --helpless
>                   epts -hl

– –version Report EarthPoints version number.

> Display the EarthPoints version number and copyright information.
> (overrides everything else on the command line)

> To also report the AnsiCmd-class version number, append an `'a'` to the argument.

>        EXAMPLES:  epts --version
>                   epts --versionA

## AnsiCmd Library

### Introductory Notes

For those who are new to the terminal (emulator) environment, or for those who are interested in the technical details of terminal configuration, this chapter provides an overview of the challenges the author faced during development of this project, and our responses to those challenges.

#### Terminal Environment

A common saying in Linux is that “Everything is a file.” While it is true in general that most things are acessed as if they were files, many of the underlying targets are not actually files on the storage media. This is nowhere more apparent than with the input and output data streams of the terminal emulator. Generically, these are known as Standard Input(stdin), Standard Output(stdout) and Standard Error(stderr).

Within the `AnsiCmd` library, these are referred to by their so-called file handles which are named by the `'TermStream'` enumerated type:

Name Handle stdIn 0 stdOut 1 stdErr 2

These streams are not actual files, but the terminal’s VIRTUAL configuration files. Therefore, practically speaking, when modifying terminal settings, it doesn’t matter whether the stdIn, stdOut or stdErr stream is referenced because they are not actual file descriptors. Instead, they reference the underlying terminal-attributes structure.
For more information, see Terminal Configuration.

### ANSI Escape Sequences

`ANSI` (American National Standards Institute) escape sequences are simply a well-defined set of byte sequences that may be used to communicate with the host terminal. They are hopelessly old-fashioned, slow, unreliable, difficut to use and all-around relics from the mid-20th century. That being said, they are also widely supported and a lot of fun to play with.

`ANSI` escape sequences include functionality for cursor positioning, erasing blocks of text, setting color attributes and text modifiers such as bold, italic etc., and all other attributes defined by the ECMA-48, ANSI X3.64 standard. See also ISO/IEC 6429, FIPS 86, ISO/IEC 2022, JIS X 0211.

Wikipedia: https://en.wikipedia.org/wiki/ANSI_escape_code

#### Escape-sequence Definitions

Within the AnsiCmd library, the individual `ANSI` escape sequences are referenced by the “`enum aeSeq`” enumerated type.

`aeSeq` (ANSI Escape Sequence) is located in the `AnsiCmdDef.hpp` header file and includes all the `ANSI` escape sequences defined by the `ECMA-48, ISO/IEC-6429` standard.

Note that each member begins with “`aes`” to indicate that it belongs specifically to this enumerated type. The short example below should give the basic idea of how `aeSeq` is constructed.

    enum aeSeq : short
    {
       //** Text Modification Options. **
       aesRESET = 0,              // reset all attributes
       aesBOLD,                   // bold (increase intensity)
       aesFAINT,                  // faint/dim (decrease intensity)
       aesITALIC,                 // italic (or inverse)
       . . .
       //** Foreground Color Attributes (3-bit and 4-bit color selection) **
       aesFG_BLACK,               // set foreground color to black (i==24)
       aesFG_RED,                 // set foreground color to red
       aesFG_GREEN,               // set foreground color to green
       . . .
       //** Background Color Attributes (3-bit and 4-bit color selection) **
       aesBG_BLACK,               // set background color to black (i==41)
       aesBG_RED,                 // set background color to red
       aesBG_GREEN,               // set background color to green
       . . .
       //** Indexed Color Attribute Options (8-bit color and greyscale) **
       aesFG_INDEX,               // set foreground color by lookup table index (0-255)
       aesBG_INDEX,               // set background color by lookup table index (0-255)

       //** Red/Green/Blue Color Attribute Options (24-bit color) **
       aesFG_RGB,                 // set foreground color by r/g/b register number
       aesBG_RGB,                 // set background color by r/g/b register number

       //* Cursor-positioning Options *
       aesCUR_HOME,               // set cursor at 1,1
       aesCUR_ABSPOS,             // set (absolute) cursor at specified row;column position
       aesCUR_ROWSUP,             // move cursor upward by specified number of rows
       . . .
       //* Text Erasure Options *
       aesERASE_BOW,              // erase from cursor to bottom of window
       aesERASE_TOW,              // erase from cursor to top of window
       aesERASE_WIN,              // erase entire window ('clear')
       . . .
       //* Alternate Font group *
       aesPRIMARY_FONT,           // primary font      (font 0)
       aesALTERNATE_FONT,         // alternate fonts (font 1 through font 9)

       //* ASCII Control Codes. *
       aesBELL,                   // '\a' terminal "bell" (beep, ping, etc.)
       aesBKSP,                   // '\b' backspace
       aesHTAB,                   // '\t' horizontal tab
       . . .
       //* Ideogram (logogram) group of options *
       aesIDEO_UNDER,             // ideogram underlined
       aesIDEO_UDOUBLE,           // ideogram double-underlined
       aesIDEO_OVER,              // ideogram overlined
       . . .
       //** Aixterm codes are not part of the    **
       //** ANSI standard, but may be supported. **
       aesAIXFGb_BLACK,           // set foreground color to bright black (grey)
       aesAIXFGb_RED,             // set foreground color to bright red
       aesAIXFGb_GREEN,           // set foreground color to bright green
       . . .
       aesCOUNT                   // number of items in enumerated type list
    } ;   // enum aeSeq

The members of `aeSeq` index the corresponding byte sequences which are private data located in the `AnsiCmd.cpp` source module.
`static const wchar_t *ansiSeq[aesCOUNT];`

A majority of the element of this array are constant byte sequences; however, the sequences which require parameters are defined as formatting templates as shown in these examples.

Constant byte sequence:
`L"\x1B[22;31m"` `// aesFG_RED`
Formatting template:
`L"\x1B[38;5;%hhum"` `// aesFG_INDEX`

Note that these sequences are defined as wide character strings because as explained elsewhere (Terminal Configuration), 8-bit character streams are so very 1970s.

#### Multi-threading

ANSI escape sequences should not be used in multi-threaded applications due to timing issues and resource conflicts. For multi-threaded applications, the author recommends our `NcDialog API`, which is a fully thread-safe ncurses-based library for creating formatted-text console applications.

One practical effect of avoiding multi-threading is in the area of library functions which handle timing and delays.

In C++, the accepted way to delay the action is to use the ’chrono’ class to define the delay, and the ’sleep_for’ method to execute it. However, `ANSI` escape sequences are inherently incompatible with a multi-threaded environment. For this reason, the AnsiCmd class uses the C-language nanosleep() function. This function is technically sophisticated, but clunky in implementation; so please refer to our iplementation of nanosleep(): nsleep() for details. (see nsleep)

### Terminal Configuration

Initial terminal configuration is specified by passing an initialized `TermConfig` object to the AnsiCmd constructor.
See TermConfig Class.

Subsequent modifications to the terminal environment are specified by calling the associated AnsiCmd-class method(s).
See AnsiCmd Class Methods.

The actual configuration commands are issued by the `TermSet` object, which is a private member of the `AnsiCmd` class as described below.
See TermSet Class.

#### TermConfig Class

Initialization of the `TermConfig` object may be done directly by the application when invoking the AnsiCmd constructor:
AnsiCmd constructor,
or may be performed by the user through command-line options:
Invoking - Terminal Setup.
The options provided by the user are validated and stored in the data members of the TermConfig object.

#### Data Members

- `TermStream termStream`
  Specify the target I/O stream as a member of enum TermStream:
  `stdIn (stdin), stdOut (stdout), stdErr (stderr)`

  Note: In practical terms, the selection of the target stream is not important because changes made to one stream are reflected in all streams. Internally, `'stdIn'` is used when not specified otherwise.

- `char configFile[gsMAXBYTES]`
  `NOT YET IMPLEMENTED`
  Name of configuration file (default “ansicmd.cfg”) which specifies all terminal configuration options.
- `char localeName[LOCALE_LEN]`
  Filename of alternate locale (null string by default). If not specified, locale will be taken from terminal environment.

  For those not familiar with the purpose of the `'locale'` specification, the locale selected controls how characters are encoded, formatting of numbers, timestamps and currency, interpretation of punctuation, comparisons of text strings and other text formatting decisions. By default, applications start in the so-called “C-locale” which is not really a locale, but a lack of locale which interprets everything in terms of `ASCII` and English, rendering the application basically useless. For this reason, it is strongly recommended that all application set the locale for the language, character set and text conventions in use by the target system.
  Please refer to the acSetLocale method for additional information.

- `EchoOpt echoOption`
  The selected Echo Option specifies how the data input stream is to be managed.

  Characters received through `'stdin'` will be echoed (displayed) in the terminal window according to the specified member of enum EchoOpt.

  When system buffering of input is active, the application has no direct control over input echo, so this option will be ignored. However, when input buffering is disabled (see the `'bufferInput'` variable, below), the specified echo option will be used:

  - noEcho : input data are not echoed to the display.
  - termEcho: terminal automatically echoes input
    The terminal always controls input echo when input buffering is enabled, and may be allowed to control input echo when buffering is disabled.
  - softEcho[A|B|C|D|E]: the acRead input methods echo (display) all graphing (printing) characters to the terminal window as they arrive. The “special” keys (cursor movement, text selection, clipboard access and backspace, delete, insert) are processed according to specified soft-echo sub-option.
    - softEchoA - All special keys are captured, decoded and available to the application.
    - softEchoB - Basic group of special keys. (Text selection keys and Copy/Cut/Paste/Undo keys are excluded.)
    - softEchoC - Cursor keys only: UpArrow, DownArrow, LeftArrow, RightArrow, Home, End, PageUp, PageDown, Tab and Shift+Tab. (Edit keycodes are excluded.)
    - softEchoD - Disable (capture and discard) all special keycodes.
    - softEchoE - Edit keys Backspace, Delete and Insert, plus Tab and Shift+Tab. (Cursor movement keycodes are discarded.)

    The keycodes in each special-key group may be adjusted, as we receive more feedback from users about how they uses these options.

    Please see Soft Echo Options below for more information.

- `bool bufferInput`
  Specify whether data from `'stdin'` will be buffered by the system or whether it will be sent directly to the application as soon as it arrives in the input stream.
  `'false' : disable input buffering`
  `'true; : input buffering enabled (default)`
  Note that both the soft-echo options (described above) and non-blocking read of the input stream require that input buffering be disabled.
- `bool wideStream`
  Select the character width of the input/output streams.
  `'true' : wide (32-bit) I/O streams, wcin and wcout`
  `'false' : narrow (87-bit) I/O streams, cin and cout`
  Please see acSetStreamWidth for additional information.
- `bool nonStandard`
  Specify whether the host terminal is ANSI compliant.
  A compliant terminal supports all of the common commands of `ANSI` standard `(ANSI X3.64 (ISO/IEC6429))`. `'true' : non-standard terminal emulator`
  `'false' : ANSI compliant terminal emulator (default)`
  The three terminal emulators used during development, Gnometerm, Konsole and XTerm are all fully compliant with the standard. To determine whether your preferred terminal supports all the `ANSI` escape sequences defined by the standard, run the full set of tests provided with this library. Please see Development and Testing for full information.
- `CCH_Type bcType`
  Capture the Panic Button (CTRL+C key). The signal-capture type is specified as a member of enum CCH_Type:
  - `cchtTerm` - Terminal handles CTRL+C break-signal.
  - `cchtExit` - The application terminates execution in an orderly way.
  - `cchtUser` - Ask user whether to exit or discard the signal.
  - `cchtCopy` - Convert the break signal to an ordinary keycode.
  - `cchtIgnore` - Ignore (discard) the break signal.

  See Capturing the Break Signal below for more information.

- `bool bcAlert`
  For `'bcType' == cchtIgnore` ONLY: Specify whether the application should sound an audible alert when the break signal is captured and discarded. (This is a polite way of telling the user to stop pressing the Panic Button.)
  `'true' : sound the alert when break is captured and discarded`
  `'false': silently discard the captured break signal`
- `CurStyle cursorStyle`
  Select cursor style. The cursor style is specified as a member of enum CurStyle:
  - `csDflt` Terminal default cursor style.
  - `csBblock` The shape of the cursor is a full-character cell, blinking block. (This is also generally the terminal default shape.)
  - `csSblock` The shape of the cursor is a full-character cell, steady (non-blinking) block.
  - `csBuline` The shape of the cursor is a blinking underline i.e. one or two pixel rows at the bottom of the character cell.
  - `csSuline` The shape of the cursor is a steady underline i.e. one or two pixel rows at the bottom of the character cell.
  - `csBvbar` The shape of the cursor is a blinking vertical bar i.e. one or two pixel columns at the left edge of the character cell.
  - `csSvbar` The shape of the cursor is a steady vertical bar i.e. one or two pixel columns at the left edge of the character cell.
  - `csHide` Hide the cursor i.e. make it invisible. Note that the previouly selected cursor shape will be retained.
  - `csShow` Show the cursor i.e. make it visible.
- suspendSignal
  Specify whether the Suspend signal is captured by the application.
  The system uses the suspend signal to put the active process into hibernation.

  By default, the `AnsiCmd` library captures this signal and converts it to an ordinary keycode (wcsCTL_Z). Under most circumstances, this is the desired action; however, if specified, the system can be allowed to retain control of this signal.
  `'false' : the system retains control of the suspend signal`
  `'true' : the suspend signal is captured and disabled (default)`
  Please see acCaptureSuspendSignal for additional information.

- quitSignal
  Specify whether the Quit signal is captured by the application.
  The system uses the quit signal to immediately kill the application and then produce what is known as a “core dump” which is a file that contains information about the final state of the application.
  `'false' : the system retains control of the quit signal`
  `'true' : the quit signal is captured and an orderly`
  `shutdown is executed (default)`
  Please see acCaptureQuitSignal for additional information.
- `aeSeq foreground`
  Specify the initial foreground (text) color attribute.
  This is a member of the 4-bit foreground color group within `enum aeSeq: aesFG_xxxx (default:aesFG_DFLT)`
  Please see ANSI Escape Sequences for examples.
- `aeSeq background`
  This is a member of the 4-bit foreground color group within `enum aeSeq: aesBG_xxxx (default:aesBG_DFLT)`
  Please see ANSI Escape Sequences for examples.

#### Capturing the Break Signal (CTRL+C)

The break signal is generated by the user pressing the `Control+C` key combination. By default, the break signal is captured by the terminal which then sends the kill signal to the application running within the terminal window. It is often useful, however, to redirect the break signal to application control. The AnsiCmd library can perform this redirection in either of two ways.

1. Activate the break-signal handler during instantiation of the AnsiCmd class by setting the `'bcType'` member of The TermConfig object which is passed as the argument to the AnsiCmd constructor.
   Please see TermConfig Class and Invoking - Terminal Setup for detailed instructions on specifying a break-signal handler using this method.
2. Specify redirection of the break signal to application control through a call to the acCaptureBreakSignal method.

   While the first option always invokes the AnsiCmd library’s default handler, the `'acCaptureBreakSignal'` call can specify either the default handler or an alternate handler provided by the application.

   The `'acCaptureBreakSignal'` method can also be used to return control to the terminal’s signal handler.

The mechanics of transferring control of the break signal to the application are straightforward, but non-trivial. It is accomplished by “registering” a signal-handler function with the system using the C-library function:
`'signal( int SIGNUM, sighandler_t ACTION )'`.
This function is defined in the `'signal.h'` header file.
The SIGNUM parameter in this case is the macro `'SIGINT'` (the interrupt signal). The ACTION parameter is the address (name) of the function to which the break signal will be directed.

The terminal’s signal handler is defined by the macro `'SIG_DFL'`, while the application’s handler may be specified by the name of any (non-member) function in the application which is configured to process the signal.

The non-member function in the AnsiCmd library is cryptically named `'BreakSignal_Handler'`. The system call is then:
`signal ( SIGINT, BreakSignal_Handler );`

Because we want to provide for potential user interaction when the break signal is received, we perform the slightly dangerous operation of allowing the non-member function to call an AnsiCmd-class member method:
`breaksignalReceived ( int sigNum );`
This is where the action takes place.

The type of operation to perform has been specified during handler setup, and is a member of enum `CCH_Type` (Control_C_Handler Type).

- `cchtTerm -` Terminal handles CTRL+C break-signal by issuing the kill signal to the application running within the terminal. Generally, this can be done without serious consequences; however, it may be necessary to manually reset the terminal by calling the `'reset'` utility to return the terminal configuration to a known state. For instance, if the application is terminated using CTRL+C, the current terminal attributes will still be active when the terminal shell regains control.
- `cchtExit -` The application will perform any specified housekeeping tasks, and then immediately terminate execution, returning control to the terminal shell program. For the AnsiCmd class, “housekeeping tasks” include returning the terminal configuration to its original state, deleting all allocated objects by calling the destructors for the objects in the proper order, setting the exit code and executing the C-library exit sequence.
- `cchtUser -` Prompt user for whether to exit the application or to discard the break signal and continue execution.
  Break Detected. Exit? (N / y): _
  This message is written to the upper-right corner of the terminal window and uses a blinking text attribute to draw the user’s attention.
- `cchtCopy -` Convert the captured break signal to the keycode `wcsCTL_C` (Ctrl+C). The application can then process the keycode or discard it as desired. For instance, the ACWin class recognizes this keycode as the “Copy” command, and copies the selected text to the clipboard.
- `cchtIgnore -` Ignore (discard) the break signal and continue execution of the application; optionally, sounding an audible alert so the user knows that the signal was received, but discarded. (see bcAlert member of the TermConfig class for enabling the audible alert.)

#### Soft Echo Options

“Soft Echo” options define a range of ways in which keyboard input can be captured and filtered before it is echoed (written) to the terminal window.

The primary method for selecting the the soft-echo option is to specify it during a call to the acBufferedInput method which disables input buffering and optionally specifies the character-echo option and whether the input stream uses a blocking or non-blocking read.

The soft-echo option may also be specified as a command-line option. See the `'echoOption'` member in the discussion of the
TermConfig Class, above.

If the echo option is `termEcho`, then the terminal decides what input is echoed to the display. If the echo option is `noEcho`, then keyboard input is not written to the display.

Specifying one of the soft-echo options disables automatic echo of keyboard input to the display, and then sorts the incomming keycodes into two main groups: graphing (printing) characters and non-printing control codes.

Graphing (printing) characters are written to the display in the usual way, but control codes are captured, and either converted to one of the “special” keys or discarded according to the selected soft-echo option.

- softEchoA - All special keys are captured, decoded and available to the application, which can then interpret the keycode or discard it.
  This is the default soft-echo option.
- softEchoB - Basic set of special keys including the cursor keycodes, and the edit keycodes, but excludes the text-selection and clipboard-access keycodes.
- softEchoC - Cursor keys only: UpArrow, DownArrow, LeftArrow, RightArrow, Home, End, PageUp, PageDown, Tab and Shift+Tab.
  `` (Edit keycodes are excluded.)
- softEchoD - Disable (capture and discard) all special keycodes.
- softEchoE - Edit keys Backspace, Delete, Insert, AltEnter, plus Tab and Shift+Tab. (Cursor movement keycodes are discarded.)

See the next section for more information on the “special” keycodes.

> #### Decoding the “Special” Keys

> The “special” keycodes consist of certain keycodes which are presented to a console application in the form of escape sequences. An escape sequence is a sequence of bytes beginning with the the escape character (0Bh). The number of bytes in an escape sequence varies from two bytes to seven bytes (or more on some systems).

> Many keyboard keys are encoded in this way: the Function Keys, the Cursor Positioning keys, the Backspace/Delete/Insert keys, and most of the keycodes generated in combination with the so-called conditioning keys: Shift, Control, Alt.

> For a (nearly) complete list of keystrokes that generate escape sequences and the sequences they generate, please download the author’s NcDialog API package and study the source files `NCursesKeyDef.hpp` and `NCursesKeyDef_auto.hpp`.

> For the AnsiCmd library, only a subset of these escape sequences are captured and decoded. These include the “special” keys listed in the table below, as well as combination-keys discussed in the following sections:
> ASCII Control Codes and GUI Keys.

> Key Function | Esc Seq (hex) | Key Name | Glyph/Keycode
> --- | --- | --- | ---
> Up Arrow | 1B 5B 41 | wcsUARROW | `↑` 2091h
> Down Arrow | 1B 5B 42 | wcsDARROW | `↓` 2093h
> Right Arrow | 1B 5B 43 | wcsRARROW | `→` 2192h
> Left Arrow | 1B 5B 44 | wcsLARROW | `←` 2190h
> Home Key | 1B 5B 48 | wcsHOME | `↖` 2196h
> End Key | 1B 5B 46 | wcsEND | `↘` 2198h
> Page Up | 1B 5B 35 7E | wcsPGUP | `↗` 2197h
> Page Down | 1B 5B 36 7E | wcsPGDN | `↙` 2199h
> Tab | 09 | wcsTAB | `↱` 211Bh
> Shift+Tab | 1B 5B 5A | wcsSTAB | `↲` 21B2h
> Backspace | 7F | wcsBKSP | `↰` 21B0h
> Delete | 1B 5B 33 7E | wcsDELETE | `↳` 21B3h
> Insert | 1B 5B 32 7E | wcsINSERT | `↥` 21A5h
> Alt+Enter | 1B 0A | wcsAENTER | `↧` 21A7h
> Shift+Up | 1B 5B 31 3B 32 41 | wcsSUP | `↾` 21BEh
> Shift+Down | 1B 5B 31 3B 32 42 | wcsSDOWN | `⇂` 21C2h
> Shift+Right | 1B 5B 31 3B 32 43 | wcsSRIGHT | `⇀` 21C0h
> Shift+Left | 1B 5B 31 3B 32 44 | wcsSLEFT | `↼` 21BCh
> Shift+Home | 1B 5B 31 3B 32 48 | wcsSHOME | `⇇` 21C7h
> Shift+End | 1B 5B 31 3B 32 46 | wcsSEND | `⇉` 21C9h
> Ctrl+Home | 1B 5B 31 3B 35 48 | wcsCHOME | `⇈` 21C8h
> Ctrl+End | 1B 5B 31 3B 35 46 | wcsCEND | `⇊` 21CAh
> Ctrl+C | 03 | wcsCOPY | `∽` 223Dh
> Ctrl+X | 18 | wcsCUT | `≒` 2252h
> Ctrl+V | 16 | wcsPASTE | `≐` 2250h
> Ctrl+A | 01 | wcsSELECT | `∻` 223Bh
> Ctrl+Z | 1A | wcsUNDO | `≔` 2254h

> Note: Encoding of Backspace and Delete keys are specified in terminal settings.

> The Copy/Cut/Paste keys (`Ctrl+C, Ctrl+X, Ctrl+V`) and the other `ASCII` control codes are described below:
> (see ASCII Control Codes).

> Taken together, these keycodes comprise all the standard keycodes used to edit text within an individual field or on a form consisting of multiple fields.
> Please see skForm Class for a description of how these keycodes are interpreted within a form or a field.

> Also, please see GUI Keys for keycodes which are commonly used as user-interface commands.

#### ASCII Control Codes

`ASCII` control codes are generated by pressing and holding either CTRL key and then pressing one of the alphabetic keys: `'a'` through `'z'`, `'A'` through `'Z'`, or `'4', '5', '6', '7'`.

HEX BYTE HEX BYTE HEX BYTE HEX BYTE --------- --------- --------- ---------- 01 Ctrl+A 0B Ctrl+K 15 Ctrl+U 1D Ctrl+5 (Ctrl+]) 02 Ctrl+B 0C Ctrl+L 16 Ctrl+V 1E Ctrl+6 (Ctrl+^) 03 Ctrl+C 0E Ctrl+N 17 Ctrl+W 1F Ctrl+7 (Ctrl+_) 04 Ctrl+D 0F Ctrl+O 18 Ctrl+X 05 Ctrl+E 10 Ctrl+P 19 Ctrl+Y 06 Ctrl+F 12 Ctrl+R 1A Ctrl+Z 07 Ctrl+G 14 Ctrl+T Exceptions: 08 Ctrl+H Backspace, decoded as wcsBKSP (21B0h) 09 Ctrl+I Tab, decoded as wcsTAB (21B1h) 0A Ctrl+J Enter key i.e. newline 0D Ctrl+M (reported as Ctrl+J, newline) 11 Ctrl+Q Captured by the terminal (release terminal output) This signal is disabled when setting unbuffered input. 13 Ctrl+S Captured by the terminal (pause terminal output) This signal is disabled when setting unbuffered input. 1A Ctrl+Z This generates the SIGTSTP "Stop" signal which puts the current process to sleep. (wake using the 'fg' utility) This signal is captured and converted to wcsCTL_Z. 1B --- Escape 1C Ctrl+4 This generates the SIGQUIT "Quit" signal which kills the current application. This signal is captured and handled as if it were the break signal, implementing an orderly shutdown.

Note that the Shift key is ignored when the CTRL key is pressed. Both the uppercase and lowercase alpha characters produce the same values, and the Ctrl+[4 | 5 | 6 | 7] produce the same values regardless of whether the Shift key is pressed. Examples:
`Ctrl+a == Ctrl+Shift+A`
`Ctrl+5 == CTRL+Shift+5 ('%')`

The Ctrl+C key should be 0x03 in the sequence, but that code is tied to the Break Signal. To recapture Ctrl+C it is necessary for the break handler to capture the signal and push the code back into the input stream. The Break signal handler type “cchtCopy” performs this conversion.
Please see Capturing the Break Signal for a discussion of capturing and re-purposing the break signal.
See acCaptureBreakSignal which implements the signal capture.

The `Ctrl+Z` key should be 0x1A in the sequence, but that code is tied to the Suspend Signal. To recapture Ctrl+Z it is necessary for the suspend handler to capture the signal and push the code back into the input stream. The suspend signal handler performs this conversion.
See acCaptureSuspendSignal which implements the signal capture.

The `Ctrl+4` key should be 0x1C in the sequence, but that code is tied to the Quit Signal (with core dump). To recapture Ctrl+4 it is necessary for the quit handler to capture the signal and provide for an orderly termination of the application. (Ctrl+4 is not associated with an application-level keycode.) Note that the `Ctrl+\` key combination is equivalent to Ctrl+4.
See acCaptureQuitSignal which implements the signal capture.

The `Ctrl+S` and `Ctrl+Q` keys should be 0x13 and 0x11, respectively, but these codes are tied to the Pause/Resume output stream signals. At a terminal configuration level, the flow-control flag, `IXON` handles `stdout` flow control. This flag is automatically reset when configuring the terminal for unbuffered input. This frees the Ctrl+S and Ctrl+Q key combinations for application-specific purposes.
Please see acBufferedInput for additional information.

Certain Control-key combinations are reserved for use by the desktop environment or by the terminal emulator program. For instance, `Ctrl+PageUp` and `Ctrl+PageDown` are used to navigate among terminal tabs. Most of these so-called shortcut keys may be disabled in the terminal’s preferences/settings page.

#### The `GUI` Keys

The `GUI` keys (Graphical User Interface keys) are keycodes that are commonly used by applications as command shortcut keys. These keycodes are generated by pressing one or more of the “conditioning keys” in combination with another key. The conditioning keys are the SHIFT key, the CONTROL keys and the left-side ALT key.

With the exception of the `ASCII` control codes, these keycodes are reported to the application as escape sequences.

The `GUI` keycodes fall into these general categories:

1. Key combinations using the CTRL key and an alphanumeric key.
   `a-z and 4-7`
   These combinations generate the ASCII control codes.
2. The SHIFT key in combination with one of the cursor navigation keys.
   `UpArrow, DownArrow, RightArrow, LeftArrow`
3. The left-side ALT key in combination with another key, or
   both ALT and SHIFT keys in combination with another key.
   `a-z and A-Z and punctuation characters:`
   `! " # $ % & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ _ { | }`
   `UpArrow, DownArrow, RightArrow, LeftArrow, Home, End, PageUp, PageDown`
4. Both the CTRL and ALT keys in combination with another key.
   `a-z`
   Note that when using the CTRL key, the state of the SHIFT key is generally ignored by the keyboard controller.
5. The Function Key group: F01-F12 alone or in combination with the SHIFT and/or CTRL conditioning keys. (ALT+Fnn combinations are not supported.)

All key combinations which are captured are converted to constant values defined in `AnsiCmdDef.hpp`.

> Technical Notes:
> − To use key combinations, first press and hold the conditioning key(s), then press the other key, and release them all together.
> − Note that by default, the right-side ALT key is configured for entering keycodes that are not directly available from the keyboard.

#### TermSet Class

The `TermSet` class encapsulates the low-level access to terminal-configuration options. The AnsiCmd class methods calls the private TermSet object (`'tset' member)` for configuration options such as input buffering, input-echo options, cursor style, blocking vs. non-blocking input, flushing the `I/O` buffers and capture of the break signal (CTRL+C).

All methods and data members of the `TermSet` class are private, and are accessed only by the AnsiCmd (or ACWin) class. This ensures that there is only one point of access to the terminal configuration in order to avoid unfortunate configuration conflicts.

Although the functionality discussed here is not directly available to the application, it is interesting and educational to understand what is going on under the floorboards, so-to-speak.

The application may request a copy of the current terminal settings to verify that the terminal is configured as desired. The data consist of the bitfields defined in the C-language `termios` structure.
See acGetTermInfo for details.

#### Data Members

- `TermIos strOrig`
  This is a copy of the `I/O` stream setting captured during application startup, when the AnsiCmd/TermSet classes are first instantiated.

  This data set is used to return the terminal settings to their original values when the application exits, i.e when the AnsiCmd/TermSet destructors are called.

  Please see AnsiCmd constructor for additional information.

- `TermIos strMods`
  This member contains data for the current terminal configuration. It is updated whenever the configuration is modified.
- `TermStream aStr`
  This is the (virtual) file handle for the “active” (most recently modified) `I/O` stream. it is a member of enum TermStream, consisting of stdIn (stdin), stdOut (stdout) and stdErr (stdErr).
  Note that stdErr is not referenced within the AnsiCmd/TermSet code, but is included for completeness.

  As noted elsewhere (see Introductory Notes), this has little practical value as a file handle because it references a virtual file which manages all three streams as a unit.

- `CurStyle curStyle`
  The cursor style currently applied to the visible cursor. This is a member of enum CurStyle.

  Please see S option for specifying the cursor style as a command line option, and the TermConfig Class for a detailed description of cursor styles.

- `CCH_Type cchType`
  This is a member of enum CCH_Type and specifies the type of Control_C_Handler (break signal handler) currently in use.

  Please see Capturing the Break Signal for a discussion of the break-signal handlers built into the AnsiCmd library.

- `EchoOpt inpEch`
  This is a member of enum EchoOpt and specifies whether and how keyboard input is echoed (displayed) in the terminal window.

  Please see Soft Echo Options and TermConfig Class for a discussion of input-echo options.

- `bool inpBuf`
  This flag indicates whether input buffering is currently enabled.
  `true` == buffering enabled
  `false` == buffering disabled

  Please see B option for specifying the input buffering option as a command line option, and the TermConfig Class for a description of input buffering. See also, the acBufferedInput method.

- `bool inpBlk`
  This flag indicates whether blocking read is active for the input stream.

  The term “blocking read” refers to whether the execution thread should go to sleep while waiting for keyboard input.

  By default, blocking read is active, meaning that when the application requests keyboard input from the user (see acRead), the execution thread goes into a hibernation state until the terminal signals that input is available in the buffer.

  When blocking read is disabled, a request for user input will return the first keycode in the buffer, or will immediately return a `"WEOF"` (zero) if no data are available in the input buffer.

  The AnsiCmd library uses non-blocking read primarily for receiving escape sequences from the terminal program and for flushing the input buffer. The acBlockingInput method makes non-blocking input available in case the application needs similar functionality.
  `NOTE:` This functionality can be dangerous, so use it wisely.

- `bool cchAlert`
  This flag indicates whether an audible “beep” is enabled to alert the user when the break signal (`CTRL+C)` has been received.

  Please see Capturing the Break Signal, and also the acCaptureBreakSignal method for a discussion of the break-signal handlers.

- `bool quitCap`
  This flag indicates whether the Quit signal has been captured.
  The Quit signal is generated by either the `Ctrl+4` key or `Ctrl+\` key combination.
  `true` == signal has been captured and will be handled locally.
  `false` == terminal handles the signal
  See acCaptureQuitSignal method for further information.
- `bool suspCap`
  This flag indicates whether the Suspend signal has been captured.
  The Suspend signal is generated by the `Ctrl+Z` key combination.
  `true` == signal has been captured and will be handled locally.
  `false` == terminal handles the signal
  See acCaptureSuspendSignal method for further information.
- `bool strCap`
  This flag indicates whether the `'strOrig'` member (see above) has been initialized.
  `true` == member initialized
  `false` == member not initialized
- `bool inpMod`
  This flag indicates whether the `'strMods'` member (see above) has been initialized.
  `true` == member initialized
  `false` == member not initialized

For additional information on terminal configuration please refer to the documentation for the C-library functions: `tcgetattr, fcntl, signal` and the `termios` structure and related macro definitions defined in `termios.h and unistd.h`

### AnsiCmd Class Methods

#### Table of Public Methods

The following is a list of AnsiCmd public methods, grouped by function.
Most public methods begin with the letters “ac” (Ansi Command).

The basic methods use `ANSI` escape sequences directly. Some of these methods use C-library function calls to perform terminal configuration.

A few methods are implemented at a higher abstraction level (API level). These are referred to in the documentation as Application-Program-Interface `API` methods. These methods typically do not use the `ANSI` escape sequences directly, but instead call a sequence of low-level (primitive) methods to provide a less cluttered interface between the application and the AnsiCmd library.

See also the ACWin Class in the next chapter which provides a more sophisticated user interface whose functionality lies somewhere between the raw `ANSI` escape sequences and the dialog-oriented interface of the author’s `NcDialog API`.
Please see By the Same Author for more information.

Method Name | Description
--- | ---
`────` Configuration `──────` | `─────────────────────────────────────────`
AnsiCmd constructor | Constructors
AnsiCmd destructor | Destructor
acGetTermSize | Calculate size of terminal window
acGetTermDimensions | Get a copy of stored terminal size
acGetTermInfo | Get current terminal configuration
acSetLocale | Specify a non-default locale
acGetLocale | Get current locale setting
acSetStreamWidth | Lock in wide or narrow I/O streams
acBufferedInput | Configure input-stream buffering
acSetEchoOption | Echo option (unbuffered input only)
acGetEchoOption | Report current echo option
acBlockingInput | Input blocking (unbuffered input only)
acCaptureSignals | Enable Ctrl+C Ctrl+4 Ctrl+Z signals
acReleaseSignals | Disable Ctrl+C Ctrl+4 Ctrl+Z signals
acCaptureBreakSignal | Enable/disable capture of Ctrl+C
acCaptureQuitSignal | Enable/disable capture of Ctrl+4
acCaptureSuspendSignal | Enable/disable capture of Ctrl+Z
acRestoreTermInfo | Set terminal configuration to defaults
breaksignalReceived | default break-signal handler
suspendsignalReceived | default suspend-signal handler
quitsignalReceived | default quit-signal handler
`────` Color Attributes `───` | `─────────────────────────────────────────`
acSetFg | Set text foreground (3-bit, 4-bit, AIX)
acSetBg | Set text background (3-bit, 4-bit, AIX)
acSetFgBg | Set text fgnd and bkgnd (3/4-bit, AIX)
acSet8bitFg | Set text foreground (8-bit color)
acSet8bitBg | Set text background (8-bit color)
acSetRgbFg | Set text foreground (r/g/b color)
acSetRgbBg | Set text background (r/g/b color)
acSetWebFg | Set text foreground (web-safe r/g/b)
acSetWebBg | Set text background (web-safe r/g/b)
acSetGreyscaleFg | Set text foreground (greyscale)
acSetGreyscaleBg | Set text background (greyscale)
acReset | Reset attributes and tracking data
`────` Text Modifiers `─────` | `─────────────────────────────────────────`
acSetMod | Set or reset a text modifier
acResetMods | Reset all text modifiers
acFullReset | Reset all colors and text modifiers
`───` Cursor Position `─────` | `─────────────────────────────────────────`
acSetCursor | Position the visible cursor
acGetCursor | Get current cursor position
acSetCursorStyle | Specify cursor shape
`─────` Input Methods `─────` | `─────────────────────────────────────────`
acRead | Read from stdin
acPause | Read and discard next keystroke
acWait | Pause for timeout or keystroke
acFlushIn | Flush the input stream (stdin)
`────` Output Methods `─────` | `─────────────────────────────────────────`
acWrite | Write formatted data to stdout
ttyWrite | Write unformatted data (TTY style)
acFlushOut | Flush the output stream (stdout)
acFlushStreams | Flush both input and output streams
`────` Text Erase `─────────` | `─────────────────────────────────────────`
acEraseArea | Erase specified area of terminal window
`────` Misc Methods `───────` | `─────────────────────────────────────────`
acBeep | Make some noise
nsleep | Put thread to sleep
acVersion | Get AnsiCmd class version number
acSetFont | Seldom supported alternate font
acSetIdeogram | Seldom supported line drawing
`────` API Methods `────────` | `─────────────────────────────────────────`
acSetAttributes | Set bit-field color and text-mod data
acComposeAttributes | Encode bit-field color and text-mods
acGetAttributes | Get decoded bit-field color/text-mods
acClearScreen | Erase all data from terminal window
acClearArea | Erase specified area of terminal window
acFormatParagraph | Automatic text formatting
acShellOut | Temporarily return to shell program
acDrawLine | Draw a horizontal or vertical line
acDrawBox | Draw a rectangle in the terminal window
acEraseBox | Erase a rectangular area of terminal
acBoxDraw | Display an AC_Box object in terminal
acBoxErase | Erase an AC_Box object from terminal
acBoxClear | Clear the interior of an AC_Box object
isSpecialKey | Compare to list of special keycodes
isCommandKey | Compare to list of command keycodes
acCreateTemppath | Enable support for temporary files
acDeleteTemppath | Disable support for temporary files
acCreateTempfile | Create a temporary file
acDeleteTempfile | Delete a temporary file
acClipboardEnable | Establish communications with clipboard
acClipboardDisable | Terminate communications with clipboard
acClipboardTest | Test communications with clipboard
acClipboardGetText | Retrieve data from the clipboard
acClipboardSetText | Copy data to the clipboard
acClipboardCharCnt | Reports number of chars on clipboard
acClipboardByteCnt | Reports number of bytes on clipboard
`──` Development Support `──` | `─────────────────────────────────────────`
ansiTest | Manage AnsiCmd library testing
getDataMembers | Get a copy of internal data members
getConfig | Get a copy of terminal configuration
tseReport | Report keycode processing

#### Configuration Methods

- AnsiCmd ( void );

        Input  : none

        Returns: implicitly returns a pointer to object

  Default Constructor: Terminal configuration parameters are set to default values.
  Please see TermConfig Class for details on default values.

  The usefulness of the default constructor is miniscule, and possibly full of surprises for the programmer and the user alike. It is strongly recommended that the initialization constructor (see below) be used for all non-trivial applications.

- AnsiCmd ( const TermConfig& tCfg );

        Input  : tCfg : (by reference) terminal configuration parameters

        Returns: implicitly returns a pointer to object

  Initialization Constructor: Terminal configuration parameters are passed in the TermConfig object.

  Configuration options can be established directly by the application startup code, or if preferred, can be specified by the user as command-line options, see Invoking.

  Please see TermConfig Class for details on parameter values passed to the constructor.

  Programmer’s Note: The AnsiCmd class should be instantiated before any data is sent to the terminal’s output stream. This is because the first output may override any subsequent output-stream width designation for the current session. Note that the wide (32-bit character) stream is strongly recommended for all modern applications. The narrow stream is outdated due to its close ties to ASCII text (and to 1970).

- virtual ~AnsiCmd ( void );

        Input  : none

        Returns: nothing

  Destructor. Return all resources to the system before exit.

  The destructor is invoked either by deleting the object:
  `AnsiCmd *ansicmdPtr = new AnsiCmd( termConfig );`
  `delete ansicmdPtr;`
  OR when the object goes out-of-scope.

- WinSize acGetTermSize ( void );

        Input  : none

        Returns: current terminal dimensions in a WinSize object

  Returns the terminal dimensions in both character cells and pixels.

  The WinSize structure is defined in `/usr/include/bits/ioctl-types.h`, and is one of the many system configuration parameters handled by the C-library `ioctl` function.

         struct winsize
         {
            unsigned short int ws_row;
            unsigned short int ws_col;
            unsigned short int ws_xpixel;
            unsigned short int ws_ypixel;
         };

  Note on terminal dimensions: Although the environment may contain the terminal dimensions when the application was invoked, this is a _copy_ of the environment, not the active environment, and therefore will not reflect user changes to the terminal window size while the application is active.

  The `$LINES` and `$COLUMNS` are available from the environment at the command line (“`echo $LINES`” and “`echo $COLUMNS`”), but are not exported to programs running in the terminal window.

  Note also that the pixel dimensions will probably be returned as zeros because under Wayland, the terminal program likely doesn’t know the screen resolution.

- bool acGetTermDimensions ( short& rows, short& cols );

        Input  : rows  : (by reference) receives number of terminal rows
                 cols  : (by reference) receives number of terminal columns

        Returns: 'true'  if terminal dimensions are known
                 'false' if system call to get terminal dimensions failed

  Reports the dimensions of the terminal window in rows and columns.

- bool acGetTermInfo ( TermStream tStream, TermIos& tIos, bool orig = false );

        Input  : tStream : one of stdIn, stdOut, stdErr
                 tios    : (by reference) receives settings
                 orig    : (optional, 'false' by default)
                           'false': the current terminal settings are returned
                           'true' : the original terminal settings are returned

        Returns: 'true'  if settings captured
                 'false' if system error

  Get a copy of the current terminal I/O stream configuration (or the original settings captured on application start-up).

  This is a pass-through to the private TermSet method.

  (This method is primarily for development and debugging.)

  Terminal I/O Setting structure (defined in C library, termios.h) struct termios { tcflag_t c_iflag ; /* input mode flags */ tcflag_t c_oflag ; /* output mode flags */ tcflag_t c_cflag ; /* control mode flags */ tcflag_t c_lflag ; /* local mode flags */ cc_t c_line ; /* line discipline */ cc_t c_cc[NCCS] ; /* control characters */ } ; tcflag_t is an unsigned integer (uint16_t) bit-field type. cc_t is an unsigned integer type (uint8_t) representing characters associated with various terminal control functions. 'NCCS' is a macro indicating the number of elements in the c_cc[] array. (this is 19 in /usr/include/asm-generic/termbits.h
- bool acSetLocale ( const char * localeName = NULL );

        Input  : (optional, null pointer by default)
                  If specified, pointer to name of UTF-8 compliant locale filename.
                  If null pointer (or empty string: "\0"), set locale from terminal
                  environment.

        Returns: 'true'
                  Currently, we do not verify that 'localeName' is a valid UTF-8
                  compliant locale filename.

  Set the "locale" for the application.
  By default, the application locale is taken from terminal environment.

  Type: `echo $LANG` at the command prompt to get the terminal’s locale. If desired, an alternate locale may be specified.

  For a complete listing of locales supported by your system, at the command prompt, type: `locale -a`

- const char* acGetLocale ( void );

        Input  : none

        Returns: pointer to locale name

  Returns a pointer to the name of the current locale.

- bool acSetStreamWidth ( bool widechar );

        Input  : widechar : select 'true' (wide stream) or 'false' (narrow stream)

        Returns: current state of character-width flag

  Set input/output streams’ character width.
  This determines which input/output streams will be used:

  wide stream: wcin/wcout narrow stream: cin/cout

  IMPORTANT NOTE: This method will have no effect if called after the application has performed I/O.
  The first input or output performed by the application locks in the character-stream width used for the application.
  C++ offers a way to set stream width directly (std::freopen), but it’s better to get it right the first time.

- bool acBufferedInput ( bool buffered, EchoOpt echoType, bool block = true );

        Input  : buffered : if 'true',  enable input buffering by the terminal
                            if 'false', disable buffering and allow local control
                                        over the input stream
                 echoType : member of enum EchoOpt:
                            referenced ONLY when 'buffered' == false
                            noEcho  : data from the stdin stream will not be echoed
                                      to the terminal window
                            termEcho: terminal echoes all stdin data to the window
                            softEchoA, softEchoC, softEchoD, softEchoE:
                                      terminal echo is disabled, but the acRead()
                                      methods will echo PRINTING characters to the
                                      terminal window according to the specific
                                      soft-echo sub-option.
                 block    : (optional, 'true' by default)
                            enable or disable blocking-read of input stream
                            referenced ONLY when 'buffered' == false
                            if 'true',  enable blocking read of stdin
                            if 'false', disable blocking read of stdin

        Returns: current state of the 'buffered-input' flag (inpBuf).

  Disable buffering so each keystroke can be received as soon as the key is pressed, or restore terminal’s control over input buffering.

  Normally, user input to the terminal (stdin) is buffered. That is, typed characters are stored in the terminal’s private input buffer and are returned to the application only when the ENTER key is pressed.

  In some circumstances, however, when a “Press any key to continue...” functionality is desired. Local control of the input buffer is also necessary when capturing ANSI sequences transmitted from the terminal in order to prevent cluttering the window with data which is meaningless to the user.
  See acRead for additional info.

  IMPORTANT NOTE: When buffering is enabled (buffered!=false), then the `'echoType'` and `'block'` parameters are ignored.

  - When buffering is enabled, termEcho is always enabled.
  - When buffering is enabled, blocking read of input is always enabled. Consequently, if modifying the echo option (acSetEchoOption) and/or the input-blocking option (acBlockingInput), then input buffering must have been disabled.

  #### Notes:

  1. The ’ICANON’ flag actually controls whether the terminal references `'VTIME'` and `'VMIN'` and how those values are interpreted.
  2. Buffering has no direct dependence on whether or not the characters are echoed when they arrive, and again, the ’ICANON’ flag determines whether the terminal references the ’ECHO’ flag’.
  3. Traditionally (and logically) echo is disabled when buffering is disabled. However, we provide an option to keep echo active while buffering is disabled.
  4. Echo should be disabled if the system is queried for a response in the form of an escape sequence (for instance, asking for the current cursor position). If echo is active, then it is likely that the printing characters in the the escape sequence will inappropriately be echoed to the screen.

     To bake a cake and eat it too, see the soft-echo option.

- bool acSetEchoOption ( EchoOpt echoType );

        Input  : echoType: member of enum EchoOpt:
                           noEcho   : data from the stdin stream will not be
                                      echoed to the terminal window
                           termEcho : terminal echoes all stdin data to the window

                           For the soft-echo options, terminal echo is disabled,
                           and echo of input characters to the display is
                           handled locally by the acRead() methods which will
                           echo all PRINTING characters to the display, and
                           will decode the "special keys" (cursor keys, etc.)
                           according to the specific soft-echo sub-option.
                           softEchoA: all special keys (default soft-echo option)
                           softEchoB: basic set of special keys
                           softEchoC: cursor-movement keys only
                           softEchoD: disable all special keys
                           softEchoE: edit keys only: Backspace, Delete, Insert,
                                      plus the Tab and Shift+Tab keys

        Returns: 'true'  if echo option modified
                 'false' if input buffering currently enabled (or invalid type)

  Select the input character echo type. (enum EchoOpt).

  Echo of user keyboard input (writing the received keycode to the display can be handled in a number of ways as listed above. The terminal can be allowed to decide what key input is echoed to the display, or the application can take control of key input to provide a smoother user interface.

  The “soft-echo” options are available for customizing the user interface.
  Please see Decoding the Special Keys for more information on the soft-echo options.

  This option is available ONLY when input buffering has been disabled. Please see acBufferedInput method for additional information.

- EchoOpt acGetEchoOption ( void );

        Input  : none

        Returns: current echo option: member of enum EchoOpt

  Get the current input-echo setting which describes how data from the input stream is processed.
  See TermConfig Class for a discussion of input-stream configuration options.

- bool acBlockingInput ( bool block );

        Input  : block : if 'true',  enable blocking read of input stream
                         if 'false', disable blocking read of input stream

        Returns: current state of the inpBlk flag
                 'true'  == blocking-read of stdin
                 'false' == non-blocking read of stdin
        Returns:

  Enable or disable blocking read from the input stream (stdin).
  This is a pass-through method for the TermSet function which sets/resets The blocking/non-blocking functionality.

  IMPORTANT NOTE: Non-blocking input requires that unbuffered input be enabled. If not already enabled, unbuffered input (with ’noEcho’) will be automatically enabled.

- bool acCaptureSignals ( EchoOpt eopt = softEchoA );

        Input  : eopt  : (optional, softEchoA by default)
                          specify one of the soft-echo options (enum EchoOpt)

        Returns: 'true'  if all settings successful
                 'false' if one or more settings failed

  Disable input buffering and capture all system signals generated by keyboard input.

  This method is provided as a housekeeping convenience, performing a common sequence of terminal setup operations:

  1. If input buffering has not yet been disabled, it will be disabled using the specified soft-echo option, and with non-blocking read of the input stream.
  2. The output flow control signals will be disabled.
     The Ctrl+S (stop flow) and Ctrl+Q (resume flow) control codes become ordinary keycodes: wcsCTL_S and wcsCTL_Q, respectively.
  3. The Break signal will be captured and converted to an ordinary keycode:
     `Break Signal : SIGINT - Ctrl+C` becomes wcsCTL_C
  4. The Suspend signal will be captured and converted to an ordinary keycode:
     `Suspend Signal: SIGTSTP - Ctrl+Z` becomes wcsCTL_Z
  5. The Quit signal will be captured so that the application will be terminated in an orderly manner.
     `Quit Signal : SIGQUIT - Ctrl+4` performs an orderly application shutdown
  Refer to the individual capture methods for details: acBufferedInput() acCaptureBreakSignal() acCaptureSuspendSignal() acCaptureQuitSignal()
- void acReleaseSignals ( void );

        Input  : none

        Returns: nothing

  Release all captured signals. Return control to the terminal software.

  Releases the following signals: `1) Break Signal : SIGINT - Ctrl+C` `2) Suspend Signal: SIGTSTP - Ctrl+Z` `3) Quit Signal : SIGQUIT - Ctrl+4`
- bool acCaptureBreakSignal ( bool enable, CCH_Type handlerType, bool alert, void* handlerAddr = NULL );

        Input  : enable : if 'true',  enable application capture of the break key
                          if 'false', disable application capture of the break key
                                      terminal handles the break signal
                 handlerType: (optional, cctDefault by default)
                              member of enum CCH_Type, specify the break-handler type.
                 alert      : (optional, 'false' by default)
                              Referenced only when 'handlerType' == cchIgnore.
                              Optionally sound a beep when the break signal is
                              received and discarded.
                              if 'false', silently discard the break signal.
                              if 'true',  beep when discarding the break signal.
                 handlerAddr: (optional, null pointer by default)
                              - by default, the internal AnsiCmd method,
                                BreakSignal_Handler() will provide an orderly response
                                to receipt of the break signal. See below for details.
                              - if the address of a handler method is specified, that
                                method will be activated by the break signal. That
                                method controls the response (if any) to the signal.
                                Note: The name of the target method is the address of
                                      that method.
                              This argument is referenced only if 'enable' is set.

        Returns: current state of capture flag
                 'true'  break key will be captured by the application
                 'false' break key will be handled by the terminal program

  Enable or disable application-level capture and processing of the BREAK key `(CTRL+C)`.

  By default, the terminal software processes the break signal by immediately killing the application which is running in the terminal window. While this is certainly an efficient and reliable way to terminate an application, it is grossly messy and potentially dangerous. For instance, what if the application is editing a critical system file when it is terminated in mid-update? Chaos.

  In contrast, if the application itself captures the break signal, the application can shut down in an orderly manner, ask the user what to do, or simply ignore the break signal.

  When local capture of the break signal is active, by default, the signal will be handled by the default (non-member) method, BreakSignal_Handler().

  The handler type is specified by the ’ccType’ member variable which is initialized here.

  #### Valid Handler Types:

  - cchtIgnore: Ignore the Ctrl+C key (default, cctDefault)
    Application will continue as if the signal had not been received.
  - cchtExit : Exit the application in an orderly way:
    1. the cursor will be placed on the bottom row of the terminal window and the row will be cleared,
    2. the terminal bell will sound,
    3. a short message will be displayed,
    4. the AnsiCmd destructor will be called, and
    5. the application will be terminated with a minus-one (-1) exit code.
  - cchtUser : Ask the user if they really want to exit the application:
    1. the terminal bell will sound,
    2. Clear a small area in the upper-right-hand corner of the terminal window. (This is assumed to be the least cluttered, least used area of the window.)
    3. Display a message asking the user to answer:
       `Exit? 'y'es or 'n'o: _`
    4. Wait for the user’s response.
  - cchtCopy : Convert the break signal to an ordinary keycode (wcsCTL_C) which may then be used in the common copy-and-paste sequence: `Ctrl+C --> Ctrl+V`.
  - cchtTerm : Local handler is disabled, so the local handler is not called.
- bool acCaptureQuitSignal ( bool enable );

        Input  : enable : if 'true',  enable application capture of the quit key
                          if 'false', disable application capture of the quit key
                                      terminal handles the signal

        Returns: current state of capture flag
                 'true'  quit key will be captured by the application
                 'false' quit key will be handled by the terminal program

  Pressing the `CTRL+4 key` (or the CTRL+\ key) generates the system Quit signal. If the system receives the Quit signal, it will immediately terminate the application and generate a “core dump” file.

  Core dump files are created in `/var/lib/systemd/coredump` by default. The format of the file should be ELF (Executable and Linkable) format, but could be an older format. An explanation of core dump files is beyond the scope of this document, but see the `'gdb'` (GNU Debugger) utility, which may be used to decode the contents of core-dump files.

  The Quit Signal is captured by default during configuration of the AnsiCmd class and its derived classes. Then when the Quit signal is received, `(CTRL+4 key)` the application is shut down in an orderly manner, and a core dump is not generated.
  The local Quit signal handler deletes the temporary files, releases dynamic memory allocations and performs general housekeeping chores. Before exiting the application, the bottom two rows of the terminal window are cleared and a message is written indicating that the application has been terminated.
  After all, we’re not just wild animals pooping in the forest. (well, most of us anyway :-)

  See Q option for specifying this option as a command line parameter.

  Technical Note:
  This signal is sometimes referred to as the Kill signal, but note that the Quit signal is technically different from the Kill signal in that the Kill signal cannot be captured or modified. It is an absolute command, and in fact, failure to respond to the Kill signal would be considered as a major system bug.

- bool acCaptureSuspendSignal ( bool enable );

        Input  : enable : if 'true',  enable application capture of the suspend key
                          if 'false', disable application capture of the suspend key
                                      terminal handles the suspend signal

        Returns: current state of capture flag
                 'true'  suspend key will be captured by the application
                 'false' suspend key will be handled by the terminal program

  Enable or disable application-level capture and processing of the SUSPEND key CTRL+Z. Signal name: SIGTSTP.

  If this signal is seen by the terminal program, it will suspend the active process. That is, it will put the process into the background and disable direct access to it. A different process may then occupy the foreground, interacting with the input and output streams.
  Use the ’fg’ utility to restore the hibernating process.

  Because Ctrl+Z is often used as a command (undo) within an application, this signal is captured by default and converted to an ordinary keycode: wcsCTL_Z.

- bool acRestoreTermInfo ( bool restoreAll );

        Input  : restoreAll : (optional, 'false' by default)
                              if 'false' this method restores input buffering,
                                 input echo, and blocking-read settings only.
                                 Break-handler, cursor style, and other terminal
                                 configuration options are not affected.
                              if 'true',  all terminal setting under control of
                                 the TermSet object will be returned to the states
                                 when the object was instantiated. (see list below)

        Returns: 'true' if settings restored
                 'false' if original settings not previously saved
                         or if system error

  Restore terminal stream settings to original values captured during the first access to the terminal settings. This probably occurred during creation of the TermSet-class object which is done as part of the AnsiCmd-class constructor sequence. The TermSet object manages the the current terminal settings. The settings restored depend on the state of the `'restoreAll'` flag, and include:

  1. Buffering of input stream.
  2. Echo option (see enum EchoOpt).
  3. Blocking vs. non-blocking read of input stream.
  4. Disable local break-key handler, if active.
  5. Set cursor style to terminal default.
- void breaksignalReceived ( int sigNum );

        Input  : sigNum: signal number to be handled
                         Currently, only the SIGINT (interrupt) is handled.
        Returns: nothing

  When the break signal has been captured, (see Capturing the Break Signal), this method is called by a non-member method specified as the dedicated CTRL+C signal handler. The handler type is specified by the ’ccType’ member variable which is set to one of the following:

  cchtIgnore: Ignore the Ctrl+C key (default, cctDefault) cchtExit : Exit the application in an orderly way. cchtUser : Ask the user if they really want to exit the application. cchtCopy : Push the literal value for Ctrl+C (0x03) back into the input stream. cchtTerm : Local handler is disabled, so this method is not called.
  `─ ─ ─ ─ ─ ─ ─ ─ ─ ─`

  This is technically a public method; however, it is called ONLY by the non-member method which handles receipt of the break-signal (CTRL+C).

- void suspendsignalReceived ( int sigNum );

        Input  : sigNum: signal number to be handled
                         Currently, only the SIGSTP (suspend) is handled.
        Returns: nothing

  When the suspend signal has been captured, (see acCaptureSuspendSignal), this method is called by a non-member method specified as the dedicated `CTRL+Z` signal handler.

  This method captures the signal and converts it to an ordinary keycode: wcsCTL_Z.

  `─ ─ ─ ─ ─ ─ ─ ─ ─ ─`

  This is technically a public method; however, it is called ONLY by the non-member method which handles receipt of the suspend-signal (CTRL+Z).

- void quitsignalReceived ( int sigNum );

        Input  : sigNum: signal number to be handled
                         Currently, only the SIGQUIT (quit) is handled.
        Returns: nothing

  When the quit signal has been captured, (see acCaptureQuitSignal), this method is called by a non-member method specified as the dedicated `CTRL+4` signal handler. The handler will then perform an orderly shutdown of the application, returning all resources to the system.

  `─ ─ ─ ─ ─ ─ ─ ─ ─ ─`

  This is technically a public method; however, it is called ONLY by the non-member method which handles receipt of the quit-signal (CTRL+4 or CTRL+\).

#### Color Attributes

- bool acSetFg ( aeSeq fg );

        Input  : fg   : foreground color attribute (member of aeSeq)

        Returns: 'true'  if valid color attributes specified and set
                 'false' if invalid parameter(s) specified
                         (attributes will not be modified)

  Set text foreground color attribute (3-bit and 4-bit color).

  This includes both the standard 3-bit and 4-bit attributes, as well as the non-standard IBM Corp. AIX extensions.

  Note: The AIX color attributes were defined by IBM to provide interoperability of the terminal interface between their proprietary systems (Aixterm) and the Linux/UNIX world. Although these attributes are not part of the `ANSI` standard, they are widely supported and provide basic foreground and background colors using a slightly different (brighter) combination of Red/Green/Blue register values. The differences are demonstrated in the color-attribute tests included with the AnsiCmd library. See Development and Testing for more information.
- bool acSetBg ( aeSeq bg, bool synth );

        Input  : bg   : background color attribute (member of aeSeq)
                 synth: (optional, 'true' by default)
                        if 'true',  use synthesized background color attributes
                        if 'false', use standard ANSI background color attributes

        Returns: 'true'  if valid color attributes specified and set
                 'false' if invalid parameter(s) specified
                         (attributes will not be modified)

  Set text background color attribute (3-bit and 4-bit color).

  This includes both the standard 3-bit and 4-bit attributes, as well as the non-standard IBM Corp. AIX extensions.
  (See note on AIX attributes, above.)

  > #### Note on synthesis of intense background color attributes

  > The default color attributes for intense (bold) backgrounds are inadequate because the
  > `'intense'` (`'bold'`) bit affects only the foreground color.

  > “Synthesized” bold backgrounds are used by default, which bypasses the ’bold’ flag problem by
  > using a member from the color lookup table which is outside the basic sixteen color (4-bit) group.

- bool acSetFgBg ( aeSeq fg, aeSeq bg );

        Input  : fg   : foreground color attribute (member of aeSeq)
                 bg   : background color attribute (member of aeSeq)

        Returns: 'true'  if valid color attributes specified and set
                 'false' if invalid parameter(s) specified
                         (attributes will not be modified)

  Set text foreground AND background colors (3-bit and 4-bit color).

  This includes both the standard 3-bit and 4-bit attributes, as well as the non-standard IBM Corp. AIX extensions.
  (See note on AIX attributes, above.)

  Programmer’s Note: The foreground is set AFTER the background so that if the ‘bold’ flag is used in the foreground escape sequence, it will not be masked by a subsequent non-bold background. Note also that bold background color escape sequences include the ‘bold’ flag, but unfortunately, because of the way the terminal interprets this flag, it affects only the foreground attribute. Exception: "synthesized" bold backgrounds are used by default, which bypasses the ’bold’ flag problem by using a different member from the color lookup table which is outside the basic sixteen (4-bit) color group.

- bool acSetFgBg ( acAttr fgbg );

        Input  :
           fgbg : foreground/background/modifiers
                  encoded as an acAttr bitfield

        Returns: 'true'

  Set text foreground/background colors using a value encoded as an acAttr bitfield value.
  Although the acAttr group of color attribute bitfields is defined for use within the AnsiCmd API; this method allows for color attributes to be specified using these encoded bitfield attributes regardless of whether the API code is compiled into the library.

  The specified value may be created directly as a logical OR of multiple members of the “acAttr” enumerated type.
  Example: `acAttr( acaFG_GREEN | acaBG_BLACK | acaUNDERLINE)`

  The bitfield value may also be built by a call to one of the acaExpand-class methods. See acaExpand class, for details.

  Note that this is a simplified version of the API method: ’acSetAttributes’, which is preferred when the API methods are available. This method should be used only if the library has been compiled without the API method group.

- bool acSet8bitFg ( uint8_t fg );

        Input  : fg : index into the lookup table for 8-bit color attributes

        Returns: 'true'  if valid color attribute specified and set
                 'false' if invalid parameter(s) specified
                         (attributes will not be modified)

  Set foreground color from 8-bit-color lookup table.
  Select an index number between min8BIT through max8BIT (16-231).

- bool acSet8bitBg ( uint8_t bg );

        Input  : bg : index into the lookup table for 8-bit color attributes

        Returns: 'true'  if valid color attribute specified and set
                 'false' if invalid parameter(s) specified
                         (attributes will not be modified)

  Set background color from 8-bit-color lookup table.
  Select an index number between min8BIT through max8BIT (16-231).

- bool acSetRgbFg ( uint8_t rReg, uint8_t gReg, uint8_t bReg );

        Input  : rReg : red value
                 gReg : green value
                 bReg : blue value

        Returns: 'true'  if valid R/G/B registers specified and set
                 'false' if specified parameters are out-of-range
                         (attribute will not be modified)

  Set foreground color using R/G/B register numbers.

  Each of the basic Red, Green and Blue color attributes may be displayed in any of 216 shades, and the color values may be in any combination.

  Each of the values may be specified as any register number between minRGB (16) and maxRGB (231).

  Smaller values indicate less saturation (darker colors), and larger values indicate greater saturation (lighter, more intense colors). If desired, the special value zero (0) may be used to indicate minimum saturation.

- bool acSetRgbBg ( uint8_t rReg, uint8_t gReg, uint8_t bReg );

        Input  : rReg : red value
                 gReg : green value
                 bReg : blue value

        Returns: 'true'  if valid R/G/B registers specified and set
                 'false' if specified parameters are out-of-range
                         (attribute will not be modified)

  Set background color using R/G/B register numbers.

  Each of the basic Red, Green and Blue color attributes may be displayed in any of 216 shades, and the color values may be in any combination.

  Each of the values may be specified as any register number between minRGB (16) and maxRGB (231).

  Smaller values indicate less saturation (darker colors), and larger values indicate greater saturation (lighter, more intense colors).

  If desired, the special value zero (0) may be used to indicate minimum saturation.

- bool acSetWebFg ( WebSafeRGB hue, uint8_t shade );

        Input  : hue   : member of enum WebSafeRGB
                         wsrgbBLACK   : black color index
                         wsrgbRED     : base color index (red color block)
                         wsrgbGREEN   : base color index (green color block)
                         wsrgbBLUE    : base color index (blue color block)
                         wsrgbBROWN   : base color index (brown color block)
                         wsrgbMAGENTA : base color index (magenta color block)
                         wsrgbCYAN    : base color index (cyan color block)
                         wsrgbGREY    : base color index (grey color block)
                         Remaining members of WebSafeRGB are reserved for other
                         purposes.
                 shade : intensity of the color specified by 'hue'
                         wsrgbSHADE_MIN <= shade <= wsrgbSHADE_MAX
                         where:
                         wsrgbSHADE_MIN == minimum saturation (subdued)
                         wsrgbSHADE_MAX == maximum saturation (brightest)

        Returns: 'true'  if valid hue and shade values specified
                 'false' if specified parameters are out-of-range
                         (attribute not be modified)

  Set foreground color using "web-safe" R/G/B register value combinations.

  #### What's a Web Safe? Spiderman's closet?

  In the early days of the internet and using early versions of color display hardware, it was necessary to define a set of color attributes that could be reliably duplicated on any standard hardware with any of the early graphics-based web browsers. (Yes, we used to surf the web using text-only browsers; but you must remember that like Mister Spock, we were trying to build a mnemonic memory circuit using stone knives and bear skins.)

  The solution was to create the so-called “web-safe” set of color attributes. This was done by creating a 6 x 6 x 6 matrix of Red/Green/Blue register values yielding 216 discrete colors. Conceptually, each color can take one of six hex values: `00 33 66 99 CC FF`. For each color, the actual index into the 256 entry color lookup table is selected according to this model. See `enum WebSafeRGB` for the way this mapping is done.

  In the modern world of “true-color” computing, the idea of web-safe colors is a bit outdated, but it is still a valid concept in the simpler world of console applications, where we are limited to the palette specified by the terminal configuration.

  Please see Development and Testing for a fuller discussion of the color attributes available to console applications.

- bool acSetWebBg ( WebSafeRGB hue, uint8_t shade );

        Input  : hue   : member of enum WebSafeRGB
                         wsrgbBLACK   : black color index
                         wsrgbRED     : base color index (red color block)
                         wsrgbGREEN   : base color index (green color block)
                         wsrgbBLUE    : base color index (blue color block)
                         wsrgbBROWN   : base color index (brown color block)
                         wsrgbMAGENTA : base color index (magenta color block)
                         wsrgbCYAN    : base color index (cyan color block)
                         wsrgbGREY    : base color index (grey color block)
                         Remaining members of WebSafeRGB are reserved for other
                         purposes.
                 shade : intensity of the color specified by 'hue'
                         wsrgbSHADE_MIN <= shade <= wsrgbSHADE_MAX
                         where:
                         wsrgbSHADE_MIN == minimum saturation (subdued)
                         wsrgbSHADE_MAX == maximum saturation (brightest)

        Returns: 'true'  if valid hue and shade values specified
                 'false' if specified parameters are out-of-range
                         (attribute not be modified)

  Set background color using "web-safe" R/G/B register value combinations.

  See acSetWebFg, above for a description of “web-safe” colors.

- bool acSetGreyscaleFg ( uint8_t shade );

        Input  : shade : brightness of grey color: minGSCALE <= shade <= maxGSCALE
                         example: acSetGreyscaleFg ( minGSCALE + 2 ) ;

        Returns: 'true'  if valid greyscale attribute specified and set
                 'false' if invalid parameter(s) specified
                         (attributes will not be modified)

  Set Greyscale foreground color attribute. (background unchanged)

  For systems that have at least 256 colors, 24 shades of greyscale intensity are available.
  These are accessed through indices 232-255 of the terminal’s 256-color lookup table.

- bool acSetGreyscaleBg ( uint8_t shade );

        Input  : shade : brightness of grey color: minGSCALE <= shade <= maxGSCALE
                         example: acSetGreyscaleBg ( minGSCALE + 2 ) ;

        Returns: 'true'  if valid greyscale attribute specified and set
                 'false' if invalid parameter(s) specified
                         (attributes will not be modified)

  Set Greyscale background color attribute. (foreground unchanged)

  For systems that have at least 256 colors, 24 shades of greyscale intensity are available.
  These are accessed through indices 232-255 of the terminal’s 256-color lookup table.

- bool acSetAixFg ( aeSeq fg );

        Input  : fg   : AIX foreground color attribute (member of aeSeq)

        Returns: 'true'  if valid color attributes specified and set
                 'false' if invalid parameter(s) specified
                         (attributes will not be modified)

  NOTE: This method is obsolete. See acSetFg.

- bool acSetAixBg ( aeSeq bg );

        Input  : bg   : AIX background color attribute (member of aeSeq)

        Returns: 'true'  if valid color attributes specified and set
                 'false' if invalid parameter(s) specified
                         (attributes will not be modified)

  NOTE: This method is obsolete. See acSetBg.

- bool acReset ( void );

        Input  : none

        Returns: 'true'

  Return all ANSI attributes to terminal defaults. Set all tracking members to their default values. Flush the input and output buffers.

  This method does not modify the terminal configuration. It resets only the ANSI control environment as defined by the set of escape sequences.

  Programmer’s Note: It is not possible to programatically check whether each attribute was actually reset; however, the ANSI reset escape sequence should be trustworthy.

#### Text Modifiers

- bool acSetMod ( aeSeq mod );

        Input  : mod  : text modification attribute (member of aeSeq)

        Returns: 'true'  if valid modifier attributes specified and set
                 'false' if invalid parameter(s) specified
                       (attributes will not be modified)

  Set or reset the specified text modifier.

  Any text written after setting a modifier using this command will be displayed using the specified modifier (bold, italic, etc.). Any text written after resetting a modifier will be displayed without the specified modifier.

  See acResetMods method below for a list of valid text modifiers.

- void acResetMods ( bool full );

        Input  : full: (optional, 'false' by default)
                       if 'true',  write a reset command instead of writing
                                   the ANSI modifier-off sequences.
                                   This option is available in case the host
                                   terminal does not support some or all of the
                                   modifier-off sequences.
                                   NOTE: this ALSO resets the color attributes.
                       if 'false', write only the individual modifier commands,
                                   do not write the reset command

        Returns: nothing

  Reset all text modifiers, leaving the base foreground and background color attributes unchanged.

  The text modifier attributes are:

        aesBOLD,          // bold (increase intensity)
        aesFAINT,         // faint/dim (decrease intensity)
        aesITALIC,        // italic (or inverse)
        aesUNDERLINE,     // underline
        aesBLINK_SLOW,    // slow blink
        aesBLINK_FAST,    // fast blink
        aesREVERSE,       // reverse foreground and background colors
        aesCONCEAL,       // hide text
        aesXOUT,          // crossed out text (marked for deletion)
        aesFRACTUR,       // a variety of German calligraphy
        aesDBL_UNDERLINE, // double-underline (or bold off)
        aesFRAMED,        // "frame" the text
        aesENCIRCLE,      // "encircle" the text
        aesOVERLINE,      // overlined text

  Calling this method is equivalent to calling acSetMod() nine times, once for each of the modifer resets.

        aesBOLD_OFF,      // normal intensity (neither bold nor faint)
        aesITALIC_OFF,    // italic off (and Fractur off)
        aesUNDERLINE_OFF, // not underlined
        aesBLINK_OFF,     // not blinking
        aesREVERSE_OFF,   // not reversed
        aesCONCEAL_OFF,   // conceal off
        aesXOUT_OFF,      // not crossed out
        aesFRM_ENC_OFF,   // not framed, not encircled
        aesOVERLINE_OFF,  // overline off

- bool acFullReset ( bool enable );

        Input  : enable : 'true' to enable full reset for attribute modifications
                          'false' to disable full reset and rely upon the
                                  setting/resetting the flag which controls the
                                  specific attribute being modified

        Returns: current state of the full-reset flag

  Enable or disable reset of all ANSI display attributes before modifying a text attribute.

  The AnsiCmd class is constructed so that when modifying an ANSI parameter other parameters will be affected as little as possible. Specifically, when enabling or disabling an attribute such as Bold, Underline, etc., the intent is to avoid disturbing the existing forground and background color settings.

  However, some console software or their underlying system software may not support all of the single-attribute commands such as aesBOLD_OFF, aesITALIC_OFF, aesUNDERLINE_OFF, aesBLINK_OFF aesREVERSE_OFF, aesCONCEAL_OFF, aesXOUT_OFF, aesFRM_ENC_OFF, aesOVERLINE_OFF, aesIDEO_OFF.

  If these reset commands are not supported on a given platform, then set the ’fullReset’ flag, and the AnsiCmd class will use the full reset command, aesRESET when changing terminal settings. The aesRESET command is supported by nearly all terminal emulators.

  See Invoking - Terminal Setup (`-A option`) which enables the full-reset flag as part of the startup sequence.

#### Cursor Positioning

> #### Important Note On Cursor Positioning

> Cursor positions within a terminal window are always defined as offsets from some reference position. In general, offsets are relative to the upper-left corner of the terminal window, also known as the “origin”.
> The terminal window origin is defined as position `1:1` (not the logically correct `0:0`).

> Unfortunately, the developers of terminal software and the authors of the `ANSI` commands and other utilities are not always on the same page regarding whether cursor offsets should be `0-based` or `1-based`. Be aware that a zero(0) value may be silently converted to a one(1) value, OR it may cause an operation to fail, or worse, produce unexpected results.

> The AnsiCmd cursor-positioning methods will accept an “absolute” value of zero and silently convert it to a one(1). This prevents artifacts such as unexpected scrolling or pushing text out of the window. However, be aware that not all utilities are so user friendly. Be aware!

- bool AnsiCmd::acSetCursor ( aeSeq curcmd, short arga, short argb ) const;

        Input  : curcmd: one of the members of the cursor-positioning group which
                         are included in enum aeSeq.
                         Example: acSetCursor ( aesCUR_HOME ) ;
                 arga  : (optional, 1 by default)
                         for options which require arguments, 'arga' specifies the
                         first argument.
                         Example: acSetCursor ( aesCUR_ABSCOL, 30 ) ;
                 argb  : (optional, 1 by default)
                         for options which require arguments, 'argb' specifies the
                         second argument.
                         Example: acSetCursor ( aesCUR_ABSPOS, 12, 60 ) ;

        Returns: 'true'  if valid cursor command (and valid arguments, if required)
                 'false' if invalid parameter(s) specified
                         (position will not be modified)

  Set cursor position within terminal window.

  Some ANSI cursor commands perform cursor movements relative to the current position, while other commands set the cursor at an absolute position within the terminal window.

  See cursor offsets above regarding 1-based vs. 0-based cursor positioning.

  This method invokes the specified `ANSI` escape sequence directly; however, there are two variations on this method, described below, which may also be used to set the cursor position. Please choose the one that best suits your needs.

  > NOTE: One member of the cursor-positioning group: aesCUR_REPORT, is not handled by this method.
  > Instead please see acGetCursor. If aesCUR_REPORT is received, it will be ignored and ’false’ will be
  > returned to indicate that the request was not handled.

  > Also:
  > Digital Equipment Corporation (DEC) and the SCO Group (UnixWare) defined some of the
  > cursor-management commands differently. On our test systems, the SCO commands work correctly,
  > while the DEC commands do not. Your mileage may vary.

- bool AnsiCmd::acSetCursor ( short row, short col ) const;
- bool AnsiCmd::acSetCursor ( const WinPos& wp ) const;

        Input  : One of the following:
                    row : target row
                    col : target column
                 or:
                    wp  : (by reference) target row and column

        Returns: 'true'  if specified row/column are within the terminal window
                 'false' if invalid position (cursor position not modified)

  Set absolute cursor position within terminal window.

  These methods reformat the parameters and call the low-level acSetCursor method described above.

- WinPos acGetCursor ( void ) const;

        Input  : none

        Returns: an initialized WinPos object
                 (If system error or parsing error, window origin is returned.)

  Get the current cursor position within terminal window.

  #### Technical Notes

  This method requires that input buffering be disabled and that input echo be set to ’noEcho’. The reason for this is that when buffering is active, the response from the terminal will not become available to the application until the Enter key is detected in the input stream.
  In addition, echo of input characters to the terminal window must also be disabled because when the system writes the response to the position query, it is written to stdin, which if echo were enabled would likely trash the currently-displayed text, or at minimum would move the cursor, causing a big surprise at the application level. While setting and restoring the buffering/echo options is an expensive operation in terms of CPU cycles, it is necessary for smooth operation at the application level.

      -- Write the ANSI sequence requesting the current cursor position.
      -- Read the response (binary data) from stdin.
      -- Decode the response which is of the form: 1B 5B (row) 3B (col) 52
           1B       escape character
           5B       left square bracket
           row      one or more ASCII numeric chars indicating row number
           3B       ';' (ASCII semicolon)
           col      one or more ASCII nummeric chars indicating column number
           52       ASCII 'R'

- bool acSetCursorStyle ( CurStyle style, aeSeq color );

        Input  : style : member of enum CurStyle
                 color : (optional, default from terminal profile)
                         member of aeSeq, foreground attribute group: aesFG_xxx
                         color attribute for cursor [CURRENTLY IGNORED]

        Returns: 'true' if valid argument(s), else 'false'

  Set cursor type i.e. the shape of the cursor.

  Three basic cursor shapes are available in either a steady state or blinking:
  `Block:'█' Underline:'▁' Vertical Bar:'▎'`

  In addition, the cursor can be made invisible. The style is specified as a member of `enum CurStyle` which is the parameter for the escape sequence to be transmitted. (Note that cursor style settings are not part of the `ANSI` standard.)

        csBblock = 0,  // Full-character cell, blinking block
        csDflt   = 1,  // Cursor type defined by terminal configuration
        csSblock = 2,  // Full-character cell, steady (non-blinking) block
        csBuline = 3,  // Blinking underline
        csSuline = 4,  // Steady underline
        csBvbar  = 5,  // Blinking vertical bar
        csSvbar  = 6,  // Steady vertical bar
        csHide   = 7,  // Hide cursor (make it invisible)
        csShow   = 8,  // Show cursor (make it visible)

  Note on cursor blink timeout: Although the cursor shape and blinking/steady status can be specified using this method, the terminal settings specify a timeout on the blinking status. For instance, the Gnometerm terminal emulator specifies a default timeout on the cursor’s blink status of ten(10) seconds. This timeout can be adjusted using the “gsettings” utility. Example: Get current settings: gsettings get org.gnome.desktop.interface cursor-blink-timeout Report the range of valid values: gsettings range org.gnome.desktop.interface cursor-blink-timeout Set a new timeout of 25 seconds: gsettings set org.gnome.desktop.interface cursor-blink-timeout 25

  Note: The cursor color attribute is automatically set by the terminal to the same color as the text. Theoretically, the `"gsettings"` utility and other utilities can also be used to set the cursor color, but early testing shows that such commands are ignored. Testing continues.

#### Input Methods

- short acRead ( gString& gsIn, short limit ) const;

        Input  : gsIn  : (by reference) receives captured text (null terminated)
                 limit : (optional, size of gString object by default)
                         If specified, 'limit' indicates the maximum number of
                         characters (wide-stream input) OR the maximum number of
                         bytes (narrow-stream input) that will be extracted from
                         the stdin buffer.
                         Important Note: This argument is referenced only when
                         unbuffered input is active. This argument is ignored
                         when input-stream buffering is enabled.

        Returns: number of characters captured (NOT the number of bytes)

  Capture user input as a sequence of characters terminated by the Enter key, OR when input buffering is disabled and the number of characters specified by the `'limit'` parameter has been reached.

  Internally, this method loops a call to the single-character `acRead` (see below). The called method contains most of the intelligence of the operation.

  #### Note on capture of the Enter key

  - If the Enter key is the first and only keycode captured, the Enter keycode is returned and the character count returned will be one(1).
  - If the input is terminated by the Enter key, the characters captured before the Enter key are returned. The Enter keycode will not be returned and is not included in the character total.

  Please see Soft Echo Options for a discussion of when and how key input is echoed to the display.

- wchar_t acRead ( void ) const;

        Input  : none

        Returns: keycode from user

  Capture a single keystroke from the user.

  The functionality of this method is dependent upon three factors:
  `1)` Whether input buffering is enabled,
  `` (see acBufferedInput)
  `2)` The active input echo option,
  `` (see Soft Echo Options)
  `3)` Whether input is configured for blocking or non-blocking read.
  `` (see acBlockingInput)
  Please study these options carefully and configure the input stream according to the needs of your application. A good place to start would be with 1) unbuffered input, 2) softEchoA, and 3) blocking read.

- wchar_t acPause ( bool nl = false ) const;

        Input  : nl : (optional, default: false)
                      if 'true',  after user keypress, output a newline character
                      if 'false', no output will be written to display

        Returns: keycode from user

  Wait for user to press a key. This is an unbuffered read, with no echo of the keycode to the display. Typically, this method would be used after the application displays a ’press any key’ or similar message.

  The optional `'nl'` parameter may be used to write a newline character `(NEWLINE (0x000A)` to the display after the user presses any key. This will move the cursor to the leftmost column of the next row. This option should be used only when the application is writing directly to the terminal window, and not when formatted (ACWin-class) data are being displayed.

  Technical Note: After the keycode is received, the input stream is flushed, that is, any data remaining in the input buffer is read and discarded. This is done to protect against stale data being left in the buffer in case the key pressed by the user generates an escape sequence or another multi-byte sequence. If the initial keycode received is the Escape keycode `(0x001B)`, the keycode for the space key `wcsSPACE (0x0020)` will be returned instead.

- void acWait ( uint16_t seconds ) const;

        Input  :
           seconds : specifies the sleep interval in seconds (1 minute max)
                     0 <= seconds <= 60

        Returns: nothing

  Pause for a specified amount of time OR until user presses a key.
  This can be thought of as a combination of the `acPause` and `nsleep` methods.

  The specified delay is broken into segments and after each delay segment, the input stream is pinged to determine whether user has pressed a key.
  The pause continues until either the full pause interval is complete, or until user presses any key, whichever comes first.

  Any keycode received is discarded, and before return, the input stream is flushed to avoid abandoning any stale data in the input stream.

- void acFlushIn ( void ) const;

        Input  : none

        Returns: nothing

  Flush stdin, (the active input stream, wcin or cin).
  Any data still in the input stream will be discarded.

  #### Note On Performance

  Flushing the input buffer relies on an unbuffered input stream to reliably extract the stale data from the stream. If input buffering is enabled when this method is called, this method disables buffering before the flush and re-enables buffering after the flush.
  While this is effective, it does produce a small performance hit. For this reason, it is recommended that unless there is a clear reason to do otherwise, the application should disable input buffering during startup and then re-enable buffering just before exit.
  Please see acBufferedInput for more information.

  See also acFlushStreams, below.

#### Output Methods

- WinPos acWrite ( WinPos wp, const gString& gsTxt, bool flush = true ) const;
- WinPos acWrite ( short row, short col, const gString& gsTxt, bool flush = true ) const;
- WinPos acWrite ( WinPos wp, const wchar_t* wTxt, bool flush = true ) const;
- WinPos acWrite ( short row, short col, const wchar_t* wTxt, bool flush = true ) const;
- WinPos acWrite ( WinPos wp, const char* cTxt, bool flush = true ) const;
- WinPos acWrite ( WinPos wp, wchar_t wchar, bool flush = true ) const;
- WinPos acWrite ( short row, short col, wchar_t wchar, bool flush = true ) const;
- WinPos acWrite ( WinPos wp, char cbyte, bool flush, bool newln ) const;
- WinPos acWrite ( short row, short col, char cbyte, bool flush = true ) const;

        Input  : starting cursor position in one of the following formats:
                    wp    : a WinPos object (by reference)
                          OR
                    row   : target row
                    col   : target column

                 text data to be written in one of the following formats:
                    gsTxt : (by reference) a gString object
                          OR
                    wTxt  : a wchar_t string (32-bit characters)
                          OR
                    cTxt  : a char (byte) string
                          OR
                    wchar : a single wchar_t (wide) character
                          OR
                    cbyte : a single byte

                 flush : (optional, default: 'true')
                         if 'true,   flush the output buffer before return
                         if 'false', do not flush the output buffer

        Returns: current cursor position (WinPos object)

  Write text data to `stdout` beginning at the specified cursor position. The final cursor position is at the end of the output. This is the return value.

  > > This method is not reliable for writing ANSI escape sequences and ASCII control codes. For these special cases, use the `'ttyWrite'` method below.

  The primary difference between this method and traditional TTY-style output is that newline (`'\n'`) characters are handled as a special case. When a newline character is encountered in the output stream, it causes the cursor to be placed on the next row at the same column as the first column of the previous row. This automatic formatting allows the application to write formatted paragraph data without the painful task of having to count columns. (“You’ll thank me later.” — Adrian Monk)

  This method is actually a group of overloaded methods which provide flexibility in the way parameters are passed.

  Cursor position may be specified either as a WinPos object or as seperate row and column values.

  The source text may be formatted as:

  1. a gString object,
  2. a wchar_t (UTF-32) character array,
  3. a char (UTF-8) character array, or
  4. a single character

  By default, the output buffer is flushed after all data have been written. This is equivalent to the C++ sequence:
  `wcout << "text_data" ;`
  `wcout.flush() ;`
  However, flushing the output buffer is a slow operation (relatively speaking), so if multiple writes are performed in sequence, it is more efficient to flush the stream only once, after the last write of the sequence. For example, the following sequence writes three text strings, each in a different color, with the `'flush'` flag set (default value) for the last write.
  `WinPos wp( 4, 30 ) ;`
  `acSetFg ( aesFG_RED ) ;`
  `wp = acWrite ( wp, "Red textdata.\n", false ) ;`
  `acSetFg ( aesFG_BLUE ) ;`
  `wp = acWrite ( wp, "Blue text data.\n", false ) ;`
  `acSetFg ( aesFG_GREEN ) ;`
  `wp = acWrite ( wp, "Green text data.\n" ) ;`

  Note that this method is aware of the terminal window dimensions.

  1. Text rows which would overrun the right edge of the terminal window are truncated,
     that is, automatic line wrap does not occur.
  2. Text data that would overrun the bottom edge of the terminal window will be ignored.
     Scrolling of the window contents WILL NOT occur.

  If automatic scrolling or automatic line wrap are desired, then call the ttyWrite method instead.

  Note that the width of the output stream (wide or narrow stream) is established during the application startup sequence; therefore, regardless of the width of the source data, it will be transmitted using the established stream width.
  Please see acSetStreamWidth, or the W option command-line option for more information on stream configuration.

- void ttyWrite ( const gString& gsTxt, bool flush = true, bool nl = false ) const;
- void ttyWrite ( const wchar_t* wTxt, bool flush = true, bool nl = false ) const;
- void ttyWrite ( const char* cTxt, bool flush = true, bool nl = false ) const;
- void ttyWrite ( const uint_8* uTxt, bool flush = true, bool nl = false ) const;
- void ttyWrite ( wchar_t wchar, bool flush = true, bool nl = false ) const;
- void ttyWrite ( char cbyte, bool flush = true, bool nl = false ) const;

        Input  : text data to be written in one of the following formats:
                    gsTxt : (by reference) a gString object
                          OR
                    wTxt  : a wchar_t string (32-bit characters)
                          OR
                    cTxt  : a char (byte) string
                          OR
                    uTxt  : a UTF-8 (byte) string
                          OR
                    wchar : a single UTF-32 character
                          OR
                    cbyte : a single byte (generally: an ASCII control code)
                 flush : (optional, 'true' by default)
                         if 'true,   flush the output buffer before return
                         if 'false', do not flush the output buffer
                 nl    : (optional, default: 'false')
                         append a newline character to the output

        Returns: nothing

  Write text data (or ANSI sequence) to stdout beginning at the current cursor position. This emulates the action of a teletype machine (TTY).
  (If you don’t know what a teletype machine is, your grandparents will explain it to you.)

  Any newline characters encountered will cause the cursor to be positioned on the first (leftmost) column of the line below, and if on the last line in the window, all data will be scrolled upward.
  Text will automatically wrap at the right edge of the window.

  This method is actually a group of overloaded methods which provide flexibility in the way parameters are passed. The source text may be formatted as

  1. a gString object,
  2. a wchar_t (UTF-32) character array,
  3. a char (UTF-8) character array, or
  4. a single character

  By default, the output buffer is flushed after all data have been written. This is equivalent to the C++ sequence:
  `wcout << "text_data" ;`
  `wcout.flush() ;`
  However, flushing the output buffer is a slow operation (relatively speaking), so if multiple writes are performed in sequence, it is more efficient to flush the stream only once, after the last write of the sequence. For example, the following sequence writes three text strings, each in a different color, with the `'flush'` flag set (default value) for the last write.
  `acSetCursor ( 4, 1 ) ;`
  `acSetFg ( aesFG_RED ) ;`
  `ttyWrite ( "Red textdata.\n", false ) ;`
  `acSetFg ( aesFG_BLUE ) ;`
  `ttyWrite ( "Blue text data.\n", false ) ;`
  `acSetFg ( aesFG_GREEN ) ;`
  `ttyWrite ( "Green text data.\n" ) ;`

  Note that the width of the output stream (wide or narrow stream) is established during the application startup sequence; therefore, regardless of the width of the source data, it will be transmitted using the established stream width.
  Please see acSetStreamWidth, or the W option command-line option for more information on stream configuration.

- void acFlushOut ( void ) const;

        Input  : none

        Returns: nothing

  Flush stdout, (the active output stream, wcout or cout).
  Any data still in the output stream will be written to the terminal window.

  Note that the output methods acWrite and ttyWrite by default, flush the output stream at the end of each write. The `acFlushOut` method may be used to explicitly flush the data from the stream.

  See also acFlushStreams, below.

- void acFlushStreams ( void ) const;

        Input  : none

        Returns: nothing

  Flush (write) any data in the `stdout` stream and discard an stale data in the `stdin` stream.

  This method combines calls to acFlushIn and acFlushOut as described above.

  Technical Note: Although every effort has been made to clear the `I/O` buffers as needed, transmission and receipt of `ANSI` escape sequences can be interrupted or broken, causing display artifacts or other problems. Explicitly flushing the buffers at critical moments can help to reduce such accidents.

#### Text Erase

- bool acEraseArea ( aeSeq area, short rowOff, short colOff );

        Input  : cur   : one of the members of the text-erasure group within
                         enum aeSeq.
                         example: acEraseArea ( aesERASE_WIN ) ;
                 rowOff: (optional, ZERO by default) If a non-zero value is
                         specified, the cursor will be shifted upward (negative
                         values) or downward (positive values) from the current
                         cursor position before the erasure occurs.
                 colOff: (optional, ZERO by default) If a non-zero value is
                         specified, the cursor will be shifted leftward (negative
                         values) or rightward (positive values) from the current
                         cursor position before the erasure occurs.

        Returns: 'true' if successful
                 'false' if invalid parameter(s) specified

  Erase the specified area of the terminal window.
  The area to be erased is specified by one of the ANSI erasure commands.
  `aesERASE_BOW, //` erase from cursor to bottom of window
  `aesERASE_TOW, //` erase from cursor to top of window
  `aesERASE_WIN, //` erase entire window (’clear’)
  `aesERASE_SAVED, //` erase "saved" lines
  `aesERASE_EOL, //` erase from cursor to end of line
  `aesERASE_BOL, //` erase from cursor to beginning of line
  `aesERASE_LINE, //` erase entire line
  The specified erasure is performed relative to the current cursor position UNLESS an offset is specified:
  `rowOff :` row offset from current row
  `colOff :` column offset from current column
  Important Note: If the specified offset moves the cursor beyond the edge of the terminal window, unexpected side-effects may occur.

  See also the direct erasure method, acClearArea.

#### Misc Methods

- void AnsiCmd::acBeep ( short repeat, short delay, int freq ) const;

        Input  : repeat : (optional, 1 by default) repeat count
                          Range: 1 - 32,767
                 delay  : (optional, 5 by default i.e. 1/2 second)
                          delay between successive beeps in tenths of a second
                          in the range: 2 - 600 (0.2sec through 1.0min)
                          Note: The system is unable to handle short delays, so
                                a delay of two-tenths second is the safe minimum.
                 freq   : (optional, -1 by default)
                          if specified, this is the auditory frequency of the beep
                          [CURRENTLY IGNORED]

        Returns: nothing

  Invoke the console’s default auditory alert (beep).

  When called without parameters, the `acBeep` method produces a single beep (or whatever sound your terminal is set up to produce when the `ASCII Bell` control code is received.

  Three optional parameters are available: `'repeat', 'delay', and freq'` as shown above.

  The `repeat` parameter is straightforward, specifying the number of individual beeps to produce from 1 (default) to 32,767, although we can attest that anything over about 200 will cause everyone in your household to toss the nearest loose object in your direction.

  The `delay` parameter specifies the (approximate) pause between beeps. The quality and repeatability of the tone is heavily dependent upon the delay between beeps. This is because the the actual physical timer used and the system code which controls it are both shared resources.
  The delay interval may be specified as a multiple of 0.10 (1 tenth) second, with the default being 0.5 (5 tenths) second, and the maximum being one minute (600 tenths). For a stable repeatable sound, the practical minimum is two or three tenths (0.2 - 0.3) of a second.

  The `freq` parameter specifies the frequency of the tone that will be produced. For the current (pre)release, this parameter is ignored, and the tone is produced by simply issuing the `ASCII Bell` control code.
  For the production release, however, we hope to implement a more robust and flexible sound control.

- void AnsiCmd::nsleep ( uint16_t tenths, uint16_t millisec, time_t nanosec ) const;

        Input  : tenths  : specifies the sleep interval in tenths of a second
                           (1/10 sec == 0.10 sec)
                 millisec: (optional, zero by default) for finer control over the
                           length of the delay, specify a delay in milliseconds.
                 nanosec : (optional, zero by default) for even finer control over
                           the length of the delay, specify a delay in nanoseconds.
                           [CURRENTLY IGNORED]

        Returns: nothing

  Sleep (pause) execution for the specified time period. This method encapsulates access to the C-language `'nanosleep'` function. It is intended to simplify the the interface and replaces direct calls to the obsolete C-language `sleep` and `usleep` functions.

  The primary delay value is specified in tenths of a second (0.10sec), with a secondary delay specification in milliseconds (0.001sec). The sum of the two values specifies the total duration of the delay.
  Thus the effective minimum delay is 1 millisecond, while the theoretical maximum delay is: 65535/10 or 6553 minutes + 65535 milliseconds or approximately 6618 minutes.This is an impractically large number, so we arbitrarily limit the maximum delay to 61 minutes, which is approximately 60 minutes more than anyone will likely ever need.
  `1 millisecond <= delay <= 61.0 minutes`
  Note that the `'nanosec'` parameter is currently ignored. (see tech notes below)

  The philosophy here is that delays of less than one tenth of a second are not very useful for a human interface, while smaller delays are oriented toward computer-oriented tasks and which are limited only by the resolution of the clock referenced by the called function.

  #### Technical Notes

  In C++, the cosmopolitan way to delay the action is to use the `'chrono'` class to define the delay, and the `'sleep_for'`
  method to execute it.
  `Example: chrono::duration<short>aWhile( 10 );`
  `this_thread::sleep_for( aWhile );`
  `Example: chrono::duration<short, std::milli>aMoment( 250 );`
  `this_thread::sleep_for( aMoment );`
  The `chrono/sleep_for` C++ implementation is much cleaner and more intuitive than nanosleep(); however, `ANSI` escape sequences are by definition incompatible with multi-threaded environments, so we do not introduce multi-threading in the AnsiCmd class.
  Instead, we use the `'nanosleep'` function which is technically sophisticated, but clunky in implementation. That is why we isolate it here to avoid cluttering up our otherwise lovely code.

  The `nanosleep` C-library function is defined in `time.h` and takes as parameters two `'timespec'` structures as shown.

  #include <time.h> struct timespec { time_t tv_sec ; /* seconds */ long tv_nsec ; /* nanoseconds */ }; nanosleep ( const struct timespec *req, struct timespec *rem ) ;

  The first parameter `'req'` (the ‘request’) specifies the duration of the sleep interval in seconds and nanoseconds. Note that the `nanosleep` function rounds the nanosecond value `('tv_nsec')` upward to the resolution of the clock. Note also that the `('tv_nsec')` value is limited to 9,000,000,000 (nine billion nanoseconds). Any larger value will generate an error.

  If the requested interval is completed without interruption, the second parameter `('rem')` (the ‘remainder’) remains unused. If however, the sleep interval is interrupted by some system event, then the second parameter receives the remainder of the delay so that `nanosleep` can be called again to complete the specified sleep interval.

  The resolution of the clock used for this interval is also a significant factor in the accuracy of the operation.
  It is important to keep in mind that although `nanosleep` claims to be accurate in the nanosecond range, a number of factors may affect the results. For instance, the default Linux scheduler is based on ten-millisecond intervals, so sequential calls may be limited to this resolution. Some newer systems with newer kernel support may be able to provide a resolution of one(1) millisecond.

  See the documentation for the C-library `'clock_getres'` function for more information on the clocks available on the host system.
  See also: `"man 7 time"`, which indicates that the effective resolution is between 1 and 10 milliseconds.
  Also see the resolutions specified in the file: `"/proc/timer_list"`. Most of the entries in that file specify a resolution of 1 nanosecond, but we see this as more aspirational, than mathematical.

  While the `nanosleep` function cannot be relied upon by timing-critical operations which may be affected by these factors, for user-oriented delays, into the tens-of–milliseconds range, however, the `nanosleep` function is a welcome addition to the C-language library.

- const char * acVersion ( void ) const;

        Input  : none

        Returns: pointer to version string

  This method return a const pointer to a string containing the AnsiCmd class version number. The version number takes the form: `x.y.zz`, where `'x'` is the major version, `'y'` is the minor version and `'zz'` is the step version.
  Example: `0.0.03`

  Unlike some other developers whom we will politely not name (Firefox), this author does not advance the major or minor version number without a very good reason. Therefore, even packages we have had in circulation for twenty years seldom advance beyond version `0.2.00`. For instance, the `gString class` distributed with package, which we first released in 2011 is now at version `0.0.32`, and yes, it is absolutely solid.

- bool AnsiCmd::acSetFont ( aeSeq font, uint8_t fontnum );

        Input  : font   : one of aesPRIMARY_FONT or aesALTERNATE_FONT which are
                          members of enum eSeq.
                 fontnum: (optional, zero(0) by default)
                          specify the alternate font, range: 1 through 9

        Returns: 'true'  if valid greyscale attribute specified and set
                 'false' if invalid parameter(s) specified
                         (attributes will not be modified)

  Specify the terminal font used to write subsequent text data.

  Specify the `'font'` parameter as a member of enum aeSeq:

  aesPRIMARY_FONT set the primary font as the active font ('fontnum' parameter is ignored) aesALTERNATE_FONT set one of the alternate fonts as the active font USER# 1 2 3 4 5 6 7 8 9 translates to: ANSI# 11 12 13 14 15 16 17 18 19

  These commands are not recognized on any of our development platforms, but the font test is available for testing them on your particular system: (see Test_AltFonts).

- bool acSetIdeogram ( aeSeq idea );

        Input  : idea  : member of enum aeSeq within the ideogram-command group.

        Returns: 'true'  if valid argument
                 'false' if invalid parameter(s) specified
                         (attribute will not be modified)

  Interface to the seldom-supported and little-used "ideogram" (logogram) group of `ANSI` commands.

  It is unclear what this group of commands was originally intended to do. Presumably they were intended to provide some kind of border or highlighting around a block of text.
  `aesIDEO_UNDER //` ideogram underlined
  `aesIDEO_UDOUBLE //` ideogram double-underlined
  `aesIDEO_OVER //` ideogram overlined
  `aesIDEO_ODOUBLE //` ideogram double-overlined
  `aesIDEO_STRESS //` ideogram stress marking (italic?)
  `aesIDEO_OFF //` all ideogram attributes off
  These are probably non-functional, but they can be tested using this method.

  See acDrawBox and acDrawLine methods for line drawing options.

#### API Methods

The `API` (Application Programming Interface) methods are designed to encapsulate some of the more common operations performed as a sequence of calls to the low-level primitive methods. Using the `API` methods reduces code clutter at the application level, which will hopefully reduce development and debugging time for the application.

Color Attribute Methods
The most significant difference between the `ANSI` primitives and the `API` layer is the way color attributes are encoded. While the terminal emulator program interprets the `ANSI` escape sequences to set color attributes and text modifiers, it is rather inconvenient to work with them directly. Internally, the `AnsiCmd` library encodes color attributes as 32-bit bit fields.
`` List of Attribute Names
`` Attribute Bitfield Definitions

Display Formatting Methods
Erase the current data displayed in the specified area of the terminal window, or format text paragraph data to fit within a specified area.

Line Drawing Methods
Draw horizontal and vertical lines or draw rectangles in the terminal window.

Identify "Special" Keycodes
Identify whether a given keycode matches one of the defined “special” or “command-key” keycodes.

Temporary File Management
Create and manage temporary files for useby the application.

Communicate With System Clipboard
Establish a communications channel with the system clipboard and exchange text data with the clipboard.
`` AnsiCmd Clipboard Access

#### Color Attribute Methods

- bool AnsiCmd::acSetAttributes ( acAttr newAttr, bool resetAll = false );

        Input  : newAttr : bitfield containing the logical OR of the desired
                           foreground/background attributes and text modifiers.
                 resetAll: (optional, 'false' by default)
                           if 'false', only the the attributes specified by
                                       'newAttr' will be modified.
                           if 'true',  all attributes and modifiers will be reset
                                       to their default values before the new
                                       attributes are applied.

        Returns: 'true' if successful, else 'false' (currently always 'true')

  Modify or replace the current color attributes and/or text modifiers.

  The basic group of AnsiCmd methods set or reset one attribute per call by issuing the corresponding `ANSI` escape sequence designated as a member of `enum aeSeq` (ansi escape Sequence). The `acSetAttributes` method, by contrast, takes as a parameter the logical OR of an arbitrary number of attributes designated as members of `enum acAttr` (ansi cmd Attribute). Arguably, this provides a cleaner interface between the application layer and the display-formatting functionality.

  The individual `enum acAttr` members are `OR'd` together to produce the `'newAttr'` parameter sent to `acSetAttributes`.

  The examples below demonstrate how a `logical OR of acAttr values` specifies the attribute(s) to be modified.

  Note that when performing any mathematical operation using members of an enumerated type such as `enum acAttr`, the compiler will complain. For instance, when performing a `logical OR` using members of `enum acAttr`, the compiler insists that the result be cast back into the `acAttr` type. For example, the compiler will complain about this assigment:
  `acAttr newAttr = acaFG_BLUE | acaBG_GREEN ;`
  so to make the compiler happy we perform a cast back to the type:
  `acAttr newAttr = acAttr(acaFG_BLUE | acaBG_GREEN) ;`
  Please see enum acAttr, below for more detailed information.

  - To set the foreground color attribute to blue text:
    `acSetAttributes ( acaFG_BLUE ) ;`
  - To set the background color attribute to green:
    `acSetAttributes ( acaBG_GREEN ) ;`
  - To simultaneously set both foreground and background color attributes:
    `acSetAttributes ( acAttr(acaFG_BLUE | acaBG_GREEN) ) ;`
  - To set Bold and Italic text modifiers:
    `acSetAttributes ( acAttr(acaBOLD | acaITALIC) ) ;`
  - To reset only a specific text modifier (or modifiers) combine the modifier(s) with the “acaCLEAR_MODS” member:
    `acSetAttributes ( acAttr(acaCLEAR_MODS | acaBOLD) ) ;`
  - To reset all text modifiers (i.e. plain text), call with only the “acaCLEAR_MODS” member:
    `acSetAttributes ( acaCLEAR_MODS ) ;`
  - To set Bold, blue foreground text, either specify a blue foreground in combination with the Bold attribute, or specify the bold blue attribute directly:
    `acSetAttributes ( acAttr(acaBOLD | acaFG_BLUE) ) ;`
    `or`
    `acSetAttributes ( acaFGb_BLUE ) ;`
  - RGB (Red/Green/Blue) or 8-bit color foreground and background attributes are specified as index values rather than as individual members of enum acAttr. For this reason, setting RGB or 8-bit attributes is a two-step process.
    First, call `acComposeAttributes` (described below) to construct the bitfield value, then call acSetAttributes with the resulting value.

    RGB attribute values combine `'acaFG_RBG'` and/or `'acaBG_RGB'` with “web-safe” color indices in the range: wsrgbMIN <= index <= wsrgbMAX. This example sets both foreground and background to web-safe RGB attributes:
    `acAttr aca = acComposeAttributes( 14, 221, true, true );`
    `acSetAttributes ( aca );`

    Eight-bit attributes combine `'acaFG_INDEX'` and/or `'acaBG_INDEX'` with 8-bit color indices in the range: min8BIT <= index <= max8BIT. This example sets both foreground and background to 8-bit attributes:
    `acAttr aca = acComposeAttributes( 32, 112, false, false );`
    `acSetAttributes ( aca );`
    See acComposeAttributes below for additional examples.

  - To reset all attributes and modifiers to their default values, and then set new fgnd/bgnd attributes and text modifiers, call with the `'resetAll'` flag set:
    `acSetAttributes ( acAttr(acaFG_BLUE | acaBG_GREY | acaUNDERLINE), true ) ;`
  - To reset all attributes and modifiers to their default values, use the “acaATTR_DFLT” member in combination with the `'resetAll'` flag:
    `acSetAttributes ( acaATTR_DFLT, true ) ;`
- acAttr acComposeAttributes ( uint8_t fgVal, uint8_t bgVal, bool rgbfg, bool rgbbg, acAttr mods = acaPLAINTXT )

        Input  : fgVal  : foreground index (8-bit index or web-safe RGB index)
                          -- if 'rgb' reset, then value interpreted as 8-bit index.
                             Range: 16-231 (or greyscale:232-255)
                          -- if 'rgb' set, then value interpreted as web-safe RGB
                             index. Range: 0-252
                          -- if 'rgb' reset AND 'fgVal' 0-15, then assume 4-bit color
                 bgVal  : background index (8-bit index or web-safe RGB index)
                          -- if 'rgb' reset, then value interpreted as 8-bit index.
                             Range: 16-231 (or greyscale:232-255)
                          -- if 'rgb' set, then value interpreted as web-safe RGB
                             index. Range: 0-252
                          -- if 'rgb' reset AND 'fgVal' 0-15, then assume 4-bit color
                 rgbfg  : if set, fgVal is interpreted as a (web-safe) RGB index
                          if reset, fgVal is interpreted as a 4/8-bit index
                 rgbbg  : if set, bgVal is interpreted as a (web-safe) RGB index
                          if reset, bgVal is interpreted as a 4/8-bit index
                 mods   : (optional, acaPLAINTXT by default)
                          logical OR of acAttr text-modifier flags)

        Returns: the constructed acAttr value
                 (if a value is out-of-range, terminal default will be used)

  Construct an acAttr attribute bitmap from component values:
  Call this method when composing attributes with 8-bit fgnd/bgnd indices or web-safe RGB fgnd/bgnd indices.

  Use the constructed value as the parameter for a call to acSetAttributes, above.

  Examples:

      acAttr aca ;      // receives the constructed value

      Construct an 8-bit foreground and background value:
        aca = acComposeAttributes ( min8BIT + 2, min8BIT + 27, false, false );
      Construct a value with a 4-bit foreground on an 8-bit background:
        aca = acComposeAttributes ( 3, max8BIT - 32, false, false );
      Construct the same attribute value, but adding italic text.
        aca = acComposeAttributes ( 3, max8BIT - 32, false, false, acaITALIC );
      Construct a web-safe RGB foreground and background value:
        aca = acComposeAttributes ( wsrgbMIN + 16, wsrgbMAX - 32, true, true );
      Construct a value with an 8-bit foreground on an RGB background.
        aca = acComposeAttributes ( 201, wsrgbMIN + 32, false, true );
      Construct the same attribute value, but adding underlined text.
        aca = acComposeAttributes ( 201, wsrgbMIN + 32, false, true, acaUNDERLINE );
      Construct the same attribute value, but with italic _and_ underlined text.
        aca = acComposeAttributes ( 201, wsrgbMIN + 32, false, true,
                                    acAttr(acaITALIC | acaUNDERLINE) );

      Use the constructed value to set the specified attributes:
        acSetAttributes ( aca );
          or
        acSetAttributes ( acAttr(aca | acaITALIC | acaUNDERLINE) );

  Note on 4-bit values:
  The 4-bit color attributes are individually named, so the attributes may be specified directly.
  `Examples: acSetAttributes( acAttr(acaFG_BLUE | acaBGb_BROWN) );`
  `acSetAttributes( acAttr(acaFG_DFLT | acaBGb_BLUE) );`
  `acSetAttributes( acAttr(acaFG_DFLT | acaBG_DFLT) );`
  Although this method is not designed to configure 4-bit color indices (0-15), they will be handled correctly, EXCEPT THAT it is not possible to specify terminal default foreground or background using this method.
  `aca = acComposeAttributes ( 3, 12, false, false );`

- void acGetAttributes ( acaExpand& decodedAttr );

        Input  : decodedAttr: (by reference) instance of an acaExpand object
                              to receive data.

        Returns: nothing

  Get a decoded copy of the current color attributes and text modifier flags.

  The bitfield containing the attributes is decoded into it component values.

  Refer to the description of the acaExpand class data members for more information.

> #### Technical Notes on the acAttr Enumerated Type

> The `acAttr` (AnsiCmd Attributes) enumerated type provides application-level color-attribute and text-modifier configuration for terminal applications. The enumerated list, `enum acAttr` is defined in `AnsiCmdDef.hpp`.

> Members of this type specify color attributes and text modifiers in a consistent format which encapsulates the primitive `ANSI` escape sequences defined for terminal-window text formatting. (see enum aeSeq).

> Within the AnsiCmd class, these values are decoded and mapped to their corresponding `ANSI` escape sequences (or group of sequences). This allows the application to focus on algorithms and user interaction rather than reading and writing binary data within the terminal window.

> Although `acAttr` is defined as an enumerated type, is constructed as a group of macros defining bitfields. This allows the macros to be grouped in a coherent manner while also allowing bitwise OR operations for the desired foreground, background and text-modifier attributes. For example, combine foreground, background attributes PLUS the “bold” and “italic” text attributes, then pass the value as an argument to one of the application-level methods.
> `acAttr txtAttr = acAttr(acaFG_GREEN | acaBG_GREY | acaBOLD | acaITALIC) ;`
> `acSetAttributes ( txtAttr ) ;`

> Technical Note: The compiler will complain when performing any mathematical operations on members of an enumerated type; therefore, be sure to cast the OR’d value back to the acAttr type. For instance, the following would cause a compiler warning: `acAttr a; a |= acaBOLD;`
> Instead, use the following syntax: `a = acAttr(a | acaBOLD);`

> See also the `acaExpand class` below for more information on encoding and decoding the bitfield values.

> #### Bit Twiddling — the acaExpand Class

> Late Night host, Seth Meyers once defined nerds as people “with coffee-breath and crippling anxiety.” While that characterization was a bit rude, he actually wasn’t wrong. For all OCD sufferers, (otherwise known as technically proficient people), having more information is like having a mug of hot cocoa and a warm blanket.

> So, while accessing the `API` method group (which includes the ACWin class), does not require an understanding of the bit manipulations that occur within the AnsiCmd library, our nerd DNA insists that we have at least a general idea what’s going on in the binary jungle.

> All significant bit-oriented operations are encapsulated within the `acaExpand` class. The data managed by the `acaExpand` class are derived from the `acAttr` enumerated type and the `WebSafeRGB` enumerated type. These are both defined in `AnsiCmdDef.hpp`.

> The `acaExpand` class is also defined in `AnsiCmdDef.hpp`, and is implemented in the `AnsiCmdAca.cpp` source module.

> All methods and data members of the `acaExpand` class are “public”; however, the live data are not available to the application (Duh!). If desired, however, a copy of the live data data may be retrieved and studied.
> Please see acGetAttributes, above.

> acaExpand Methods

> `~acaExpand ( void ) ;` // destructor

> `acaExpand ( void ) ;` // default constructor

> `acaExpand ( acAttr bits ) ;`
> Initialization Constructor:
> The `'bits'` parameter consists of one or more members of enum acAttr combined using a logical OR. Example:

>        acaExpand aca( acAttr(acaFG_RED | acaBG_GREY) );

> `void decode ( acAttr bits ) ;`
> Decode the specified bitfield value into it component parts and store them in the data members.

>        acaExpand aca;
>        aca.decode( acAttr(acaFG_RED | acaBG_GREY) );

> `acAttr modify ( acAttr acaValue, bool add ) ;`
> Add (or remove) one or more elements to (from) the bitfield value.
> `'acaValue'` specifies the item(s) to be modified.
> `'add'` (optional, ’true’ by default)
> `` referenced ONLY for text modifiers, not color attributes
> `` if true, add the ’acaValue’ items to the existing bitfield
> `` if false, remove (reset) the specified items

>        acaEx.modify( acaBOLD, true );
>        acaEx.modify( acaBOLD, false );
>        acaEx.modify( acAttr(acaFGb_RED | acaBG_BLUE) );

> `void update ( aeSeq aesValue, uint8_t colorIndx = ZERO );`
> Update attribute tracking data by converting the provided member of
> enum aeSeq to the equivalent acAttr bitfield value.
> `'aesValue'` aeSeq item specifying attribute to be updated
> `'colorIndx'` for aeSeq items requiring a color-attribute index value
> (Used internally, but not really useful at the application level.)

> `acAttr compose ( void );`
> Construct an acAttr attribute bitmap from the data in the data members:
> fgIndex, bgIndex and the boolean (flag) members. This is the reverse of the `'decode'` method, above, and is used to encode 8-bit and RGB attribute indices. (Used internally, but not really useful at the application level.)
> Please refer to the API-level method acComposeAttributes which calls the ’compose’ method with consistent formatting.

> `bool swap ( void );`
> Swap (exchange) the foreground and background attributes.
> Text modifiers are not affected.

> `acAttr buildRgb ( bool fg, WebSafeRGB fgVal,`
> `bool bg = false, WebSafeRGB bgVal = wsrgbMIN ) const`
> Construct an acAttr bitfield from web-safe RGB color indices.
> Specify RGB values for foreground and/or background color attributes. The values are members of enum WebSafeRGB which encode the RGB `'hue'` and `'shade'` used to initialize the Red/Green/Blue register values.
> `'fg'` ’true’ if foreground value specified in ’fgVal’
> `` ’false’ if ’fgVal’ is to be ignored
> `'fgVal'` member of enum WebSafeRGB
> `` if ’fg’ flag is set, web-safe RGB foreground value
> `` if ’fg’ flag is reset, this value is ignored
> `'bg'` ’true’ if background value specified in ’bgVal’
> `` ’false’ if ’bgVal’ is to be ignored
> `'bgVal'` member of enum WebSafeRGB
> `` if ’bg’ flag is set, web-safe RGB background value
> `` if ’bg’ flag is reset, this value is ignored
> Returns: the constructed acAttr bitfield (If one or more parameters out-of-range, acaATTR_DFLT is returned.

> Examples:

>     1) Construct a bitfield with medium red foreground and dark blue background.
>        acaExpand aca ;
>        acAttr newVal =
>              aca.buildRgbVal ( true, WebSafeRGB(wsrgbRED + wsrgbSHADE_MED),
>                               true, wsrgbBLUE );
>        aca.decode( newVal );

>     2) Construct a bitfield with bright cyan background, and with a standard
>        4-bit (non-RGB) blue foreground.
>        acaExpand aca ;
>        acAttr newVal =
>              aca.buildRgbVal ( false, wsrgbMIN,
>                                true, WebSafeRGB(wsrgbCYAN + wsrgbSHADES - 1) );
>        newVal = acAttr(newVal | acaFG_BLUE);
>        aca.decode( newVal );

>     3) Construct a bitfield with bright magenta foreground, and a medium blue
>        background shade.
>        acaExpand aca ;
>        acAttr newVal =
>              aca.buildRgb ( true, WebSafeRGB(wsrgbMAGENTA + wsrgbSHADE_MAX),
>                             true, WebSafeRGB(wsrgbBLUE + wsrgbSHADE_MED / 2) );
>              aca.decode( newVal );

>     4) Construct a bitfield with bright yellow foreground and a medium blue
>        background.
>        acaExpand aca ;
>        acAttr newVal =
>              acaBld.buildRgb( true, WebSafeRGB(wsrgbBROWN + wsrgbSHADE_MAX),
>                               true, WebSafeRGB(wsrgbBLUE + wsrgbSHADE_MAX * 0.65) );
>        aca.decode( newVal );

> `acAttr build8Bit ( bool fg, uint8_t fgVal, bool bg, uint8_t bgVal ) const`
> `'fg'` ’true’ if foreground value specified in ’fgVal’
> `` ’false’ if ’fgVal’ is to be ignored
> `'fgVal'` index of foreground attribute, range: min8BIT - max8BIT
> `` if ’fg’ flag is set, calculate foreground bitfield
> `` if ’fg’ flag is reset, this value is ignored
> `` and foreground bits are initialized as reset
> `'bg'` (optional, ’false’ by default)
> `` ’true’ if background value specified in ’bgVal’
> `` ’false’ if ’bgVal’ is to be ignored
> `'bgVal'` (optional, min8BIT by default)
> `` index of background attribute, range: min8BIT - max8BIT
> `` if ’bg’ flag is set, calculate background bitfield
> `` if ’bg’ flag is reset, this value is ignored
> `` and background bits are initialized as reset
> Returns: the constructed acAttr bitfield

>        acaExpand acaBld ;
>        acAttr pbAttr = acaBld.build8Bit( true, 160, true, 82 ) ;
>        acAttr sbAttr = acaBld.build8Bit( true, 16, true, 219 ) ;
>        acAttr rbAttr = acaBld.build8Bit( false, 0, true, 219 ) ;
>        acAttr sbAttr = acaBld.build8Bit( true, 16 ) ;

> `aeSeq bits2aeseq ( acAttr acaBits, uint8_t byteIndx, bool isFgnd, bool isRgb );`
> Convert between acAttr (bitfield) and aeSeq (ANSI escape sequence).
> Note: If the aeSeq value is one of the 4-bit "bold" foreground attributes, the ’boldMod’ flag is set. Otherwise the flag is not modified.
> `'acaBits'` acAttr bitfields to be converted
> `'byteIndx'` byte index value (either foreground or background index)
> `` (currently unused)
> `'isFgnd'` true if foreground target, false if background target
> `'isRgb'` (optional, false by default)
> `` true if `'acaBits'` references one of the
> `` web-safeRGB register indices, minRGB-maxRGB.
> `` ’false if ’acaBits’ is a lookup table index:
> `` 0-15 : 4-bit color index
> `` 16-231 : 8-bit color index
> `` 232-255 : greyscale index
> Returns: member of enum aeSeq

>        acAttr attrBits = acAttr(acaFG_CYAN | acaBG_BLUE) ;
>        WebSafeRGB attrRgb = wsrgbBLUE + wsrgbSHADE_MED ;
>        acaExpand acax ;
>        // 8-bit background
>        aeSeq attrSeq = acaex.bits2aeseq ( attrBits, 0, false );
>        // RGB foreground
>        attrSeq = acaex.bits2aeseq ( attrRgb, 0, true, true );

> `acAttr aeseq2bits ( aeSeq aesCmd, bool& setFlag );`
> Convert between aeSeq (ANSI escape sequence) and acAttr (bitfield).
> For named escape sequences only; specifically:
> a) 4-bit foreground
> b) 4-bit background
> c) text modifier flags
> All other aeSeq values return acaPLAINTXT (i.e. zero).
> Note: If the aeSeq value is one of the 4-bit "bold" foreground or background attributes, the ’boldMod’ flag is set.
> Otherwise the flag is not modified.
> `'aesCmd'` member of enum aeSeq to be converted
> `'setFlag'` (by reference) receives the state of the internal
> `` set/reset flag associated with the attribute
> Returns: member of enum acAttr

>        aeSeq fgnd = aesFGb_BLUE ;
>        bool flag ;
>        acaExpand acax ;
>        acAttr convAttr = acax.aeseq2bits( fgnd, flag ) ;

>        Returns:
>        convAttr == acaFGb_BLUE  and  flag == true

> `bool web2regs ( uint8_t webrgb, bool fgnd );`
> Convert web-safe RGB index into red/green/blue RGB register values.
> `'webrgb'` value indicating one of the web-safe RGB register groups
> `` in the range: wsrgbMIN <= webrgb <= wsrgbMAX.
> `'fgnd'` true if fgnd attributes, false if bgnd attributes
> 216 web-safe colors are defined by the standard, which are mapped to the 256 color indices defined for terminal color attributes and are then translated to individual R, G and B register values as shown.

>                     DARK >>>> LIGHT   CORRESPONDING RGB REGISTER INDICES
>      Black        :    0               16;16;16
>      Red group    :    1      36       22;16;16  >>>>  231;16;16
>      Green group  :   37      72       16;22;16  >>>>  16;231;16
>      Blue group   :   73     108       16;16;22  >>>>  16;16;231
>      Brown group  :  109     144       22;22;16  >>>>  231;231;16
>      Magenta group:  145     180       22;16;22  >>>>  231;16;231
>      Cyan group   :  181     216       16;22;22  >>>>  16;231;231
>      Grey group   :  217     231       22;22;22  >>>>  231;231;231

> `void reset ( bool modsOnly = false ) ;`
> Reset (clear) all data members. Optionally, reset text-mod flags only.
> `'modsOnly'` if true, reset only the text-modifier attributes
> `` if false, reset all color and text-modifier attributes

> acaExpand Data Members

> Note that while there is some redundancy among the members, the layout of the data members is constructed for speed of access and to minimize the need for higher-level methods to perform bitwise operations. This in turn reduces the chance of processing errors.

> `acAttr acaVal;` full, encoded acAttr value
> `uint32_t fgBits;` nine bits defining foreground: index byte + fg default flag
> `uint32_t bgBits;` nine bits defining background: index byte + bg default flag
> `uint32_t allFlags;` all binary flags (excludes fg/bg indices)
> `uint32_t modFlags;` text-modification flags (subset of ’allFlags’)
> `acAttr acaFgnd;` 8-bit field defining the foreground index
> `acAttr acaBgnd;` 8-bit field defining the background index
> `aeSeq aesFgType;` Foreground attribute type:
> `aesFG_DFLT:` 4-bit color
> `aesFG_INDEX:` 8-bit color
> `aesFG_RGB:` r/g/b color
> `aeSeq aesBgType;` Background attribute type:
> `aesBG_DFLT:` 4-bit color
> `aesBG_INDEX:` 8-bit color
> `aesBG_RGB:` r/g/b color
> `aeSeq aesFgnd;` 4-bit foreground (member of enum aeSeq)
> `aeSeq aesBgnd;` 4-bit background (member of enum aeSeq)
> `uint8_t fgIndex;` foreground byte index
> `uint8_t bgIndex;` background byte index
> `uint8_t rgbFgR;` if RGB foreground, Red register value
> `uint8_t rgbFgG;` if RGB foreground, Green register value
> `uint8_t rgbFgB;` if RGB foreground, Blue register value
> `uint8_t rgbBgR;` if RGB background, Red register value
> `uint8_t rgbBgG;` if RGB background, Green register value
> `uint8_t rgbBgB;` if RGB background, Blue register value
> `bool fgDflt;` if set, terminal default foreground (ignore fg index bits)
> `bool bgDflt;` if set, terminal default background (ignore bg index bits)
> `bool boldMod;` if set, Bold (intense) text
> `bool italicMod;` if set, Italic text
> `bool ulineMod;` if set, Underlined text
> `bool olineMod;` if set, Overlined text
> `bool xoutMod;` if set, X-out (strikethrough) text
> `bool blinkMod;` if set, Blinking text
> `bool invisMod;` if set, Invisible (concealed) text
> `bool revMod;` if set, Reversed foreground and background
> `bool clrMods;` if set, Clear existing mods before setting new mods
> `bool fgRgb;` if set, rgbFgR, rgbFgG and rgbFgB contain the foreground color
> `bool bgRgb;` if set, rgbGbR, rgbBgG, and rgbBgB contain the background color

> acaExpand Decoding Examples

>     AnsiCmd (enum acAttr) color-attribute bit fields:
>     0x000000FF  index for foreground color
>                 ......00-......0F  16  4-bit color attributes
>                 ......10-......E7  216 8-bit color attributes
>                 ......E8-......FF  24  greyscale color attributes
>                 ......00-......FC  232 RGB color attributes
>     0x0000FF00  index for background color
>                 ....00..-....0F..  16  4-bit color attributes
>                 ....10..-....E7..  216 8-bit color attributes
>                 ....E8..-....FF..  24  greyscale color attributes
>                 ....00..-....FC..  232 RGB color attributes
>     0x00FF0000  text modifier flags
>                 ..00....   plain text (no modifiers)
>                 ..01....   bold (intense)
>                 ..02....   italic
>                 ..04....   underline
>                 ..08....   overline
>                 ..10....   x-out (strike-through)
>                 ..20....   blink
>                 ..40....   concealed (invisible)
>                 ..80....   reversed fg/bg
>     0xFF000000  additional flags
>                 01......   clear existing modifiers before setting the new ones
>                 02......   use terminal default foreground attribute
>                            (foreground index ignored)
>                 04......   if set, it indicates that foreground index is the
>                            index of a "web-safe" RGB foreground color attribute
>                            with a range of: minRGB <= value <= maxRGB
>                 08......   use terminal default background attribute
>                            (background index ignored)
>                 10......   if set, it indicates that background index is the
>                            index of a "web-safe" RGB background color attribute
>                            with a range of: minRGB <= value <= maxRGB
>                 20......   (reserved)
>                 40......   (reserved)
>                 80......   (reserved as internal placeholder value)

>     The following shows some examples of how the bitfield is constructed.
>     The contruction is performed by creating a logical OR of enum acAttr members;
>     or in the case of 8-bit and RGB color attributes by using the 'compose' method
>     described above.
>     See also the AnsiCmd 'acComposeAttributes' public method.

>     To specify the terminal default foreground attribute, set the acaFG_DFLT flag.
>     The foreground index value will be ignored.
>        Fgnd:  xxxx-x01x-xxxx-xxxx-xxxx-xxxx-....-....

>     To specify the terminal default background attribute, set the acaBG_DFLT flag.
>     The background index value will be ignored.
>        Bgnd:  xxx0-1xxx-xxxx-xxxx-....-....-xxxx-xxxx

>     To specify a 4-bit foreground attribute, _reset_ the acaFG_DFLT and
>     acaFG_RGB flags and insert the desired member of enum acAttr in the range:
>     acaFG_BLACK through acaFGb_GREY inclusive.

>     To specify a 4-bit background attribute, _reset_ the acaBG_DFLT and
>     acaBG_RGB flags and insert the desired member of enum acAttr in the range:
>     acaBG_BLACK through acaBGb_GREY inclusive.

>     To specify an 8-bit indexed color foreground attribute, initialize the
>     foreground index and _reset_ both the acaFG_DFLT and acaFG_RGB flags.
>        Fgnd:  xxxx-x00x-xxxx-xxxx-xxxx-xxxx-nnnn-nnnn

>     To specify an 8-bit indexed color background attribute, initialize the
>     background index and _reset_ both the acaBG_DFLT and acaBG_RGB flags.
>        Bgnd:  xxx0-0xxx-xxxx-xxxx-nnnn-nnnn-xxxx-xxxx

>     To specify one of the "web-safe" RGB register combinations, initialize
>     the foreground or background index and set the acaFG_RGB or acaBG_RGB
>     flag, respectively.
>        Fgnd:  xxxx-x10x-xxxx-xxxx-xxxx-xxxx-nnnn-nnnn
>        Bgnd:  xxx1-0xxx-xxxx-xxxx-nnnn-nnnn-xxxx-xxxx

>     To set one or more text modifiers, _reset_ the acaCLEAR_MODS flag and
>     create a logical OR of the desired attributes. (include existing fg/bg bits.)
>     Ex: acAttr fgbg = acAttr(acaFG_BLUE | acaBGb_RED);
>         acAttr((fgbg |acaBOLD | acaITALIC | acaUNDERLINE) & ~acaCLEAR_MODS)
>        Mods:  xxxx-xxx0-xxxx-x111-xxxx-xxxx-xxxx-xxxx

>     To reset one or more text modifier, set the acaCLEAR_MODS flag and _set_
>     the flag(s) for the modfier(s) to be reset. (include existing fg/bg bits.)
>     Ex: acAttr(fgbg | acaITALIC | acaCLEAR_MODS)
>        Mods:  xxxx-xxx1-0000-0010-xxxx-xxxx-xxxx-xxxx

#### Display Formatting Methods

- void acClearScreen ( wchar_t fillchar = L`' '`, acAttr fillattr = acaUSEDFLT );

        Input  : fillchar: (optional, space character ' ' by default)
                           specify a (single-column) character to be written to
                           each character cell of the terminal window
                 fillattr: (optional, default: terminal default attribute)
                           color attribute for clearing the terminal window.
                           Note: If a non-default attribute is specified, that will
                                 be the current fg/bg attribute on return.

        Returns: nothing

  Clear the entire terminal window using the specified fill character and color attribute.

  On return, the visible cursor will be at the HOME position (1,1).

- bool acClearArea ( short row, short col, short height, short width,
  `` wchar_t fillchar = L`' '`, acAttr fillattr = acaUSEDFLT );
- bool acClearArea ( WinPos wpOrig, short height, short width,
  `` wchar_t fillchar = L`' '`, acAttr fillattr = acaUSEDFLT );

        Input  : row     : top row of target area
                 col     : left column of target area
                        OR
                 wpOrig  : top row and left column of target area

                 height  : number of rows in target area
                 width   : number of columns in target area
                 fillchar: (optional, ' ' by default)
                           specify a (single-column) character to be written to
                           each character cell in the target area
                 fillattr: (optional, default: terminal default attribute)
                           color attribute for clearing the target area.
                           Note: If a non-default attribute is specified, that will
                                 be the current fg/bg attribute on return.

        Returns: 'true'  if successful
                 'false' if parameter(s) out-of-range

  Clear the specified rectangular area using spaces (default), or using the specified fill character.
  See acDrawLine below for an example invocation.

  Position, height and width of the area are adjusted as necessary to remain within the terminal window.
  See also the note in cursor offsets regarding 1-based vs. 0-based cursor positioning.

  Note: On return, the cursor position within the window will be indeterminate, so it is caller’s responsibility to adjust cursor position.

- short acFormatParagraph ( gString& gsTxt, short maxRows, short maxCols,
  `` bool trunc = true, bool hypenbrk = false, short *truncIndex = NULL );
- short acFormatParagraph ( wchar_t* wTxt, short maxRows, short maxCols,
  `` bool trunc = true, bool hypenbrk = false, short *truncIndex = NULL );

        Input  : on entry, contains raw message text and
                 on return, contains formatted message text
                 gsTxt    : (by reference) a gString Object
                          OR
                 wTxt     : a wchar_t string (32-bit characters)

                 maxRows  : maximum rows for message
                 maxCols  : maximum columns on any message row
                 trunc    : (optional, 'true' by default)
                            if 'true',  truncate the data if necessary to ensure
                                        that the data do not extend beyond the
                                        specified target area
                            if 'false', format the entire source text array, even
                                        if doing so requires violating the specified
                                        height of the target area (maxRows).
                                        (see also 'truncIndx' parameter)
                 hyphenbrk: (optional, 'false' by default)
                            if 'false', automatic line breaks occur after space
                                        characters only.
                                         ASCII space   (U+0020)
                                         CJK space     (U+3000)
                                         CJK comma     (U+3001) (see notes)
                                         CJK full stop (U+3002) (see notes)
                            if 'true',  in addition to the space ' ' characters,
                                        enable line break at:
                                         ASCII hyphen    '-' (U+002D)
                                         Unicode &mdash; '—' (U+2014)
                                         Unicode &ndash; '–' (U+2013)
                                         Unicode &minus; '−' (U+2212)
                 truncIndx: (optional, null pointer by default)
                             -- referenced _only_ when the 'trunc' flag is reset
                             if specified, points to a variable to receive the
                             index at which the data _would_have_been_ truncted to
                             fit the specified height of the target area if the
                             'trunc' flag had been set.
                             a) A positive value indicates that the data have not
                                been truncated, AND that the data extend beyond the
                                the specified target area.
                             b) A negative value indicates that it was not necessary
                                to truncate the data i.e. the data fit entirely
                                within the target area.

        Returns: number of text rows in formatted paragraph

  Reformat the provided text to fit within the specified dimensions.

  1) Remove all newlines.
  2) Perform word wrap to limit width of each row of the paragraph.
  3) If necessary, truncate the text to limit height of the paragraph.
  `` (but see the ’trunc’ and ’truncIndx’ parameters)

  This method is used internally by the ACWin-class objects when writing text in the window and when creating dialogs within the window, but may be used freely when sizing text for display.

  Both single-width and CJK double-width (two column) characters are handled by the this method.
  Note: “CJK” indicates the Chinese, Japanese, Korean (and historically, Vietnamese) character sets.

  Notes on automatic word wrap:

  1. Line breaks occur after the space character at the end of a token, (word). This means that the line is broken by placing the newline after the identified space character.
     Note: Currently the ASCII space character (20h) and the two-column CJK space (U+3000) are the only whitespace characters recognized.

     Special Case: In every-day use, CJK text seldom contains any spaces at all within a sentence, or even between sentences. Two-column punctuation is designed to provide a visual spacing effect. For this reason, we have made the design decision to process the following CJK ideographs as whitespace:
     `'、'` comma U+3001 and `'。'` full stop U+3002

     Caution: Tab characters `('\t')` are not recognized as whitespace characters because they are effectively variable width characters. Don’t use them!

     Optionally, the ASCII hyphen and the Unicode hyphen-like characters can be treated as if they were whitespace for purposes of calculating where to break a line. See the `'hyphenbrk'` parameter.

  2. When reformatting the data, it is possible that the text will be pushed beyond the specified number of rows. In this case, we have two options:
     1. Truncate the text after the last specified row is filled.
     2. Alert the caller about the number of rows actually required. Optionally, we can indicate the index at which the text would have been truncated so that caller can manually truncate the text if desired. (see the `'truncIndx'` parameter)
  3. It is possible that a single token (word) will be longer than the width of the target area. Handling this (unlikely) scenario complicates the line-break algorithm, but could come into play; for instance: filespecs, URLs, or German words. :-)
     Filespecs and URLs should be parsed using specialized formatting methods. Long words, especially hyphenated words can be a problem. This method can optionally break after hyphens (see the `'hyphenbrk'` parameter).
  4. Notes on automatic hyphenation at mid-word line breaks:
     Technically, hyphens should be placed between syllables, but that would require a full dictionary of the target language.
     “Can open... worms everywhere.” (Thank you, Chandler Bing.)
     - The hyphen used is the the Unicode &ndash; U+2013. This facilitates stripping them from the text if the text is copied and pasted elsewhere.
       Note the ideally we would use the so-called “soft hyphen,” Unicode &shy; U+00AD, but unfortunately the terminal sees that as a zero-width character making it invisible under most circumstances.
       Example of stripping characters using the gString utility:
       `gString gsTxt(` `"Dashing–through–the–snow–in–a–one-horse–open–sleigh." );`
       `short sindx = ZERO ;`
       `while ( (sindx = gsTxt.find( nDASH, sindx )) >= ZERO )`
       `gsTxt.erase( sindx, 1 ) ;`
       Yields: `"Dashing through the snow in a one-horse open sleigh."`
       Note that the ASCII hyphen between ’one’ and ’horse’ is not affected.
       Please see gString Text Tool for more information on the gString text internationalization utility.
     - Programmer’s Note: If the current character is the same width as the hyphen, then the hyphen will be at the right edge of the target area. Otherwise there will be a one-column gap at the end of the line.
     - Special case: For multi-column characters, it is assumed that the characters belong to one of the CJK character sets. (This may not be true, but multi-column characters seldom appear in Romance languages.
       Therefore, for multi-column characters only, hyphens are not inserted after mid-token line breaks because there is no way of knowing if we are breaking in mid-word or between words unless we have access to dictionaries for those languages.
       (Again, “...worms everywhere.”)
- int acShellOut ( const char* cmd = NULL, bool clrWin = false, acAttr txtAttr = acaUSEDFLT );

        Input  :
           cmd    : (optional, default: null pointer) command to be executed
                    -- any valid command, or sequence of commands may be
                       specified, using the syntax recognized by the shell
                       program.
                    -- if a command is not specified, the default shell
                       program is invoked with a message similar to:
                       "type 'exit' to return."
           clrWin : (optional, default: false)
                    if 'false', the called application begins output at the
                                at the current cursor position
                    if 'true',  clear the terminal window before invoking the
                                command. The command will appear at the top
                                of the terminal window
           txtAttr: (optional, default: acaUSEDFLT)
                    -- if the default value is seen, the the current color
                       attribute settings will be used for both the optional
                       clear of the window and for the text written by the
                       called terminal application.
                    -- if a non-default value is specified, it is used for
                       both clearing the terminal window ('clrWin' parameter)
                       and as the color attributes used by the called program
                       for writing text to the window.
                       Note: Many console utilities override the existing
                             terminal attributes, so the specified attribute
                             may be ignored.

        Returns: exit code of child process
           Ideally, this is the exit code of the last utility run in the
           child process, but this cannot be guaranteed.

  Temporarily return control to terminal shell program.

  1. If specified, set foreground/background color attributes.
  2. If specified, clear the terminal window.
  3. Return I/O buffering and input echo settings to the terminal defaults.
  4. Any signal handlers which have been set within the application will become inactive while the shell program is in control. These signals will become available to the shell program and any utilities executing within the shell.
     Please see acCaptureSignals for a discussion of available signal handlers.
  5. When the application regains control, the previous I/O buffering, echo option and color attributes will be restored.

  This method uses the standard library `'system'` function which in turn uses members of the `'exec'` function group to format and execute the command and its arguments.
  Refer to standard library docs for details:
  `info system`
  `man 3 system`

  See also the `ACWin-class` ShellOut method.

#### Line Drawing Methods

- WinPos acDrawLine ( const WinPos& wpOrig, short length, bool vertical, LineType lType = ltSINGLE,
  `` wchar_t begChar = L`'\0'`, wchar_t endChar = L`'\0'` );

        Input  : pos     : offset from upper-left corner of terminal window to
                           upper-left corner of box (1-based)
                 length  : length of the line: number of number of rows (vertical),
                           or number of columns (horizontal).
                 vertical: 'true'  : vertical line
                           'false' : horizontal line
                 lType   : (optional, ltSINGLE by default) line style
                            member of enum LineType: either ltSINGLE or ltDUAL
                 begChar : (optional, null character by default)
                            specify the beginning endpoint character
                 endChar : (optional, null character by default)
                            specify the final endpoint character

        Returns: cursor position at the end of the line:
                 For horizontal lines, this is the column following the last character.
                 For vertical lines, this is the column below the last character.

  Draw a horizontal or vertical line in the terminal window.
  Horizontal lines are drawn left-to-right.
  Vertical lines are drawn top-to-bottom.

  Optionally, the endpoint character(s) may be specified for the beginning and/or end of the line. The valid endpoint characters include any of the line-drawing glyphs defined in `AnsiCmdDef.hpp`. Note however, that the `'begChar'` and `'endChar'` parameter are not range checked, so the character specified (if any), will be written. (Use single-column characters only.) If the endpoint(s) are not specified, the line-drawing character is used as the endpoint character.

      Example:
         // define the dimensions of the box
         short hgt = 9, wid = 25 ;
         // define the upper left corner of the box object
         WinPos wp( 9, 9 ) ;
         // clear target area using optional color attributes, and note that
         // on return, the specified colors are still active.
         acClearArea ( wp, hgt, wid, L' ', acAttr(acaFGb_CYAN | acaBG_BLUE) ) ;
         // draw the box
         acDrawBox ( wp, hgt, wid, ltDUAL ) ;
         // move downward to start position of first line
         wp.row += 4 ;
         // draw a line the full width of the box with connections on each end
         acDrawLine ( wp, 25, false, ltSINGLE, wcsLTEEdv, wcsRTEEdv ) ;
         // move to the top center of the box
         wp = { 9, 21 } ;
         // draw a line that connects with the box at the top and terminates
         // with a line-intersection character
         wp = acDrawLine ( wp, 5, true, ltSINGLE, wcsTTEEdh, wcsINSECT ) ;
         // draw a line from below the intersect character to the bottom
         // of the box, and which terminates with a connector character
         acDrawLine ( wp, 4, true, ltSINGLE, NULLCHAR, wcsBTEEdh ) ;

              ╔═══════════╤═══════════╗
              ║           │           ║
              ║           │           ║
              ║           │           ║
              ╟───────────┼───────────╢
              ║           │           ║
              ║           │           ║
              ║           │           ║
              ╚═══════════╧═══════════╝

- WinPos acDrawBox ( WinPos pos, short height, short width, LineType lType = ltSINGLE, const char *text = NULL );

        Input  : pos   : offset from upper-left corner of terminal window to
                         upper-left corner of box (1-based)
                 height: number of rows for box
                 width : number of columns for box
                 lType : (optional, ltSINGLE by default) line style
                         member of enum LineType: either ltSINGLE or ltDUAL
                 text  : (optional, null pointer by default)
                         If specified, text to be written to interior of box.

        Returns: current cursor position within the box

  Draw a box in the terminal window and optionally write text in the box.

  This is a greatly simplified form of drawing a window. It simply draws a rectangle in the terminal window at the specified position and of the specified dimensions.
  The box is drawn using the currently active foreground and background colors.

  If parameters are out-of-range, the position and dimensions will be modified as necessary to fit within the terminal window.

  The position of the visible cursor is returned.
  If the `'text'` parameter specifies text data to be written into the box, then the cursor will be positioned at the end of the text. Otherwise, the cursor will be positioned at the top-left corner of the interior of the box.
  See acDrawLine above for an example invocation.

- void acEraseBox ( WinPos wpOrig, short height, short width );

        Input  : pos   : offset from upper-left corner of terminal window to
                         upper-left corner of box (1-based)
                 height: number of rows for box
                 width : number of columns for box

        Returns: nothing

  Erase the specified area. This is a companion method to the `acDrawBox` method above. `acEraseBox` simply calls the low-level method to clear the text from the specified area.

  #### The AC_Box Class

- WinPos acBoxDraw ( AC_Box& box, const char* text = NULL );

        Input  : box : (by reference) configuration parameters for the object
                 text: (optional, null pointer by default)
                       If specified, text to be written to interior of box.

        Returns: coordinates of upper-left corner of text area within the box
                 (These coordinates are the one-based offset from the )
                 (upper-left corner of the terminal window.           )

  Display the data of an AC_Box object in the terminal window.

  1. Clear the target area.
  2. Draw the box.
  3. Initialize the interior of the box to the specified background color.
  4. If specified, write the initial text to the interior of the box.
     1. Text will be written using the foreground and background attributes specified for the interior.
     2. Caller is responsible for ensuring that the text fits entirely within the interior area, AND that the final cursor position also lies within the interior area. Automatic text formatting is not performed.
  5. On return, the visible cursor will be positioned at the origin (upper-left corner) of the text area unless initial text data were specified, in which case the visible cursor will be positioned at the end-of-text.
  6. On return, color attributes will have been set to terminal defaults.

  AC_Box Example

      WinPos boxOrigin( 1, 16 ) ;
      short  boxHEIGHT = 11 ;
      short  boxWIDTH  = 48 ;
      LineType lType   = ltSINGLE ;
      aeSeq  borderFg  = aesFGb_GREY ;
      aeSeq  borderBg  = aesBG_BLUE ;
      aeSeq  textFg    = aesFG_BLUE ;
      aeSeq  textBg    = aesBG_CYAN ;
      const char* title = "  Life Is A.. What?!  " ;

      AC_Box box( boxOrigin, boxHEIGHT, boxWIDTH, lType,
                  borderFg, borderBg, textFg, textBg, title ) ;
      acBoxDraw ( box, "\n\n     Life is like a box of chocolates.\n"
                           "     You never know what you're gonna get.\n"
                           "      -- Forrest G." ) ;

  ┌───────────┤ Life Is A.. What?! ├───────────┐ │ │ │ │ │ Life is like a box of chocolates. │ │ You never know what you're gonna get. │ │ -- Forrest G. │ │ │ │ │ │ │ │ │ └──────────────────────────────────────────────┘
- void acBoxErase ( const AC_Box& box );

        Input  : box : (by reference) configuration parameters for the object
        Returns: nothing

  Erase the rectangular area drawn by the `acBoxDraw` method, above.

  The current color attributes will be used to clear the area.

- WinPos acBoxClear ( const AC_Box& box );

        Input  : box : (by reference) configuration parameters for the object
        Returns: coordinates of upper-left corner of text area within the box

  Erase the text area of of an AC_Box object.

  1. On return, the foreground/background color attributes are set to the colors specified for the interior of the object.
  2. On return, the visible cursor is set to the upper-left corner of the text area.

#### Identify "Special" Keycodes

- bool isSpecialKey ( wchar_t& wkey, bool alert = false, EchoOpt *eopt = NULL ) const;

        Input  : wkey : (by reference) keycode to be tested

                 alert: (optional, 'false' by default) audible alert
                        'true'  execute a terminal beep if keycode under test
                                IS one of the supported soft-echo keycodes, but
                                IS NOT not included in the active soft-echo group.
                        'false' do not execute an audible alert
                 eopt : (optional, null pointer by default)
                        If specified, this is a pointer to an alternate soft-echo
                        option to be used for the test.
                           (used internally for special-key verification)

        Returns: 'true'  if key is one of the ACTIVE special keys
                 'false' if key is not one of the active special keys
                         If the caller's keycode is a Special key that IS NOT a
                         member of the active group. the keycode will be set to
                         the null character (NULLCHAR) on return.

  Determine whether the specified keycode is one of the "special" keys, AND whether that keycode is a member of the active soft-echo sub-group.

  The test is performed against the soft-echo option specified by the prior terminal setup, (but see the ’eopt’ argument).

  The available character-echo options are members of enum EchoOpt.
  Please refer to TermConfig Class, and specifically the `'echoOption'` member variable for terminal setup information.

  Each of the soft-echo options encompasses a subset of the supported "special" keycodes.
  Please see Soft Echo Options for a description of the soft-echo groups.

  NOTE: This method should not be called when the echo option is not one of the soft-echo options, but if it is, it will only result in a harmess waste of CPU cycles.

- bool isCommandKey ( wchar_t& wkey, bool all = false ) const;

        Input  : wkey : (by reference) keycode to be tested
                 all  : (optional, 'false' by default)
                        if 'true', include the "special" keycodes as command keycodes*
                        if 'false, "special" keycodes are excluded

        Returns: 'true' if keycode is one of the command keycodes, else 'false'

  Determine whether the specified keycode is one of the converted keycodes: 1) ASCII control codes: Ctrl+A - Ctrl+Z, Ctrl+4, Ctrl+5, Ctrl+6, Ctrl+7. 2) "GUI" command keys: Alt+A - Alt+Z, Alt+punctuation characters. 3) Ctrl + navigation keys. 4) Left Alt + navigation keys 5) Function keys: wcsF01-fcsF12, wcsSF01-wcsSF12, wcsCF01-wcsCF12

  By default, this test excludes the “special” keycodes. (see isSpecialKey), however, this method may optionally include the “special” keycodes within the command-key group by setting the `'all'` flag.

  > Technical Note: These keycodes have been converted from escape sequences or ASCII control codes to graphing characters; however, they should not be echoed to the display. They would just look like garbage from the user’s point of view. If the keycode is not associated with an action within the application, it should be discarded. See the (protected) `normalkeyProc` method for additional information.

#### Temporary File Management

Temporary files are an integral part of any application which needs to interact with the host system or with other applications. The `AnsiCmd` library provides full support for creating and managing temporary files within the system temporary directory.

Although the `AnsiCmd` library does not make use of temporary files internally; most non-trivial applications do. For this reason, management of temporary files for applications based on the `AnsiCmd` library is encapsulated here to provide a clean interface to the compiler’s standard library functions for creating and deleting temporary files.

These methods, in turn, rely on the author’s `TFMan class` which is a stand-alone class included in, but functionally seperate from the `AnsiCmd/ACWin/ACDlg` group.
Please see TFMan Class for a full description of this class and the associated test utility TFMTest Demo App.

- bool acCreateTemppath ( const char* prefix = NULL );

        Input  : prefix : (optional, default: null pointer)
                          specify a constant token which will prefix the name of the
                          temporary sub-directory in which temp files will be created.
                          If a prefix is not specified, then the default "ANSICMD_"
                          prefix token is used.
                          Important Note: Use only valid filename characters
                                          (not "special" chars) for the prefix string

        Returns: 'true'  if path/dirname created successfully
                 'false' if call to standard library function failed

  Enable support for temporary files:
  Create a unique sub-directory within the system’s temp-file directory to contain the application’s temporary files.

  Internally, this is implemented by creating an instance of the `'TFMan'` class. The Temp File Manager class encapsulates creation and deletion of temporary files. This prevents one of the most common programmer errors, namely exiting the application and leaving orphaned temp files for the system to clean up. This can be especially important if your temp files contain sensitive information.

  The optional `'prefix'` parameter is used as the leading substring for the filename to be constructed. A unique six-character sequence will be appended to this sequence to form the name of the subdirectory.

  Example: AnsiCmd *acptr = new AnsiCmd() ; acptr->acCreateTemppath ( "MyApp_" ) ; will result in a directory name of the form: MyApp_rPuyzA

  This name is guaranteed to be unique within the system’s temporary directory.

  If no prefix is specified, then the default prefix (`"ANSICMD_"`) will be used.

- void acDeleteTemppath ( void );

        Input  : none
        Returns: nothing

  Disable support for temporary files.
  Delete the sub-directory containing the application’s temporary files and any files remaining in that subdirectory.

  `1)` May be called directly by the application layer, or else
  `2)` Will be called by the AnsiCmd-class destructor.

- bool acCreateTempfile ( gString& tempPath );

        Input  :
           tmpPath: (by reference) receives the path/filename of the new file
        Returns:
           'true'  if file created successfully
           'false' if library call failed

  Create a unique path/filename for a temporary file, then create the file.
  The file will have been closed and will be empty (will contain no data).

  gString tmpPath ; ACWin* win = new ACWin( ... ); ... win->acCreateTempname ( "SAM_" ) ; if ( (win->acCreateTempfile ( tmpPath )) ) { ofstream ofs ( tmpPath.ustr(), ofstream::out | ofstream::app ) ; if ( (ofs.is_open()) ) { ofs << "Write some data to the temp file." << endl ; ofs.close() ; } } // This is optional. If this method is not explicitly called by // the application, it will be called by the ACWin/AnsiCmd destructor. win->acDeleteTempname () ;
- bool acDeleteTempfile ( const gString& tempPath );

        Input  :
         tmpPath : full path/filename specification of source
        Returns:
           'true'  if successfully deleted
           'false' if library call failed

  Delete the specified temporary file.

  This method will delete the specified file ONLY if the file resides within the temporary subdirectory created by `acCreateTemppath`.

#### Communicate With System Clipboard

- bool acClipboardEnable ( gString* version = NULL );

        Input  :
           version : (optional, default: null pointer) if specified,
                      pointer to gString object which receives version
                      number of the WaylandCB class _and_ if available,
                      the version number of the wl-clipboard utility.

        Returns:
           'true'  if system clipboard connection established
           'false' if unable to connect: wl-clipboard utilities
                   not installed or inaccessable, or system error

  Establish communications with the system clipboard.
  It is assumed that the system clipboard is managed by the Wayland protocol, which is the case for most modern Linux distributions.

  Create a temporary file in the system temp directory. This file is used for communications with the external “`wl-clipboard`” utilities, “`wl-copy`” and “`wl-paste`”.
  Please see AnsiCmd Clipboard Access for a discussion of these utilities.

  If the `wl-clipboard` utilities are installed and accessible, establish the connection with the system clipboard.

  This is done through a simple handshake sequence which writes a short text string to the system clipboard, then reads it back. If the received data equal the transmitted data, the connection is verified.

  Technical Note: If the connection was previously established, then the call to `acClipboardEnable` will reset and re-initialize the connection.

  Note on version number report:

  If the optional version number parameter is included in the call, the two version-number sub-strings are returned in the gString object, separated by a newline character (’\n’) as shown:
  `"x.y.zz\na.b.c"`
  where `"x.y.zz"` is the WaylandCB version, and `"a.b.c"` is the reported wl-copy/wl-paste version. Example:
  `0.0.06\n2.2.1`
  If communication with the `wl-clipboard` utilities cannot be established, the version number will be of the form: “`0.0.06\nunknown`”

- void acClipboardDisable ( void );

        Input  : none

        Returns: nothing

  Terminate the connection to system clipboard.

  1) Delete the temp files used for communication.
  2) Delete the WaylandCB-class object.
  3) Return all resources to the system.

  Technical Note: If the application forgets to call `acClipboardDisable` on exit, the `AnsiCmd` destructor will release the system resources.

- bool acClipboardTest ( void );

        Input  : none

        Returns: 'true'  if connection verified, else 'false'

  Test the connection with the Wayland clipboard.

  Send a short message to the clipboard, then retrieve the data and compare the results.

- int acClipboardGetText ( gString& gsTxt );

        Input  : gsTxt : (by reference) receives contents of clipboard

        Returns: number of characters returned

  Get a copy of the text data on the clipboard.

  Technical Note: If communication with the system (Wayland) clipboard has been established (see acClipboardEnable), the data are copied from the system clipboard to the local clipboard buffer, and a copy is then returned to caller.
  If communication with the system clipboard has not been established, the data currently in the local clipboard buffer are returned.

  Within a high-level window (ACWin) or dialog (ACDlg) context, copy/cut/paste operations are handled by the `skForm/skField` class. See AnsiCmd Clipboard Access, below for more information.
- int acGetClipboardSetText ( const gString& gsTxt );

        Input  : gsTxt : (by reference) contains data to be written

        Returns: number of characters written

  Write the specified text data to the clipboard.

  Technical Note: The data are first written to the local clipboard buffer; then, if communication with the system (Wayland) clipboard has been previously established, the data are copied to the system clipboard.

  Within a high-level window (ACWin) or dialog (ACDlg) context, copy/cut/paste operations are handled by the `skForm/skField` class. See AnsiCmd Clipboard Access, below for more information.
- int acClipboardCharCnt ( void );

        Input  : none

        Returns: number of (wchar_t) characters (including NULLCHAR)
                 Note that a value of one(1) indicates an empty string.

  Returns the number of UTF-32 characters currently in the local clipboard buffer.

  1. If connected to the system (Wayland) clipboard, return size of system clipboard data.
     Note: This operation will refresh the contents of the local clipboard buffer.
  2. If NOT connected to the system clipboard, value returned is the number of UTF-32 characters stored on the local clipboard.

  Important Note: It can NEVER be assumed that one character equals one byte.

- int acClipboardByteCnt ( void );

        Input  : none

        Returns: number of data bytes (including NULLCHAR)
                 Note that a value of one(1) indicates an empty string.

  Returns the number of UTF-8 bytes of data on the clipboard.

  1. If connected to the system (Wayland) clipboard, return size of system clipboard data.
     Note: This operation will refresh the contents of the local clipboard buffer.
  2. If NOT connected to the system clipboard, value returned is the number of UTF-8 data bytes stored on the local clipboard.

#### AnsiCmd Clipboard Access

1. The “clipboard” is an area of system memory which can be used to transfer text, images and other data among the active applications and system processes, or between segments of a single application.
2. Under most modern flavors of Linux, the “Wayland Protocol” manages communications among the system server and its clients, which includes the system clipboard.
3. While terminal applications are technically able to handle any type of data on the clipboard, practically speaking, only text data should be transferred between the terminal window and the clipboard.
4. The `AnsiCmd` library implements a “local clipboard” which performs copy-and-paste operations within the application. The local clipboard is under the `INCLUDE_API` conditional compile directive.
5. The `AnsiCmd` library is built specifically to avoid third-party tools; and therefore direct communication between the library and the system clipboard is not provided; however, an indirect communications channel to the system clipboard is available, as follows:
   1. The `AnsiCmd` interface with the system clipboard is is included in this package and is under the `INCLUDE_WAYLANDCB` conditional-compilation directive which enables this author’s (very simple) `WaylandCB` class.
      Please see Build Options for information on including the `WaylandCB` module in the build.
   2. The `WaylandCB` class object communicates with the system clipboard through the Linux utility package, `wl-clipboard`. The `wl-clipboard` suite was written by Sergey Bugaev and is available on most Linux mirror sites:
      `sudo dnf install 'wl-clipboard'` or
      `sudo apt-get install 'wl-clipboard'`
      If the `wl-clipboard` utility has been installed on the system and its component interface modules (`wl-copy` and `wl-paste`) are visible on the path, then the WaylandCB object may be initialized at any time after the AnsiCmd (or ACWin) object has been instantiated.
      `AnsiCmd* acptr = new AnsiCmd( ... );`
      `acptr->acClipboardEnable();`
   3. If communication between the system (Wayland) clipboard and the `AnsiCmd` local clipboard has been established, then data may be exchanged between the current application and all other processes which use the system clipboard.
   4. If `wl-clipboard` is not installed, or if communication cannot be established, then the application will be limited to the local clipboard.

   Technical Note: The standalone `WaylandCB` module (see By the Same Author) may be compiled directly into the application instead. If needed, this would provide the application more direct control of the clipboard interface. In that case, to avoid resource conflicts, the `AnsiCmd` instance of the class should should not be enabled.
   For full details on the WaylandCB class and the associated test app, please visit the author’s website.

6. Clipboard operations Within an `skForm` object.
   The `AnsiCmd` methods (acClipboardSetText, etc.) which send data to the clipboard and retrieve data from the clipboard are for use outside any window (`ACWin` object) or dialog (`ACDlg` object).

   Within an `ACWin` or `ACDlg` object, data are exchanged with the clipboard via protected member methods: (`'cbCopy' and 'cbPaste'`). Text selection, Copy, Cut are Paste operations are initiated using the “special” key associated with the operation while a Textbox (ftTB) control has the input focus.

   Ctrl+C wcsCOPY Copy selected text to clipboard Ctrl+X wcsCUT Copy selected text, then delete source text Ctrl+V wcsPASTE Paste text at the IP position Ctrl+A wcsSELECT Select or deselect all Shift+RightArrow wcsSRIGHT Select text moving rightward Shift+LeftArrow wcsSLEFT Select text moving leftward Shift+UpArrow wcsSUP Select text moving upward Shift+DownArrow wcsSDOWN Select text moving downward

   Please see Decoding the Special Keys for a complete list of defined “special keys”.

   Invoking the “Copy” or “Cut” operation will copy the “selected” text of the Textbox field with input focus to the clipboard. Note that selected text is underlined within the field.
   The data is first copied to the local (`AnsiCmd`) clipboard, and then if the application has enabled communications with the system clipboard, (see acClipboardEnable), the data are copied from the local clipboard to the system clipboard, where it will be available to all processes of the system.

   (If no text within the field has been “selected”, then the Copy/Cut command will be ignored.)

   Invoking the “Paste” operation will copy the text stored on the clipboard to the `IP` (insertion point, i.e. the current cursor position) within the Textbox field which has the input focus.
   If the application has enabled communications with the system clipboard, data is first copied from the system clipboard to the local (`AnsiCmd`) clipboard. Then a copy of the data on the local clipboard is written to the target Textbox field.

   If there is “selected” text within the target field the selected text will be replaced by the clipboard data. Otherwise the clipboard data will be inserted into the existing text (if any) of the field.
   Technical Note: The Paste operation ignores the current state of the Insert/Overstrike flag when inserting text.

   (If the field with input focus is not a Textbox field, then the Paste command will be ignored.)

#### Development Support

- void ansiTest ( dbgArgs& args );

        Input  : args : (by reference) test to perform and test options
                        major   : specifies the test to perform
                        minor   : specifies test sub-section
                        supp    : specifies sub-test for RGB, etc.

        Returns: nothing

  This method is a gateway to the debugging code. If debugging disabled (DEBUG_ANSICMD == 0), then a warning message is displayed.

  Perform the specified test of terminal functionality. This functionality is divided into different groups. See ansiTest_Menu method for details.

- void getDataMembers ( acaExpand* ab, locale* lo, short& tr, short& tc, short& fn, bool& fr, bool& ws ) const

        Input  : lo : receives a pointer to current locale structure
                 tr : (by reference) receives terminal rows
                 tc : (by reference) receives terminal columns
                 fn : (by reference) receives current font number
                 fr : (by reference) receives the 'full-reset' flag value
                 ws : (by reference) receives the 'wide-stream' flag value

        Returns: nothing

  Returns a copy of the protected data members of the class.

  Used primarily by the ACWin class to synchronize terminal configuration, but may be used by the curious app designer.

  void getConfig ( termConfig& tCfg ) ;

        Input  : tCfg : (by reference) receives configuration data
        Returns: nothing

  For use during development: The terminal-configuration data used by the `AnsiCmd` class are private members; however, during development, it is often useful to retrieve a snapshot of the current terminal configuration to verify that the terminal is configured as intended.

  void tseReport ( const skForm& skf, const WinPos& wpRpt, uint8_t secret_code ) ;

  Although this method is "technically" a public method, it is called ONLY by the test method, Test_SoftEcho() (and its callback function) to report user input and keycode processing. *

#### Coding Example

The following example demonstrates application startup including creation of an `AnsiCmd`-class object which provides terminal setup and color attribute control capabilities.

Under C++, the `'main'` function does as little as possible.
It simply passes the command-line arguments and terminal environment to the application class, which returns to `'main'` only when it is time to exit.

The application class is unique to each application, allocating data storage and providing the functionality and user interface needed to complete the tasks for which it was designed.

The EarthPoints application class is typical of such classes in that it leverages well-established classes and library functions to do most of the work of the application. The application class provides coordination among the various components to produce the desired results. A really good application will also add something the world has never seen before.

The EarthPoints application does not aim so high. It is simply a vehicle for development and testing of the AnsiCmd class library, which is itself interesting, but not particulary innovative. The AnsiCmd library could be characterized as a nerd’s version of binge-watching a Netflix series during a long, long Covid-19 lockdown while on vacation in Guangxi Province.

int main ( int argc, char* argv[], char* argenv[] ) { //* For capture and parsing of command-line arguments.* //* (includes the application environment variables) * commArgs ca( argc, argv, argenv ) ; //* Instantiate the application class * EarthPoints *ep = new EarthPoints ( ca ) ; //* Save a local copy of the exit code, then invoke * //* the EarthPoints destructor. This returns all * //* allocated resources to the system, including * //* the allocated AnsiCmd object. * xCode xcode = ep->exitCode ; delete ep ; //* Exit, returning control to the shell.* exit ( xcode ) ; } //* End main() * //* The EarthPoints constructor gathers the command-line arguments, * //* creates an AnsiCmd class object and exercises its functionality.* EarthPoints::EarthPoints ( commArgs& ca ) { gString gsOut ; // text formatting //* Initialize all class data members.* this->reset () ; //* Parse command-line arguments * clArgs userOption = this->GetCommandLineArgs ( ca ) ; //* Create the AnsiCmd object and configure terminal settings.* //* Note that color attributes are set during initialization. * this->ansi = new AnsiCmd ( ca.tConfig ) ; //* Exercise the AnsiCmd library functionality. (sample) * this->ColorTheEarth () ; this->ansi->acFlushStreams () ; // flush the I/O streams } //* End EarthPoints() * //* The EarthPoint destructor releases the statically * //* allocated resources back to the system. * EarthPoints::~EarthPoints ( void ) { //* Restore original terminal settings * if ( this->ansi != NULL ) delete ( this->ansi ) ; } //* End ~EarthPoints() * //* This method exercises a sample of * //* the AnsiCmd library functionality. * void EarthPoints::ColorTheEarth ( void ) { //* Configure the input stream ('stdin') for unbuffered input.* this->ansi->acBufferedInput ( false, softEchoA ) ; this->ansi->acEraseArea ( aesERASE_WIN ) ; // clear the terminal window //* The title will be displayed using the color attributes * //* specified when creating the AnsiCmd object. * //* (If not specified, then this is the terminal defaults.)* WinPos wp( 1, 1 ) ; // cursor position is window origin wp = this->ansi->acWrite ( wp, "Welcome to Earth!\n" "-----------------\n\n" ) ; // (wp now contains terminal offset 4;1) //* Set color attributes and write some text.* this->ansi->acSetFgBg ( aesFGb_BLUE, aesBG_MAGENTA ) ; this->ansi->ttyWrite ( "This text is bright blue on a magenta background.\n" ) ; this->ansi->acSetMod ( aesUNDERLINE ) ; // set the 'underline' text modifier this->ansi->ttyWrite ( "This text uses the existing color attributes,\n" "with the addition of the 'underline' modifier.\n" ) ; this->ansi->acSetMod ( aesUNDERLINE_OFF ) ; // reset underline modifier short termRows, termCols ; gString gs ; this->ansi->acGetTermDimensions ( termRows, termCols ) ; gs.compose( "Terminal window size is %hd rows by %hd columns.\n", &termRows, &termCols ) ; this->ansi->ttyWrite ( gs ) ; this->ansi->acSetBg ( aesBG_GREEN ) ; // set a new background color this->ansi->ttyWrite ( " Press Any Key To Exit... " ) ; this->ansi->acRead () ; // wait for user response //* Reset color attributes to terminal defaults * this->ansi->acReset () ; //* Set the cursor position to the saved position, * //* then erase all text from the cursor position to * //* the Bottom Of the Window. * this->ansi->acSetCursor ( wp ) ; this->ansi->acEraseArea ( aesERASE_BOW ) ; //* Goodbye! * this->ansi->acWrite ( wp, "Thanks for visiting Earth.\n" "Preparing to leave orbit.\n\n" ) ; //* Restore all terminal settings to defaults * this->ansi->acRestoreTermInfo ( true ) ; } //* ColorTheEarth() *

## ACWin Class

The AnsiCmd Window class, `ACWin`, is a “derived” class based upon the `AnsiCmd` class. This means that it includes all the public methods of its parent and methods which are unique to the new class.

ACWin implements a more sophisticated level of abstraction from the basic reading and writing of `ANSI` escape sequences. It defines a “window”, a bordered rectangular area within the terminal display. The interior of the window can be used directly to display text data, or may contain various user-interface constructs (see skForm Class), or both direct display and user interface fields. In addition, “dialogs” (sub-windows) (see Dialog sub-Windows) may be created within the primary window either to display informational messages or to interact with the user via “control” objects such as Pushbuttons.

### ACWin Public Methods

This table lists the public methods of the ACWin class.

Method Name | Description
--- | ---
`───` Window-Oriented Methods `───` | `──────────────────────────────────────`
ACWin constructor | Constructors
ACWin destructor | Destructor
OpenWindow | Open the window (make it visible)
CloseWindow | Close the window
RefreshWin | Redraw the window
HideWin | Erase window from display
MoveWin | Move window to another position
ClearWin | Erase interior of window
ClearRow | Erase specified interior row
Write | Write directly to window interior
GetCursorPos | Get cursor position in the window
SetCursorPos | Set cursor position in the window
SetTitle | Specify window title text
SetTextAttr | Specify window interior colors
SetBorderAttr | Specify window border colors
WinInfo | Report basic window information
`───` Form-Oriented Methods `─────` | `──────────────────────────────────────`
EditForm | User edit of skForm object
GetForm | Get a pointer to skForm object
GetInputFocus | Get index of field with focus
SetInputFocus | Set input focus to a field
Focus2NextField | Move input focus to next field
Focus2PrevField | Move input focus to prev field
InsertKey | Configure the Insert key
isInsertMode | Report insert/overstrike flag
AlertEnable | Enable/disable auditory alert
EstablishCallback | Specify a callback function
KeycodePush | Push a keycode into input stream
`───` Field-Oriented Methods `────` | `──────────────────────────────────────`
SetFieldText | Replace text in specified field
GetFieldText | Get a copy of text in field
SetFieldAttr | Set color attributes for a field
SetFieldIP | Set insertion point and cursor
GetFieldIP | Get current insertion point
GetFieldItem | Report highlighted item
SetFieldState | Set binary state of field
GetFieldState | Get binary state of field
SetFieldFlow | Specify auto word wrap option
SetFieldLabel | Attach a label to the field
SetFieldOutline | Draw a border around a field
SetFieldHotkey | Assign a hotkey to the field
SetFieldHidden | Set/reset visibility of field
SetReadOnly | Set/reset field to read-only
SetFieldData | Set field text, color and IP
GetFieldData | Report current field stats
RefreshField | Redraw text in a field
ClearField | Delete text in specified field
ReformatFieldText | Reformat text to fit field
ScrollFieldText | Auto scroll for multi-row data
ShiftFieldText | Block shift for multi-row data
HilightFieldText | Highlight a segment of text data
`───` Dialog-Oriented Methods `───` | `──────────────────────────────────────`
QuickDialog | Simple Info/Decision dialog
Dialog | Full-initialization dialog
Dialog_GetText | Get data from dialog textbox
Dialog_SetText | Set data of dialog textbox
Dialog_SetAttr | Set multi-color attributes
Dialog_GetItem | Get dialog menu item
Dialog_SetItem | Set dialog menu selection
Dialog_GetState | Get state of dialog radiobutton
Dialog_GetStateXOR | Get state of radiobutton XOR group
Dialog_GetField | Get pointer to dialog field object
Dialog_Hilite | Highlight a segment of text data
Dialog_SetFocus | Set input focus to target field
Dialog_SetReadOnly | Set/Reset field’s read-only flag
Dialog_Scroll | Adjust control’s insertion point
Dialog_Write | Write text to dialog window
Dialog_Refresh | Redraw the dialog window
`───────` Utility Methods `───────` | `──────────────────────────────────────`
FormatParagraph | Automatic text formatting
ParagraphSize | Calculate text dimensions
isPrint | Test for “graphing” characters
EnableFootnotes | Enable/disable output of footnotes
Footnote | Write message in bottom border
Sidebar | Write message in left/right border
DrawBox | Draw a rectangle in text area
DrawLine | Draw a line in the text area
LaunchDefaultApp | Invoke an external application
ShellOut | Invoke an app in current window
`─────` Development Support `─────` | `──────────────────────────────────────`
GetWinAttributes | Report color attributes
GetWinConfig | Report height, width and position
GetFifo | Report saved static text
dumpConfig2Log | Write config data to log
dumpField2Log | Write skField stats to log
dumpMrp2Log | Write MRParse data to log
dumpFifo2Log | Write BlockFifo data to log
dumpFifoRecord2Log | Write a single FIFO record to log
Screenshot | Take a screenshot of the window

#### Window-Oriented Methods

- ACWin ( void );

        Input  : none

        Returns: implicitly returns pointer to object

  Default Constructor:
  Create a default window defined as:
  `posRow :` offset one row from top of terminal window
  `posCol :` centered in the terminal window
  `winHgt :` height == eight(8) rows
  `winWid :` width == thirty-six(36) columns
  `` All other parameters use the initialization defaults.

  The default window is rather useless, so the initialization constructor, below, is recommended.

- ACWin ( short posRow, short posCol, short winHeight, short winWidth,
  `` LineType bdrLine = ltSINGLE, acAttr bdrAttrib = acaATTR_DFLT, acAttr txtAttrib = acaATTR_DFLT,
  `` const char* winTitle = NULL, skForm *formDef = NULL );

        Input  : posRow    : Row    - position of window within the terminal window
                 posCol    : Column - position of window within the terminal window
                 winHeight : Height of window in rows
                 winWidth  : Width of window in columns
                 bdrLine   : (optional, member enum LineType, ltSINGLE by default)
                             border style i.e. type of line for border
                             Note: specifying either ltHORIZ OR ltVERT will cause
                             the border to be drawn with spaces only (no line).
                 bdrAttrib : (optional, acaATTR_DFLT by default, terminal defaults)
                             border color attributes OR'd value of acAttr bitfields
                 txtAttrib : (optional, acaATTR_DFLT by default, terminal defaults)
                             interior color attributes and text modifiers
                             OR'd value of acAttr bitfields
                 winTitle  : (optional, null pointer by default)
                             if specified, text for window title displayed in
                             top border
                 formDef   : (optional, null pointer by default)
                             an 'skForm' object which specifies the
                             position and dimensions of the input fields

        Returns: implicitly returns pointer to object

  Initialization Constructor:
  Four parameters are required: upper-left row, upper-left column, window height (rows) and window width (columns).

  Other parameters, if not specified, are set to default values.

  Example Instantiation:
  `ACWin *winPtr = new ACWin( 1, 1, 24, 80 );`

  Important Note: `'OpenWindow'` should be the first ACWin method called after instantiation because it completes initialization of the internal data; however, all standard AnsiCmd-class methods are available through the window object pointer immediately after instantiation.
  For instance: `winPtr->acCaptureBreakSignal ( true, cchtIgnore, true );`

  Notes:

  1. `'posRow' and 'posCol'` specify the absolute (1-based) position of the window within the terminal display area. This is referred to as the window ‘origin” which is the upper-left corner of the window. If the argument specifies a zero value, it will be silently set to one(1).
  2. `'winHeight' and 'winWidth'` specify the number of rows and columns, respectively defining the dimensions of the window, including the border.
  3. `'bdrAttrib'` defines the color attributes for the window border, and accepts all foreground/background color attributes and text modifiers; however, certain text modifiers are not compatible with line-drawing data, and are silently disabled.
  4. `'txtAttrib'` defines the color attributes for the window interior, and accepts all foreground/background color attributes and text modifiers.
  5. `'winTitle'` specifies an optional title which is centered in the top border of the window.
     Example: `┌───────┤ Wolfie's Favorite Chew Toys ├───────┐`
     It is recommended that the first and last characters of the title text be space characters. This is not enforced, but it allows the title text to be offset from the border line glyphs which makes for better readability.
  6. Initialization of the default `'skForm'` object within the text area of the window is described in the next section. Direct initialization of the skForm gives full control of the number, dimesions and position of the user input fields within the window.
     Please see skForm Class, below for more information.
  7. Within the ACWin object the user input stream (`stdin`) is configured for unbuffered input, non-blocking read of input data and uses the `softEchoA` option to filter keyboard input and echo input to the display.
     Please see acBufferedInput and Soft Echo Options for more information on configuration of the input stream.
- ~ACWin ( void );

        Input  : none

        Returns: nothing

  Destructor: Return all allocated resources to the system before exit.

  The destructor is invoked by deleting the ACWin object. This example creates the default ACWin object, opens the window, closes the window, then deletes the object.
  `ACWin *winPtr = new ACWin;`
  `winPtr->OpenWindow( "Hello World!" );`
  `winPtr->acRead();` // wait for keypress
  `winPtr->CloseWindow();`
  `delete winPtr;`

  If the ACWin object was created as an automatic variable, then the destructor is called when the object goes out-of-scope; that is, when the execution thread exits the scope in which the object was created.
  `void myProgram ( void )`
  `{`
  `ACWin acw;`
  `acw.OpenWindow( "Hello World!" );`
  `acw.acRead();` // wait for keypress
  `acw.CloseWindow();`
  `return;` // object goes out-of-scope here
  `}`

- WinPos OpenWindow ( const char* initText = NULL, short initField = -1 );

        Input  : initText : (optional, null pointer by default)
                            initial text to be written to window
                 initField: (optional, -1 by default) [CURRENTLY IGNORED]
                            index of target field for storing 'initText' data
                            Ignored if 'initText' not specified.

        Returns: cursor position (offset) i.e. text insertion point
                 This is the character cell following the text in 'initText',
                 or if no initial text was specified, the upper-left corner.

  Complete the window setup sequence and display the window within the terminal display.

  For user input fields of the window’s skForm object which have been initialized with text data, the text will be displayed.

  On return, the visible cursor will be positioned at the text insertion point (`IP`) of the field which has the input focus.

  Important Note: `'OpenWindow'` should be the first ACWin method called because it completes initialization of the internal data. If any other ACWin method is called before `'OpenWindow'`, it may cause a reference to uninitialized data.
  All standard AnsiCmd-class methods are available through the window object pointer immediately after instantiation.

- void CloseWindow ( bool clear = true, acAttr fillColor = acaUSEDFLT );

        Input  : clear    : (optional, 'true' by default)
                            if 'true',  clear (erase) the display area
                            if 'false', do not clear the display area
                 fillColor: (optional, terminal dflt attr by default)
                            color attribute used to erase the window.

        Returns: nothing

  Close the window. Relinquish control of the window object.

  By default, the window is erased from the terminal display as part of the closing sequence; but the visual display may optionally be retained, even though control over the space has been returned to the system. This includes returning control of input stream buffering to the system.

  Note that the window object still exists in memory. To release the window’s resources, invoke the destructor i.e. delete the ACWin object.
  `Example: ACWin *winPtr new ACWin ; ... delete winPtr ;`
  or if the window was created as an automatic variable, the object will be deleted when it goes out-of-scope. (see ACWin destructor)

- void RefreshWin ( void );

        Input  : none

        Returns: nothing

  Redraw the window to display any changes that have been made, or to recover when other data have obscured the the window.
  For instance, call `RefreshWin` after a previoius call to `HideWin`.

  The border will be redrawn, the interior of the window will be cleared, and the static text (if any) will be written, and the fields of the skForm object will be redrawn.

- void HideWin ( acAttr fillAttr = acaUSEDFLT );

        Input  : fillAttr : (optional, default: terminal default attributes)
                            color attribute used to erase data from window.

        Returns: nothing

  Temporarily erase the window from the terminal display.
  All window data are retained but are not visible to the user.

  To make the window visible again, call RefreshWin.

- void MoveWin ( const WinPos& newPos, const char *newText = NULL );

        Input  : newPos   : (by reference) new row/column position for window origin
                            (upper-left corner of window)
                 newText  : (optional, null pointer by default)
                            text to be written to interior of window, beginning at
                            the upper left corner of the window interior.

        Returns: 'true'  if success
                 'false' window position not updated if specified position
                         would place any part of the window beyond the edges
                         of the terminal window.

  Move the window to another position within the terminal display.
  This is simply erasing the window, updating the base position and redrawing the window at the new position.

  The author has found this to be a useful way to draw the user’s attention to some needed action, and of course a moving window could be the basis for a customized screen-saver application.

- WinPos ClearWin ( acAttr newAttr = acaUSEDFLT );

        Input  : newAttr : (optional, acaUSEDFLT by default)
                           new color attributes for text area of window
                           (logical OR of forground and background color)
                           (attributes and text modifiers               )

        Returns: Cursor position (text insertion point)
                 This is the upper-left corner of the text area (0/0).

  Erase all text from the interior (text area) of the window.

  The text in the skForm object (if any) is retained, but is not redrawn.
  See also RefreshWin.

- WinPos ClearRow ( short trgRow, acAttr txtAttr = acaUSEDFLT );

        Input  : trgRow  : target row (0-based offset into text area)
                 txtAttr : (optional, acaUSEDFLT by default)
                           new color attributes for text area of window
                           (logical OR of forground and background color)
                           (attributes and attribute modifiers          )

        Returns: Cursor position (text insertion point)
                 This is the left edge of the specified row (trgRow/0).
                 Note: If 'trgRow' is out-of-range, window will not be modified.

  Erase text from the specified row of the text area.

  Note: `ClearRow` does not clear the stored text-field data associated with the target row. To clear a single text field within the window, use the ClearField method instead.

- WinPos Write ( WinPos txtPos, const wchar_t* txtData, acAttr txtAttr = acaUSEDFLT, bool clear = false );
- WinPos Write ( WinPos txtPos, const gString& txtData, acAttr txtAttr = acaUSEDFLT, bool clear = false );
- WinPos Write ( WinPos txtPos, const char* txtData, acAttr txtAttr = acaUSEDFLT, bool clear = false );
- WinPos Write ( WinPos txtPos, wchar_t txtData, acAttr txtAttr = acaUSEDFLT, bool clear = false );

        Input  : txtPos : WinPos-class object indicates the zero-based
                          offset from upper-left corner of window interior
                 txt    : text to write in one of the following formats:
                          -- gString object by reference
                          -- wchar_t pointer
                          -- char pointer
                          -- a single wchar_t character
                 txtAttr: (optional, existing text attributes by default)
                          text attributes and text modifiers
                 clear  : (optional, 'false' by default)
                          if 'false', existing displayed text unmodified
                          if 'true',  erase window interior before write

        Returns: current cursor position (window offset)

  Write text to the interior of the window.
  This group of methods writes directly into the window’s text area, bypassing and obscuring any defined text fields.

  These methods will automatically reformat the text if necessary to ensure that the text does not extend into or beyond the window border.
  Please see acFormatParagraph for more information on automatic text formatting.

  To write text into one of the input fields within the window, see SetFieldText.

- WinPos GetCursorPos ( void );

        Input  : none

        Returns: current cursor position (window offset)

  Get the current cursor offset within the window’s text area.

- WinPos SetCursorPos ( const WinPos& wPos );
- WinPos SetCursorPos ( short rOff, short cOff );

        Input  : Cursor position may be specified in either of 2 ways:
                 wPos : (by reference) offset from upper-left corner of
                        window's text area (0-based offset)
                     OR
                 rOff : row offset
                 cOff : column offset

        Returns: current cursor position (window offset)

  Set the cursor offset within the window’s text area.

- bool SetTitle ( const char* newTitle, acAttr titAttr = acaUSEDFLT, LineType bdrLine = ltHORIZ );

        Input  : newTitle : text of window title
                            (empty string or null pointer erases title)
                 titAttr  : (optional, existing attributes by default)
                            If specified, this is a logical OR of acAttr
                            values specifying the foreground/background
                            color attributes.
                            See the 'acAttr' enumerated type for details.
                 bdrLine  : (optional, ltHORIZ i.e. invalid line type
                             by default) If specified, new border style:
                            ltSINGLE or ltDUAL

        Returns: 'true'  if success
                 'false' if title truncated to fit

  Set the window title.
  Draw the title centered in the top border of the window.

- void SetTextAttr ( acAttr txtAttr );

        Input  : txtAttr : (acAttr bitfield) a logical OR of forground and
                           background color attributes and attribute modifiers

        Returns: nothing

  Set the color attributes and modifiers for the window interior (text area).

- void SetBorderAttr ( acAttr bdrAttr, LineType bdrStyle = ltHORIZ );

        Input  : bdrAttr : (acAttr bitfield) a logical OR of forground and
                           background color attributes and attribute modifiers
                 bdrStyle: (optional, ltHORIZ i.e. an invalid value by default)
                           specify the border line style, either ltSINGLE or ltDUAL

        Returns: nothing

  Set the color attributes and modifiers for the window border.

  Optionally, the line style of the border may be changed by specifying one of the valid border line styles, either ltSINGLE or ltDUAL.

- void WinInfo ( winInfo& wInfo );

        Input  : wInfo: (by reference) a winInfo-class object to receive the data

        Returns: nothing

  Returns a copy of the window’s current size, position, attributes and other basic information.

  This information is used primarly for development and debugging; however, it often may be useful to get a snapshot of the window configuration, especially the `'skf'` and `'tcfg'` structures.

      class winInfo
      {
         public:
         WinPos winBase ;      //* Terminal window offset (1-based)
         short height ;        //* Height of window object (rows)
         short width ;         //* Width of window object (columns)
         short txtRows ;       //* Number of text (interior) rows
         short txtCols ;       //* Number of text (interior) columns
         acAttr bdrAttr ;      //* Color attributes for window border
         acAttr txtAttr ;      //* Color attributes for window interior
         LineType bdrStyle ;   //* Line type for border
         const skForm *skf ;   //* Definition of text fields within the window
         bool  wcbConnect ;    //* Set if connected with Wayland clipboard
         termConfig tcfg ;     //* Terminal configuration data
      } ;

  Note that the current window dimensions and position are not guaranteed to be those specified during instantiation. This is because the constructor range checks and automatically adjusts these values as necessary to fit within the terminal window.

#### Form-Oriented Methods

- wchar_t EditForm ( short& focusFld, short exitField = -1, wchar_t exitChar = NULLCHAR );

        Input  : focusFld : (by reference) receives the index of the field with
                            input focus on return to caller.
                            (initial value ignored)
                 exitField: (optional, default: -1) If specified, this is the index
                            of the ftPB (Pushbutton) control that, when pressed,
                            will cause the loop to terminate, and a return to caller.
                 exitChar : (optional, default: '\0') If specified, when this
                            character is received, the loop will terminate and
                            return to caller.
                            Note: If a callback method has been established which
                            will determine when to return to caller, then 'exitChar'
                            should contain the default value.

        Returns: keycode of last key pressed

  Interactively edit the fields defined within the skForm object.

  The skForm class defines an array of user-interface fields within the window which can be used to create an interactive user interface within a console application.

  Keyboard input is captured, formatted and written into the fields. Certain “special keys” are defined for navigating within and among the fields. These keycodes are discussed in the chapter on terminal configuration.
  Please see Soft Echo Options for more information.

  A technical description of the skForm class and the associated skField class as well as a discussion of user interaction with these objects can be found at: skForm Class and skField Class.

  There are three ways to exit the user-interface loop:

  1. When the Pushbutton control specified by ’exitField’ is pressed.
     Typically, a window will include an ’Exit’, ’Quit’, ’Close’ or similar pushbutton that may be selected by the user to close the window. If defined, the index of this Pushbutton may be specified by the optional ’exitField’ parameter. Then when user selects this control, the loop will terminate and control will be returned to caller. If ’exitField’ contains the default value (-1), then the parameter will be ignored.
  2. When the character specified by ’exitChar’ is received from the user.
     The optional ’exitChar’ parameter may be used to specify that when the specified keycode is received, the loop will terminate and control will be returned to caller. If ’exitChar’ contains the default value (’\0’), then the parameter will be ignored. This is an experimental parameter, and thusfar has not proven to be very useful; however, it remains a valid option.
  3. Via a signal from the callback method.
     To directly monitor user activity within the `EditForm` loop, a “callback” method may be established at the application level. The user interface loop will then invoke the callback method for each keystroke entered by the user.
     Please see EstablishCallback for additional information.
- const skForm* GetForm ( void );

        Input  : nothing

        Returns: pointer to the window's skForm object.

  Get a pointer to the window’s skForm object.
  Note: This is a ’const’ pointer. Contents may not be modified.

  This method is useful when the call to EditForm has returned, because it reports the final contents and states of the `skForm` control array.

  It is also useful during the development process.

  A technical description of the skForm class and the associated skField class as well as a discussion of user interaction with these objects can be found at: skForm Class and skField Class.

- short Get`I`nputFocus ( void );

        Input  : none

        Returns: index of field with focus

  Returns the index of the field within the `skForm` object which currently has the input focus.
  This value may also be obtained directly if a previous call to `GetForm` has initialized a pointer to the internal skForm-class data.
  See GetForm, for more information.

- WinPos Set`I`nputFocus ( short fld`I`ndex );

        Input  : fldIndex: index of target text field
                           The specified field becomes the active field.

        Returns: index of field with focus

  Set input focus to the specified field, and refresh field contents.
  The cursor is placed on the text insertion point (`IP`) of the field.

  Note: Read-only fields cannot receive the input focus.

- WinPos Focus2NextField ( void );

        Input  : none
        Returns: index of field with focus

  Set input focus to the next field, and refresh field contents.
  If already on the last field (index==fCnt-1), wrap around to the first field of the array.

  On return, the cursor is positioned in the field with input focus.

  Note: Read-only fields cannot receive the input focus.

- WinPos Focus2PrevField ( void );

        Input  : none
        Returns: index of field with focus

  Set input focus to the previous field, and refresh field contents.
  If already on the first field (index==zero), wrap around to the last field of the array.

  On return, the cursor is positioned in the field with input focus.

  Note: Read-only fields cannot receive the input focus.

- bool InsertKey ( bool enable, bool initMode, bool styles = false,
  `` CurStyle insStyle = istyleDFLT, CurStyle ovrStyle = ostyleDFLT );

        Input  : enable  : 'true'  == enable user access to Insert key
                                      (this is the default)
                           'false' == disable user access to Insert key
                                      (the mode is locked by application)
                 initMode: initial input mode
                           'true'  == Insert Mode
                           'false' == Overstrike Mode
                 styles  : (optional 'false' by default)
                           Enable or disable automatic change of cursor
                           style when Insert/Overstrike is toggled.
                           'true'  == enable cursor style change
                           'false' == disable cursor style change
                 insStyle: (optional, istyleDFLT by default)
                            cursor style for insert mode
                            referenced only when the 'styles' flag is set
                 ovrStyle: (optional, ostyleDFLT by default)
                            cursor style for overstrike mode
                            referenced only when the 'styles' flag is set

        Returns: 'true' if Insert/Overstrike toggle enabled, else 'false'

  Enable or disable user access to the Insert/Overstrike input mode when user is editing a field, and specify the initial mode.

  Insert/Overstrike toggle is active by default, and the initial mode is Insert Mode. For some fields, or some kinds of data, however, it is useful to set one mode or the other and lock out user access.

  Optionally enable or disable cursor style change when Insert/Overstrike mode is toggled. This provides a visual cue to the user whether Insert mode or Overstrike mode is active.
  Optionally, the cursor style for each mode may be specified as a member of enum CurStyle (excluding csShow and csHide).

- bool ACWin::isInsertMode ( void );

        Input  : none

        Returns: current state of the Insert/Overstrike flag

  Reports the current state of the skForm object’s Insert/Overstrike flag.

  If set, Insert Mode:
  A character written to the target field will be inserted at the current cursor position, which will push trailing text to the right.

  If reset, Overstrike Mode:
  A character written to the target field will replace (overwrite) the text at the current cursor position.

  See also the `InsertKey` method, above.

- bool AlertEnable ( bool enable );

        Input  : enable : if 'true',  enable alert
                          if 'false', disable alert

        Returns: current state of the alert flag

  Enable/disable auditory alert when user presses an invalid key.

  The auditory alert is specified during instantiation of the ACWin/skForm object; however, the alert may be enabled or disabled using this method.
  Please see skForm Class for more information.

- EstablishCallback ( CUPTR methodname );

        Input  : valid pointer to caller's method of the correct type
                 OR NULL pointer to disable existing callback

        Returns: nothing

  Establish (or disable) a callback method which gives the application layer access to user input so that text fields and other controls in the parent window may be dynamically updated.
  The specified method will be called from within the user-input loop of the EditForm method.

  The external method handles situations that the parent window cannot. For example:
  `- secondary validation of text data.`
  `- respond in real time to user keyboard input`
  `- manual update of read-only or hidden controls`
  `- signal that the window is to be closed`

  The following example of specifying a callback function is taken from the `Test_Menu` method in `AnsiCmdTest.cpp`.

         // static non-member pointer providing the non-member
         // callback function with access to the ACWin object.
         static ACWin* tmwPtr = NULL ;

         ACWin *win = new ACWin
               ( winROW, winCOL,          // position (upper-left corner)
                 winHEIGHT, winWIDTH,     // dimensions (height, width)
                 ltSINGLE,                // border style
                 acaBorder,               // border attributes
                 acaInterior,             // interior attributes
                 " ACWin MenuBar and Context Menu ", // window title
                 skfPtr                   // skForm data template
               ) ;

         win->OpenWindow () ;             // make the window visible
         tmwPtr = win ;                   // give callback method access to ACWin object

         // Specify the callback function to be
         // invoked from within the user-input loop.
         win->EstablishCallback ( &tmw_Callback ) ;

         win->EditForm ( f, NULLCHAR ) ;  // interact with the user
         win->CloseWindow ( false ) ;     // close the window

         tmwPtr = NULL ;                  // reset the external pointer (be safe)
         delete ( win ) ;                 // release the allocated resourses

  The callback function is based on the the following template:
  `typedef wchar_t (*CUPTR)( short ctrlIndex,` `wchar_t wkey, bool firstTime );`
  The `'ctrlIndex'` parameter reports the index of the field which currently has the input focus.
  The `'wkey'` parameter reports the keycode from the user interface.
  The `'firstTime'` flag is set ONLY during the initial call which allow the callback function to initialize its internal data.

  The callback function monitors keyboard input and responds to user requests which cannot be handled automatically by `EditForm`.
  For example, if the user “presses” a Pushbutton or sets/resets a Radiobutton, the associated action is performed.

  The most obvious of the callback actions is responding to the Pushbutton control which closes the window and returns control to the terminal window shell program. In this example, the `Exit` pushbutton is selected by the user, either by:
  `1) moving the input focus to that pushbutton and pressing`
  `the 'Enter' (or 'Space') key, or`
  `2) Pressing the "hotkey" associated with the control, which`
  `which in this case is ALT+X.`
  Note that `EditForm` automatically interprets the “hotkeys” associated with individual controls and moves the input focus to that control. Then the `Enter` key is passed to the callback indicating that that control has been “selected”.
  As shown in the example, if the control with focus is the `Exit` pushbutton and if the keycode indicates that the control has been “selected”, then the special `'exit'` keycode is returned, signalling that `EditForm` should terminate the loop and return control to the application level.

         const short fldPB_MBAR = ZERO ;  // index of pushbutton activating menu bar
         const short fldPB_EXIT = ZERO ;  // index of 'Exit' pushbutton

         if ( firstTime )                 // first call
         {
            // initialize static data (if any)
         }

         if ( (wkey == wcsENTER) || (wkey == wcsSPACE) )
         {
            if ( ctrlIndex == fldPB_MBAR )
            {
               . . .
               wkey = L'\0' ;             // signal that keycode was handled
            }
            else if ( ctrlIndex == fldPB_EXIT )
               wkey = wcsCTL_4 ;          // signal loop termination
         }

         return wkey ;

  The received keycode (`'wkey'`) can be returned as received, or can be modified as a signal to the `EditForm` loop.

  If the operation has been fully handled, the callback will return the null character (`L'\0'`).

  If the callback method returns `wcsCTL_4`, it is the signal that `EditForm` should terminate the loop and return to caller. Note that `wcsCTL_4` is the ASCII code for the SIGQUIT signal, and will never be transmitted to the callback method as the `'wkey'` parameter.

  Note: A callback template defining an application-class member method is under development. This will complement the non-member callback described above, and will provide a simpler mechanism for monitoring user activity. This requires `C++17` support, so we have delayed implementation until the community has made the transition.
- KeycodePush ( wchar_t wKey );

        Input  :
           wKey   : keycode to be placed into the queue

        Returns:
           'true'  if keycode successfully pushed into the input queue
           'false' if input queue is full

  Push a keycode into the input stream.
  All valid wchar_t (wide) keycodes are accepted. The maximum number of keycodes which can be pushed into the input stream FIFO queue without an intervening read is defined as KEYPUSH_MAX (currently 16).

  > Keycode FIFO Queue Development

  > Three additional methods are defined for management of the input stream FIFO queue. These are under a conditional compile directive and are used only during development.

  > Clear (reset) the KecodePush FIFO queue.
  > All keycodes in the queue will be discarded. Note that this does not affect data in the system key input stream.
  > ▪ void KeycodePush_Clear ( void );

  > Return the number of keycodes currently in the keycode pushback FIFO queue, and optionally, return a copy of the current contents of the queue.
  > ▪ short KeycodePush_Report ( wchar_t* kfifo = NULL );
  > `wchar_t fifoCopy[KEYCODE_MAX] ;`
  > `short kpCount = win->KeycodePush_Report ( fifoCopy ) ;`

  > Extract a keycode from the keycode pushback FIFO queue.
  > (If the queue is empty, wait for key input from the keyboard.
  > ▪ wchar_t KeycodePush_Pull ( void );

  > Please study the keyPushback class for an example of how a FIFO queue works. Because this is a very small FIFO, it is implemented the easy way, with data shifted each time an item is removed. In a more sophisticated implementation, a dual-indexed wrap-around sequence would be used to enhance performance.

#### Field-Oriented Methods

- bool SetFieldText ( short f`I`ndx, const gString& srcTxt, bool refresh = true );
- bool SetFieldText ( short f`I`ndx, const wchar_t* srcTxt, bool refresh = true );
- bool SetFieldText ( short f`I`ndx, const char* srcTxt, bool refresh = true );

        Input  : fIndx : index of target field within the skForm object
                 srcTxt: text to be written to target field
                         Text data may be in the form:
                         1) gString object (by reference)
                         2) pointer to wide (wchar_t) text data
                         3) pointer to UTF-8 (byte-oriented) text data
                 refresh : (optional, default: true)
                           if 'true',  refresh the field display
                           if 'false', do not refresh the display

        Returns: 'true'  if successful
                 'false' if invalid field index specified, or if operation
                         is not supported for target field type

  Replace the current contents of the field with new data.
  The ’ip’ (text insertion point) of the field is set to zero, and the cursor is set to the field origin.

  Field types for which text data may be modified:
  `1) ftTB (Textbox), 2) ftSB Scrollbox, 3) ftPB (Pushbutton)`
  Text for other field types is set during instantiation and remains static.

- int GetFieldText ( short f`I`ndx, gString& txtBuf ) const;
- int GetFieldText ( short f`I`ndx, wchar_t* txtBuf, int maxChars ) const;
- int GetFieldText ( short f`I`ndx, char* txtBuf, int maxBytes ) const;

        Input  : fIndx   : index of target field within the skForm object
                 txtBuf  : (by reference) receives a copy of field text
                        OR pointer to wchar_t buffer
                        OR pointer to char (UTF-8) buffer
                 maxChars: for wchar_t target buffer, maximum number of wchar_t
                           characters to write
                        OR
                 maxBytes: for char target buffer, maximum number of UTF-8
                           bytes to write

        Returns: number of characters written to target buffer including null
                 terminator (if target is UTF-8 buffer, byte count is returned)
                 -- If invalid field index specified, or if operation is not
                    supported for target field type, the target buffer is set
                    to an empty string, and a zero value is returned.
                 -- If the text is larger than the target buffer, then text
                    will be truncated to fit the target.

  Get a copy of the current contents of the target Textbox (ftTB) field.

  IMPORTANT NOTE: Target buffer must be large enough to hold AT LEAST two(2) wchar_t characters OR five(5) UTF-8 bytes.
  Otherwise, you may as well be working for Microsoft.

- bool SetFieldAttr ( short f`I`ndx, acAttr txtAttr );

        Input  : fIndx   : index of target field within the skForm object
                 txtAttr : (acAttr bitfield) a logical OR of forground and
                           background color attributes and attribute modifiers
                           (note: use of 'underline' modifier not recommended)

        Returns: 'true'  if attribute set successfully
                 'false' if invalid field index specified

  Set the color attributes and modifiers for the specified text field. Refresh the field display using the modified attributes.

  On return, the cursor is positioned in the field with input focus.

- bool SetFieldAttr ( short f`I`ndx, const acAttr* rowAttr, short rowCnt );

        Input  :
           fIndx  : index of target field (ftMB or ftSB only)
           rowAttr: pointer to an array of acAttr color attributes, one
                    attribute for each text row of the control.
           rowCnt : number of attribute values in the 'rowAttr' array (>zero).
                    (The minimum _practical_ value is two(2).

        Returns: 'true'  if attribute set successfully
                 'false' if invalid field index specified, or
                         if field type does not support per-row
                         attributes, or if 'rowCnt' out-of-range

  Set the color attributes and modifiers for the specified field.
  The array of attributes will be applied one per text row within the field.

  Multi-color attributes apply only to Menus (ftMB) and Scrollbox (ftSB) controls. These control types contain data which is not edited, and therefore the color specified for each row will remain unchanged until the window is closed.

  It is recommended that this method be called AFTER instantiation of the ACWin object, but BEFORE the call to `OpenWindow`. If called after the window has been opened, then on return from the call, the application should refresh the display explicitly. This will ensure that the changes are visible.

  To specify per-row color attributes for controls within an `ACDlg` sub-window, please see colorConfig.

- bool SetField`IP` ( short f`I`ndx, short new`I`p, bool centered = false, bool refresh = true );

        Input  :
           fIndx   : index of target field
           newIp   : character offset into the text of the field
                     ZERO <= newIp <= text characters
                     where ZERO == field origin and any value at or beyond
                     the number of characters in the array signals that IP
                     should be set to end-of-text.
           centered: (optional, default:false) vertically center
                     the row containing the IP within the field.
           refresh : (optional, default:true) refresh display
                     if 'true'  make changes visible
                     if 'false' do not update display

        Returns: 'true'  if successful
                 'false' if invalid field index specified

  Set the insertion point (`IP`) for the field. This will set the cursor position over the character at the specified offset.

  Field types supported by this method are:
  `1) ftTB (Textbox) 2) ftSB (Scrollbox).`
  Insertion point for other field types is managed programatically.

  Scrolling to ensure that new IP position is within visible space:

  1. If target IP is already within visible space no scrolling will occur; the cursor will simply be placed over the target character.
  2. If target IP is above visible space, the row containing the cursor will be positioned at the top row of the field.
  3. If target IP is below visible space, the row containing the cursor will be positioned at the bottom row of the field.
  4. The optional `'centered'` parameter will further adjust the position of the row containing the target IP so that it will be vertically centered within the field.
     Technical Note: The vertical centering option is fully functional; however, the implementation requires three(3) display updates rather than the one update needed if centering is not specified. (It’s cute, but it’s slow, so be aware!)

  If `'fIndx'` references the field which has input focus, the visible cursor will also be updated by default, but see the `'refresh'` parameter.

  Special case: If `'newIp'` is greater that the number of characters in the field, IP will be set to end-of-text (referencing the null terminator).

  Example

  For example, if user wants to find a tune in the playlist, she will type in a keyword or phrase and the application will locate the token and bring that song title into the visible space.

  ╔══════╣ Bryan Adams Play List ╠══════╗ ║▶ All for One, All for Love ║ ║ Baby When You're Gone ║ ║ Back To You ║ ║ Brothers Under The Sun ║ ║ Can't Stop This Thing We Started ║ ║ Christmas Time ║ ║ Cloud Number Nine ║ ║ Desire ║ ║ Do I Have To Say The Words ║ ║ ──────────────────────────────────────║ ║ Find: Get Off ║ ║ ──────────────────────────────────────║ ║ PLAY CANCEL ║ ╚═══════════════════════════════════════╝

  (Simplified) Code

      enum fieldNames : short
      {
         fnLIST = ZERO,
         fnFIND,
         fnPLAY,
         fnCANCEL,
         fnFIELDS
      }

      int trgetIp ;
      gString gsList, gsFind ;
      // Get text of "List" field
      win->GetFieldText ( fnLIST, gsList ) ;
      // Get text of "Find" field
      win->GetFieldText ( fnFIND, gsFind ) ;
      // Set focus to list field
      win->SetInputFocus ( fnLIST ) ;

      // Search for token in the list
      if ( (targetIp = gsList.find( gsFind.gstr() )) >= ZERO )
      {
         // Set Insertion Point to first character of token
         win->SetFieldIP ( fnLIST, targetIP, true, true ) ;
         // Clear the search text
         win->SetFieldText ( fnFIND, "", true ) ;
      }
      // Display error message
      else
         win->SetFieldText( fnFIND, "Title Not Found", true ) ;

  ╔══════╣ Bryan Adams Play List ╠══════╗ ║ Desire ║ ║ Do I Have To Say The Words ║ ║ Don't Let Go ║ ║ Everything I Do ║ ║▶ Get Off My Back ║ ║ Have You Ever Really Loved A Woman ║ ║ Heaven ║ ║ Here I Am ║ ║ I Finally Found Someone ║ ║ ──────────────────────────────────────║ ║ Find: ║ ║ ──────────────────────────────────────║ ║ PLAY CANCEL ║ ╚═══════════════════════════════════════╝

  For a more complex example, see `'gotoLine'` method of the AcEdit Demo App.

- int GetFieldIP ( short f`I`ndx );

        Input  : fIndx   : index of target field

        Returns: current character offset into the text of the field
                 (if invalid field index specified, zero will be returned)

  Get the current insertion point (IP) for the specified field.

  Note that although this method returns the IP value for all control types, this value will be meaningful only for Textbox (ftTB) fields, and possibly Scrollbox (ftSB) fields. For other types of controls IP and cursor position are not meaningful.
  For controls with “selectable items” i.e. menus (ftMB) and Scrollbox (ftSB) controls, refer to the `GetFieldItem` below, or to the `skField-class` getItem method.

- bool GetFieldItem ( short fIndx, short& itemIndex, wchar_t& itemHotkey, gString* itemText = NULL );

        Input  :
           fIndx     : index of target control
           itemIndex : (by reference) receives (0-based) index of item which
                       is referenced by the IP
           itemHotkey: (by reference) receives the "hotkey" character (if any)
                       for that item.
                       If no hotkey indicator found, '?' is returned.
           itemText  : (optional, default: null pointer)
                       If specified, this is a pointer to a gString object
                       which will receive the text of the target item.

        Returns:
           'true'  if successful
           'false' if invalid field index or target is of unsupported
                   control type
                   'itemIndex' will be set to -1 and
                   'itemHotkey' will be set to '?', and
                   'itemText' if specified, will be set to an empty string.

  For Menus (ftMB) and Scrollbox controls (ftSB), retrieve the index of the `"item"` (row) containing the insertion point (`'ip'`). Generally, this is the currently hightlighted item or the item which was highlighted when the control lost focus. The “hotkey” character for the item (if any) is also extracted from the item text.

  This method will typically be called from the application’s callback function after the item-selection signal (Enter key) is received; however, a prior item selection is not necessary. It is also useful after return from the EditForm method.

  This method calls the low level (but still public) `skField`-class `getItem` method. This low-level method is intended primarily for use by dialog-oriented callback functions, and is somewhat more difficult to use. The `GetFieldItem` method makes the operation somewhat less painful.
  Please see skField Public Methods for more information.

- bool SetFieldState ( short fIndx, bool state, bool refresh = false );

        Input  : fIndx   : index of target field within the skForm object
                 state   : if 'true',  set field state
                           if 'false', reset field state
                 refresh : (optional, 'false' by default)
                           if 'true',  refresh the field display
                           if 'false', do not refresh the field

        Returns: current state of the field

  Set the "state" of a binary field.
  Currently, this applies only to Radiobuttons (type==ftRB).

  When the binary state is `'set'`, the indicator character is displayed between the delimiters:
  `[♦]` Allow your internet provider to sell your personal info.
  When the state is `'reset'`, the indicator character is replaced by a space character.
  `[ ]` Allow your internet provider to sell your personal info.

- bool GetFieldState ( short fIndx, short* xorMember = NULL );

        Input  :
           fIndx    : index of target field within the skForm object
           xorMember: (optional, default: null pointer) for XOR groups only
                      if specifed, the referenced variable receives the index
                      of the control whose 'set' flag is 'true.

        Returns:
           current state of 'state' flag for field referenced by 'fIndx'

  Get the current "state" of a binary field.
  Currently, this applies only to Radiobuttons (type==ftRB).

  XOR Groups:

  For radiobutton XOR groups, the binary state for only one member of the group can be “set” i.e. ‘true’. If `'fIndx'` references a member of an XOR group, and if the `'xorMember'` pointer is non-null, then the variable referenced by `'xorMember'` receives the index of the group member whose flag is “set”.

  - If the control referenced by ’fIndx’ is not a Radiobutton or is not a member of an XOR group, then ’xorMember’ is ignored.
  - Note that in the (unlikely) case where no member of the XOR group has its flag set, `'xorMember'` will receive the `'fIndx'` value.
- void SetFieldFlow ( short f`I`ndx, FloType fType, bool refresh = false );

        Input  : fIndx   : index of target text field
                 fType   : member of enum FloType
                 refresh : (optional, 'false' by default)
                           if 'true',  immediately reformat field text
                                       and update the display
                           if 'false', text is reformatted, as needed but
                                       display is not updated

        Returns: 'true'  if flow option set successfully
                 'false' if invalid field index specified or if target field
                         is a single-row field or invalid 'fType'

  Set the text-flow type and optionally reformat the existing text.
  Note that this option applies only to multi-row text fields. Text of single-row fields is always truncated at the edge of the field (see flowShift option).

  The available text-flow options are specified by enum FloType and are:

  1. `floToken` – Automatic text wrap by token. A “token” is a sequence of characters delimited by whitespace or in certain cases, also by punctuation.
     In general, the application should format the text in the `'txt'` member as desired; however, if necessary, the text will be automatically reformatted to fit within the field.
     To do this, any existing newline characters (’\n’) in the source text are removed, and the text data are reformated to fit within the specified height and width of the field. If lines of text must be wrapped to keep them within the boundaries of the field, then line breaks will be inserted after the last whitespace character that fits on the line. Whitespace characters are defined as one of the following:
     `ASCII Space (U+0020)`
     `CJKSPACE (U+3000)`
     `CJKCOMMA (U+3001)`
     `CJKSTOP (U+3002)`
  2. `floHyphen` – Same as `'floToken'` above, with the addition of the following hyphen-like characters being recognized as whitespace.
     `ASCII Minus (U+002D)`
     `uMINUS (U+2212) HTML &minus;`
     `nDASH (U+2013) HTML &ndash;`
     `mDASH (U+2014) HTML &mdash;`
     `sDASH (U+00AD) HTML &shy;`
  3. `floChar` – Automatic text wrap by character.
     This is the brain-damaged form of inserting line breaks, in that the breaks are inserted after the last character that will fit on the line. Although this is not pretty, it is faster than scanning for whitespace, and is useful if you are not sure whether each text row will fit the available space.
     Note that if the text has been preformatted to fit within the field, then this option will not alter formatting of the output.
  4. `floShift` – This option disables word wrap. Instead, each text row that is too wide to fit in the field will be truncated for display to avoid violating the field boundaries. Note that the source text itself is not altered; only the displayed data are affected.
     This is what might be described as “text-editor mode.” The data are shifted both vertically and horizontally as the user scrolls through the data. This is in contrast to the `'floToken'` formatting described above in that `'floToken'` data are only scrolled vertically.
  5. `floDflt` – This option is used as a placeholder for optional call parameters, and is interpreted to mean that the existing word-wrap option is not to be modified.

  For more information on auto-formatting please refer to acFormatParagraph or the gString-class method, formatParagraph.

- bool SetFieldLabel ( short fIndx, const char* labText, acAttr labAttr = acaUSEDFLT, bool center = false );

        Input  :
           fIndx   : index of target field
           labText : display text, optionally including a "hotkey" character.
                     A hotkey is specified using the CARET character ('^')
                     followed by the ASCII character which indicates the
                     keycode to be used as a hotkey. (see examples)
           labAttr : (optional, default: text attributes of parent window)
                     color attributes for label text.
           center  : (optional, 'false' by default) horizontal offset
                     if set, center the label horizontally in the row above
                             the field
                     if reset, label is positioned one row above and in
                             the same column as the left edge of the field

        Returns: 'true' if label successfully written, else 'false'

  Assign a label, with or without embedded hotkey, to the specified field.

  - Labels may be assigned only to Textbox (ftTB) and Scrollbox (ftSB) controls.
  - Labels are incompatible with Menubox controls (FldType ftMB).
    see SetFieldHotkey for setting hotkeys for menu controls.
  - This method may not be used for Pushbuttons and Radiobuttons.
    This is because for Pushbutton (ftPB) and Radiobutton (ftRB) controls, the label (and optional hotkey) are integrated into the control definition.
  - Label length: `1 <= length <= labelLEN`. This is the storage capacity expressed as the maximum number of characters (currently 64) for a label. Text will be truncated if necessary to fit the storage array.
  - Label width (columns): Text will be truncated if necessary to avoid violation of window border.
  - The range of valid hotkeys is: `wcsALT_A <= hotkey <= wcsALT_RB`. This corresponds to `ASCII A-Z, a-z`, and most punctuation characters.
    The specified hotkey should be unique within the window.
  - The label is positioned one row above the target field with the horizontal offset determined by the ’center’ parameter.
    If the position conflicts with another object in the window, the display data may be corrupted. You have been warned!
  - Example of a label containing a hotkey specification:
    `"Gra^pefruit"`
    where the caret preceeds `'p'`, indicating that the hotkey is the `ALT+p` key combination which is assigned to the `wcsALT_P` keycode constant.
  - Technical Notes:
    - Label may not extend into the window border.
    - Label may not be an empty string.
    - Label may not contain newline characters. If it does, they will be silently removed.
    - If label includes a hotkey, it must be one of the defined valid hotkeys. The specified hotkey must be unique to the window. No other control may be assigned the same hotkey.
    - It is the application’s responsibility to ensure that the label does not violate the space reserved for any other item. A programatic test for such a violation would just be too expensive.
    - If the target field is to have BOTH a border and a label, then call the SetFieldOutline method instead.

  The following is a screenshot of a window demonstrating both field labels and field outlines. This test window may be found in the `Test_Form` method in `AnsiCmdTest.cpp`.

  ┌──────┤ Window Formatted With "skForm" ├─────┐ │ Animals(ALT+A) Vegetables(ALT+V) │ │ │ │ Tab among fields. Edit the fields as desired.│ │ "Hotkeys" == ALT key + underlined character. │ │ ┌Multi-row Field───────────────────────────┐ │ │ │Edit keys are: Left, Right, Home, End, │ │ │ │Tab, Shift+Tab, PageUp, PageDown, plus │ │ │ │Backspace, Delete and Insert. │ │ │ └──────────────────────────────────────────┘ │ │ ┌Empty Field─────────┐┌TiengViet Field─────┐ │ │ │ ││Gặp tôi ở Sai Gon. │ │ │ └────────────────────┘└────────────────────┘ │ │ ┌Zhongwen Field────────────────────────────┐ │ │ │这他妈的并不像看起来那么容易。 │ │ │ └──────────────────────────────────────────┘ │ │ [♦] Blue Border [ ] Alt. Interior │ │ [ ] Yellow Border Alternate Outlines │ │ [ ] Green Border [♦] Ins/Ovr Key │ │ ╔══════Scrolling - View Only════════╗ │ │ ║ There once was a man from Kirkuk, ║ │ │ ║ Known far and wide for his luck, ║ │ │ ║ Till while jogging one day, ║ │ │ ╚═══════════════════════════════════╝ │ │ ╔══════════════════════╗ │ │ ║ EXIT - 出口 - Salida ║ │ │ ╚══════════════════════╝ │ └──────────────────────────────────────────────┘
- bool SetFieldOutline ( short fIndx, LineType lType, acAttr lnAttr );

        Input  : fIndx   : index of target field
                           if 'fIndx' == number of fields defined, then draw an
                           outline around each field.
                 lType   : (optional, ltSINGLE by default) line style
                            member of enum LineType: ltSINGLE or ltDUAL
                 lnAttr  : (optional, acaUSEDFLT by default)
                           If specified, color attributes to be used.
                           If not specified, stored text attributes used.

        Returns: 'true'  if successful
                 'false' if invalid field index or insufficient space
                         around the target field

  Draw an outline around the outside of the specified field within the window border. The contents of the field will be refreshed after the border is drawn.

  The target field must have at least one space open on all sides. That is, it must not be positioned against the window border, and must not be adjacent to any other field.

  This method calculates the position and dimensions for the outline and then calls the DrawBox method described elsewhere in this document.

  Note: Potential incursion into the border is range checked; however, potential incursion into other fields is not tested. Beware!

  For Textbox (ftTB) and Scrollbox (ftSB) controls, a label may optionally be assigned to the field. This label will be positioned in the upper border of the field outline.
  Please see SetFieldLabel for additional information.

  ┌───────────────────┤ Outline Demo ├────────────────────┐ │┌─ Oscar Wilde ───────────────────────────────────────┐│ ││▒▒▒▒Be yourself; everyone else is already taken.▒▒▒▒▒││ │└─────────────────────────────────────────────────────┘│ │ │ │┌─────────────────── Old Uncle Ben ───────────────────┐│ ││With great power comes great responsibility.▒▒▒▒▒▒▒▒▒││ │└─────────────────────────────────────────────────────┘│ │ │ │ ╔══════ Quiet Garden ══════╗ │ │ ║ ║ │ │ ║ In my quiet garden ║ │ │ ║ The fish are so polite ║ │ │ ║ They seldom speak ║ │ │ ║ To interrupt my reverie. ║ │ │ ║ 马伦 — 2013 ║ │ │ ╚══════════════════════════╝ │ │ ╔══════════╗ │ │ ║ EXIT ║ │ │ ╚══════════╝ │ └───────────────────────────────────────────────────────┘
- bool SetFieldHotkey ( short fIndx, wchar_t hotKey );

        Input  : fIndx   : index of target field within the skForm object
                 hotKey  : hotkey character

        Returns: 'true' if hotkey set successfully
                 'false' if invalid control index, unsupported control type,
                         specified keycode is not one of the valid hotkey
                         characters, target control's hotkey was previously set

  Set the `"hotkey"` for the specified control. A hotkey is a character used to move the input focus to the associated control.

  - The range of valid hotkeys is: `wcsALT_A <= hotkey <= wcsALT_RB`.
    This corresponds to the `'ALT'` key plus `ASCII A-Z, a-z,` and most punctuation characters.
  - The majority of `CONTROL+ A-Z` characters are also available as hotkeys.

    Technical Note: A conditional compile directive controls whether these keycodes when received, will be automatically converted to the equivalent ALT+n keycode. See the private `isHotkey` method for details.

    When this conversion is enabled, if user presses one of the CTL+n keys, it will be automatically converted to the equivalent ALT+n keycode, and the converted keycode will be used to perform the action specified for that hotkey.
    For example: If the hotkey `ALT+B` is assigned to a Pushbutton control via the text of the control:
    “`^BACKUP` ”,
    then the control would be displayed with the `'B'` underlined.

    > BACKUP

    The user may then select the control using either `ALT+B` (wcsALT_B) or `CTL+B` (wcsCTL_B) which will have been converted to wcsALT_B.

    When this conversion is disabled, then `CTL+B` and `ALT+B` are seen as different hotkeys.

    Certain Control+n keycodes are reserved as specific command keys. For example, the `'wcsCTL_C', 'wcsCTL_X', 'wcsCTL_V'` are reserved for “Copy”, “Cut” and “Paste” respectively. Please see ASCII Control Codes for a further information.

  - The function keys may also be used as hotkeys: `wcsF01 <= hotkey <= wcsCF12`
  - The specified hotkey should be unique within the window.

  Please see test A which describes these keycodes in further detail.
  Refer also to the source code for the private methods `isHotkey` and `isFunky` which define the full range of available hotkeys.

  Note that the standard method for hotkey specification is to embed the hotkey character in the control label so that the user has a visual cue, (see SetFieldLabel).
  Menubox controls (ftMB) do not have labels. For this reason, if a hotkey is desired for a menu control, it must be set during skField instantiation (see skForm Class), OR via this method after ACWin instantiation.

  This method may also be used to set the hotkey for some other types of controls (ftTB, ftSB), but this is not recommended because there would be no visible cue to assist the user.

  Note that for Pushbutton and Radiobutton controls, the label (and therefore the hotkey, if any) are embedded in the control itself; and therefore this method may not be used to set the hotkey for those control types. Note also that if a hotkey has been previously specified for the target control, it will not be overwritten by this method.

- bool SetFieldHidden ( short fIndx, bool hidden, bool readOnly, bool refresh );

        Input  :
           fIndx    : index of target field within the skForm object
           hidden   ; if 'true',  field will become invisible when the window
                                  is refreshed
                      if 'false', field will become visible when refreshed
           readOnly : if 'true',  field cannot receive input focus
                      if 'false', field can receive input focus
           refresh  : if 'true',  if 'hidden' is set, refresh the entire
                                     window interior
                                  if 'hidden' is reset, refresh only the
                                     target field
                      if 'false', display is not updated

        Returns: 'true'  if operation successful
                 'false' if operation fails (invalid field index)

  Set the visible/hidden state of the target control and optionally refresh the display.

  Except for menu controls, all controls are set as visible by default; however, for complex user interface configurations, it is common for some inactive controls to be obscured by other controls. Those obscured controls become visible and active when needed and then return to the background. In this way, a creative use of the `'hidden'` and `'read-only'` flags can make efficient use of the limited space within the terminal window.

  As an example, the `AcEdit` application included in this package defines at least fourteen controls which share the application window: a menu group, a line-number field, a gutter field, a context menu and five overlapping controls for editing text: upper/lower, left/right and full-window textbox controls. See AcEdit Demo App for details.

  Making the changes visible:

  1. If target control is set as ’hidden’, AND if ’refresh’ is specified, then the entire window interior will be refreshed to restore display of any controls or static text that had been obscured by that control.
  2. If target control is set visible, AND if ’refresh’ is specified, then only the target control will be refreshed.
- bool SetReadOnly ( short f`I`ndx, bool set );

        Input  : fIndx   : index of target field within the skForm object
                 set    : if 'true',  set field as read-only
                          if 'false', set field as user-accessible

        Returns: current state of the read-only flag

  Enable or disable read-only state for the specified field.

  If a field is set as read-only, then it cannot receive the input focus; and therefore cannot be accessed by the user. A field which has been set as read-only may or may not be visible (see SetFieldHidden above).

- bool SetFieldData ( short f`I`ndx, const gString& srcTxt, acAttr txtAttr = acaUSEDFLT,
  `` short new`I`p = ZERO, bool refresh = true );
- bool SetFieldData ( short f`I`ndx, const wchar_t* srcTxt, acAttr txtAttr = acaUSEDFLT,
  `` short new`I`p = ZERO, bool refresh = true );
- bool SetFieldData ( short f`I`ndx, const char* srcTxt, acAttr txtAttr = acaUSEDFLT,
  `` short new`I`p = ZERO, bool refresh = true );

        Input  :
           fIndx   : index of target field within the skForm object
           srcTxt  : (by reference) new text data for field
           txtAttr : (optional, default: acaUSEDFLT, indicating that
                     current attributes should not be modified)
                     acAttr bitfield which is a logical OR of forground and
                     background color attributes and text modifiers
           newIp   : (optional, zero(0) by default)
                     character offset into the text of the field
                     ZERO <= newIp <= text characters
                     where ZERO == field origin and any value at or beyond
                     the number of characters in the array signals that IP
                     should be set to end-of-text.
           refresh : (optional, default:true) refresh display
                     if 'true'  make changes visible
                     if 'false' do not update display

        Returns: 'true'  if successful
                 'false' if invalid field index specified

  Set or modify the setup data for the specified field.

  The effect is the same as seperately calling three individual methods:
  SetFieldText, SetFieldAttr and SetFieldIP (see above),
  except that this method is more efficient if modifying multiple parameters.

  Not all parameters apply equally to all field types. Some combinations of field-type and configuration settings are fixed on instantiation, and some configuration settings are managed internally by the library methods.

  Legend: 1) "modify" value may be modified under application control. (Note that timing may be an issue, so make modifications) (only when target field does not have focus. ) 2) "static" indicates that value is set during instantiation and cannot be modified. 3) "program" value is programatically managed by the library. Field Text Color Ins. Type Data Attr Point ----- ------ ----- ------ ftTB modify modify modify ftSB modify modify modify ftPB modify modify static ftRB static modify static ftMB static modify program
- bool GetFieldData ( short fIndx, skField& skfld ) const;

        Input  : fIndx   : index of target field within the skForm object
                 skfld   : (by reference) receives a copy of data members

        Returns: 'true'  if successful
                 'false' if invalid field index specified

  Get a copy of the current settings for the specified field.
  This method is intended primarily for reporting data during development; however, this method may also be useful at the application level for analysis of the field data after the EditForm method has returned control to the application.

  NOTE: All data members including protected members are reported.

  Please see skForm Class for details on the structure and usage of the `skField-class` data members.

- void RefreshField ( short f`I`ndx );

        Input  :
           fIndx: index of target field
                  If fIndx < ZERO || fIndx >= total of fields defined (fCnt),
                  then all fields will be refreshed.

        Returns: nothing

  Refresh (erase and redraw) the contents of the specified field, or optionally, refresh all fields defined by the skForm object.

  Input focus remains on the currently active field, and cursor is returned to insertion point within that field.

  Technical Note:

  There are two ways to refresh the field labels or field outlines in addition to the field itself. The first is to set `'fIndx'` to `'fCnt'` when calling this method, so that all fields will be refreshed. The other is to call RefreshWin instead. Either option will redraw the data for all fields, while `RefreshWin` will also redraw any static text in the window.

- void RefreshField ( void );

        Input  : none

        Returns: nothing

  Refresh (erase and redraw) the contents of the field which currently has input focus.

- bool ClearField ( short f`I`ndx, bool delText = false, acAttr txtAttr = acaUSEDFLT );

        Input  :
           fIndx   : index of target field
           delText : (optional, 'false' by default)
                     if 'true',  delete the stored text of the field
                     if 'false', stored text is not modified
           txtAttr : (optional, acaUSEDFLT by default)
                    color attributes for the operation
                    (logical OR of forground and background color)
                    (attributes and text modifiers               )
                     -- If not specified, then current field attributes
                        will be used.
                    if 'delText' is set: field attributes will be updated
                    if 'delText' is reset: specified attributes will be used
                                 for the clear operation, but won't be saved

        Returns: 'true'  if target field cleared
                 'false' if fIndx out-of-range or if field type of target
                         is not supported by this operation (data not modified)

  Erase text from the specified text-field display. Optionally, the stored text is also deleted.

  This operation applies ONLY to fields with editable text, specifically, Textbox fields (field type: ftTB).

- bool ReformatFieldText ( short fIndx, FloType floType = floDflt );

        Input  :
           fIndx  : index of target field
           floType: (optional, 'floDflt' by default) member of enum FloType
                    specify the type of text formatting to be used
                    If 'floDflt', use the existing formatting option;
                    otherwise, set the formatting type to the specified
                    value before reformatting the data.

        Returns: 'true'  if operation is successful
                 'false' if a) invalid field index specified
                            b) target field is not a multi-row textbox
                               field (ftTB)

  Reformat text of the target field using the specified formatting type. All existing newline characters are removed and the data are reformatted according to the specified formatting option.
  `1)` Set new formatting option if specified.
  `2)` Remove existing formatting (newline characters).
  `3)` Reformat the data.
  `4)` Set IP and logical cursor to field origin (upper-left corner).
  `5)` Refresh the display.

  This operation applies ONLY to multi-row textbox fields (ftTB).
  Note also that target field should not have the input focus when data are reformatted because it could easily confuse the poor user.

  See also: SetFieldFlow which sets the formatting option, and reformats the data only if necessary to keep the text within the field boundaries.

- bool ScrollFieldText ( short fIndx, short steps );

        Input  : fIndx   : index of target field
                 steps   : number of rows to scroll

        Returns: 'true'  if successful scroll
                 'false' if already at limit in specified direction

  Scroll upward or downward through multi-row text fields under program control.

  This method applies only to multi-row fields Textbox (ftTB) and Scrollbox (ftSB), and is ignored for single-row fields and other field types.

  Examples:
  (note how the sign of the shift determines direction of scroll)
  `steps == 1` scroll up by one row (bring rows below into view)
  `steps == -1` scroll down by one row(bring rows above into view)
  `steps == hgt` scroll upward by one page
  `steps == -hgt` scroll downward by one page
  `steps == 0` scroll to the first row of text
  `steps == 999` scroll to the last row of text. Note that any value
  `` at or beyond the last text row will signal a move
  `` to end-of-text.

  This much-too-complex example demonstrates the concept: // Create and open the window ACWin* win = new ACWin ( ... ); ... win->OpenWindow (); // Get a pointer to the live data const skForm* skfp = win->GetForm (); short trg = 4, // target field txtHeight, // text dimensions txtWidth ; win->ParagraphSize ( skfp->fld[trg].txt, txtHeight, txtWidth ); // Scroll downward by one row win->ScrollFieldText ( trg, 1 ); // Scroll upward by one row win->ScrollFieldText ( trg, -1 ); // Scroll downward by one page win->ScrollFieldText ( trg, skfp->fld[trg].hgt ); // Scroll upward by on page win->ScrollFieldText ( trg, -(skfp->fld[trg].hgt) ); // Scroll to end-of-text win->ScrollFieldText ( trg, txtHeight ); // Scroll to top-of-text win->ScrollFieldText ( trg, 0 );
- bool ShiftFieldText ( short fIndx, short steps );

        Input  :
           fIndx : index of target field
           steps : direction of shift
                   positive value: shift text upward by one row
                   (toward bottom of text)
                   negative value: shift text downward by one row
                   (toward top of text)

        Returns:
           'true'  if successful shift and/or cursor movement
           'false' if already at limit in specified direction
                   or target control does not support text shift
                   or parameterout-of-range

  Perform a vertical block shift of Textbox data, either upward or downward.
  This method applies only to multi-row Textbox (ftTB) controls.

  This is similar to the ScrollFieldText method which steps the cursor through the rows of text data, EXCEPT that for `ShiftFieldText`, the cursor position remains constant (continues to reference the same character) unless the shift would place it outside of the visible space.

  Technical Note: The ‘steps’ parameter is currently limited to a single-row shift: `-1 <= steps <= 1`. It would be possible to implement a multi-row shift; however, the usefulness of that enhancement is not currently apparent.

- bool HilightFieldText ( short fIndx, bool set, int begin, int len, acAttr txtmod = acaUSEDFLT, bool center = false );

        Input  :
           fIndx : index of target field
           set   : if 'true',  highlight the text segment
                   if 'false', clear the highlight
           begin : index of first (leftmost) character to highlight
                   (referenced only when 'set' != 'false')
           len   : number of characters in highlighted segment
                   Note: If segment spans rows, be sure to include
                         the newlines in the count.
                   (referenced only when 'set' != 'false')
           txtmod: (optional, default:acaUSEDFLT)
                   text modifier attribute for highlighted text segment
                   - If specified, text modifier attribute for highlighted
                     text segment. One of the following:
                      acaBOLD      bold-text modifier
                      acaITALIC    italic-text modifier
                      acaUNDERLINE underline-text modifier
                      acaOVERLINE  overline-text modifier
                      acaXOUT      x-out (strikethrough) text modifier
                      acaBLINK     blinking-text modifier
                      acaCONCEAL   concealed (invisible) text
                      acaREVERSE   reversed fgnd/bkgnd (default attribute)
                      Note: OR'd combinations of these modifiers are not allowed.
                   - If not specified, then use previously-specified modifier
                     (if any), else acaREVERSE (fg/bg attributes reversed)
            center: (optional, default: true)
                    if set, assure that highlight is within visible
                            space by adjusting the IP if necessary.
                    if reset, do not adjust IP (highlighted text
                            may or may not  be visible).

        Returns:
           'true'  if highlight set/cleared
           'false' a) 'fIndx' references an upsupported control type
                   b) parameter out-of-range

  For Textbox controls only (ftTB), highlight a segment of text using one of the text-modifier attributes. If the target field is currently visible, the field will be refreshed before return.

  Note that while any combination of the `acAttr` color attributes may be freely OR’d under most circumstances, for this method, exactly one text-modifier attribute may be specified as the highlight attribute.

  Example: // For a field containg a list of animals, highlight // the word 'kangaroo' if found in the text: const char* Kanga = "kangaroo" ; const int KangaLen = 8 ; const acAttr txtMod = acaREVERSE ; gString gsTxt ; int hl_begin ; win->GetFieldText ( ZOO_TBOX, gsTxt ) ; // get a copy of field text // If the target word is present in the text, highlight it // by specifying the index of the first character and the // number of characters to be highlighted. if ( (hl_begin = gsTxt.find( Kanga )) >= ZERO ) { win->HilightFieldText ( ZOO_ANIMALS, true, hl_begin, KangaLen, txtMod, true ) ; }

  For a functional example, please execute the highlighting test:
  `./epts --test=Wh`

  Technical Notes:

  1. Text highlighting uses the same algorithm as the text-selection (copy/cut/paste) functionality, and shares some data members with that function. For this reason, within a single Textbox field, “highlighted” text cannot be present simultaneously with “selected” text. Highlighted data and selected data may be present simultaneously in different Textbox fields.

     Calling this method will release any “selected” segment in the target field. If the user selects text using any of the selection keys:
     `(Shift + Left/Right/Up/Down or ALT + A)`, it will release any highlight within the field.
     Please see AnsiCmd Clipboard Access for a discussion of text selection and moving text to and from the clipboard.

  2. Note that if the highlighted segment is positioned outside the visible text area of the field, then by default (`'center=true'`), the text will be scrolled to bring the highlighted segment into view and will be (approximately) centered within the visible space.
     If centering is not specified, no scrolling will occur, and the highlighted segment may or may not be visible.
  3. The text-selection modifier is acaUNDERLINE, so this modifier is not recommended as a highlight modifier because it would tend to confuse the poor user.
  4. Using the same text-modifier attribute in both the base color attribute for field text and as highlight modifier will cause visual anomalies, so please choose a highlight attribute which will avoid this conflict. For instance, if the base attribute for the field is:
     `acAttr(acaFG_BLUE | acaBG_CYAN | acaITALIC)`
     then `acaITALIC` should not be used as the highlight attribute.
  5. For dialog windows, please see Dialog_Hilite.
  6. Text hilighting is currently available only for Textbox (ftTB) controls; however, support for highlighted text within Scrollbox (ftSB) controls may be added in a future release.
- bool SetHilightMod ( short fIndx, acAttr txtmod );

        Input  :
           fIndx : index of target field
           txtmod: text modifier attribute for highlighting text segments

        Returns:
           'true'  if highlight attribute initialized
           'false' a) 'fIndx' references an upsupported control type
                   b) parameter out-of-range (default parameter set)

  For Textbox controls only (ftTB), set the text-modifier attribute to be used for highlighting text segments within the field.

  Note that no text is actually highlighted by this method; only the attribute is initialized.
  Please see the HilightFieldText method, above for additional information.
  See also the `skField` setHiliteMod method.

#### Dialog-Oriented Methods

A dialog is a small window within the parent window which provides information to the user, and optionally asks for a decision or gathers other information from the user. Please see Dialog sub-Windows for a more detailed discussion of Dialog window functionality.

- bool QuickDialog ( const gString& gsMsg, bool query, const char* title = NULL,
  `` short height = 0, short width = 0, short vOff = 0, short hOff = -1,
  `` short timeout = 0, bool dbg = false );

        Input  :
            gsMsg : (by reference) contains the message(s) to be displayed.
                    The text may be a formatted paragraph with each text
                    row terminated by a newline character (\n), OR may be
                    unformatted text which will be automatically formatted
                    to fit within the dimensions as specified below.
            query : 'true'  indicates a decision dialog, and user is
                            prompted for a yes/no response
                    'false' indicates an information dialog, and user is
                            prompted to press Enter to exit
            title : (optional, default: null pointer)
                    If specified, this is the dialog title text which will
                    be centered in the top border of the dialog.
            height: (optional, zero (0) by default) height of dialog window
                    in rows. A zero value indicates that the dialog is
                    automatically sized to accomodate the dimensions of the
                    message text in the 'gsMsg' parameter
            width : (optional, zero (0) by default) width of the dialog
                    window in columns. A zero value indicates that the dialog
                    is automatically sized to accomodate the message text
                    in the 'gsMsg' parameter
            vOff  : (optional, default: 0) vertical offset into the parent
                    window's text area (0-based)
                    A negative value indicates that the dialog is to be
                    centered vertically in the parent window.
            hOff  : (optional, default -1) horizontal offset into parent
                    window's text area (0-based).
                    A negative value indicates that the dialog is to be
                    centered horizontally in the parent window.
            timeout: (optional, zero by default) automatic timeout of
                     dialog display in seconds
                     -- By default, the dialog is closed when one of the
                        pushbutton controls is activated.
                     -- If a positive value (in seconds) is specified, the
                        dialog will close automatically after the specified
                        number of seconds has elapsed OR when any keycode is
                        received, whichever comes first.
            dbg   : (optional, default: false) for debugging only:
                    if reset, refresh the parent window on return
                    if set,   dialog remains visible on return

        Returns: if 'query' flag is set, then the user response is returned:
                    'true'  if control at index zero(0) selected
                    'false' if control at index one(1) selected
                 if 'query' flag is reset, i.e. dialog has only one control,
                    then return value is always 'true'.

  Generate a “quick” dialog window within the application’s ACWin-class window.

  QuickDialog invocations are the simpler of the two dialog types, requiring fewer configuration parameters.
  QuickDialogs are generated in either of two modes (see `'query'` parameter).

  1) information mode An information dialog displays a message and has one pushbutton control. The user selects that control to close the dialog and return execution to the parent window. 2) decision mode A decision dialog displays a question, and has two pushbutton controls which allows the user to make a binary choice: (yes/no , save/discard , continue/abort , etc.).

  Working examples of the quick dialog may be found in the AnsiCmd test suite.
  Invoke the EarthPoints test application with:
  `./epts --test=Dq`
  for a list of quick-dialog tests.

  For a fully-configurable dialog, see the Dialog method below, which accepts customized values for all configuration parameters.

- bool Dialog ( short dlgHgt, short dlgWid, skForm* formDef,
  `` const char* sTxt = NULL, const char* tTxt = NULL,
  `` short vOff = -1, short hOff = -1, LineType ltype = ltSINGLE,
  `` acAttr bdrAttr = acaUSEDFLT, acAttr txtAttr = acaUSEDFLT,
  `` short tvOff = 0, short thOff = 1, bool dbg = false );

      Input  :
         dlgHgt: dialog height (rows)
                 A value of zero (0) indicates that the height of the dialog
                 is based on the height (rows) of the PREFORMATTED text it
                 contains, plus necessary padding (typically an additional
                 three(3) rows).
                 The height of the dialog may be calculated as the rows
                 needed by the controls plus the height of the static text
                 data, plus top and bottom borders. Some additional space is
                 recommended to present a pleasing and easily-readable
                 display.
         dlgWid: dialog width (columns)
                 A value of zero (0) indicates that the width of the dialog
                 is based on the width (columns) of the PREFORMATTED text it
                 contains, plus necessary padding (typically an additional
                 four(4) columns).
                 The width of the dialog may be calculated as the columns
                 needed by the widest row of controls, or the width of the
                 static text, whichever is greatest, plus the right and left
                 borders. Some additional space is recommended to present
                 a pleasing and easily-readable display.
         formDef:pointer to user-interface control definitions (skForm object)
                 -- At least one of the defined controls MUST BE a Pushbutton
                    control; otherwise it is an unrecoverable error.
                 -- Certain member values are overridden by the values in
                    the skForm object of the parent window.
                 -- Invalid or out-of-range members will be silently
                    corrected to maintain dialog integrity.
                 -- See note below regarding data modified before return
                    to caller.
         sTxt  : static text written to be written to dialog interior
                 (a null pointer or an empty string indicates that there is
                  no static message)
         tTxt  : dialog title, if specified, will be written centered in the top
                 border of the dialog.
                 (a null pointer or an empty string indicates that
                  the dialog will have no title)
         vOff  : vertical offset (0-based) in rows from top of parent window
                 (optional, default: -1) A value of -1 specifies that
                 dialog is centered vertically in the parent window.
         hOff  : horizontal offset (0-based) in columns, from left edge of
                 parent window.
                 (optional, default: -1) A value of -1 specifies that
                 dialog is centered horizontally in the parent window.
         ltype : border style (optional, default: ltSINGLE)
                 Member of enum LineType (ltSINGLE or ltDUAL)
         battr : border color attributes
                 (optional, default: color attributes are taken from those
                 of the parent window.
         tattr : text (dialog interior) color attributes
                 (optional, default: color attributes are taken from those
                 of the parent window.
         tvOff : static text position, vertical offset
                 (optional, default: 0, top row of dialog interior)
         thOff : static text position. horizontal offset
                 (optional, default: 1, inset one column from left edge of dialog)
         callbk: (optional, default: null pointer) pointer to a non-member callback
                 function. (See typedef CUPTR for details.)
                 If specified, this function will be called by the EditDialog method
                 each time the user presses a key.
         dbg   : (optional, false by default) for debugging only:
                 if reset, refresh the parent window on return
                 if set,   dialog remains visible for analysis

      Returns:
         index of control with focus when dialog is closed
         (this is the same value contained in formDef->fi)

         The structure referenced by 'formDef' may have been updated
         to contain additional information:
           a) Text controls (ftTB): The text of the field may have been
               modified by user.  The data may be retrieved directly from
               the skField object.
           b) Radiobutton controls (ftRB): The 'set' flag which indicates
              the binary state of the control (set or reset) may have changed.
              This flag may be read directly from the skField object.
           c) Context Menu controls (ftMB): If a menu item has been selected,
              a call to the skField-class getItem() method will return the item.
           d) Scrollbox controls (ftSB): If a scrollbox item has been selected,
              a call to the skField-class getItem() method will return the item.

         If the formDef object as received has been malformed, certain
         parameters will have been corrected if possible; or if corrections
         are not possible:
           a) formDef will be ignored,
           b) a warning will be displayed, and
           c) a minus one (-1) will be returned.

  Generate a dialog window within the application ACWin window. The dimensions, position and color attributes are specified directly, while the dialog’s controls are defined by passing a pointer to a fully-initialized skForm-class object. The referenced skForm object is updated in response to user interaction, so that when the dialog is closed, caller may interpret any changes the user has made to the controls’ status. (see notes below)

  Note that verification of all parameters is performed by this method, and adjustments will be made to the position and dimensions of the dialog if necessary to make the dialog fit within the parent window. In addition, the display text, and the position of the controls will be adjusted if necessary to fit within the dialog. Keep in mind however, that it is impractical to test for all varieties of foolishness, such as overlapping controls, so construct dialogs with care.

  Working examples of the full-initialization dialog may be found in the AnsiCmd test suite.
  Invoke the EarthPoints test application with:
  `./epts --test=Dd`
  for a list of dialog tests.

  Please see Dialog sub-Windows for a more detailed discussion of Dialog window functionality.

> The following group of methods is intended specifically for use by callback functions, and are active only when a dialog window is currently open. The methods of this group are used to access the dialog’s internal data structures in response to user input. Please see Dialog Callback for additional information.

- bool Dialog_GetText ( short ctrlIndx, gString& txtData );

        Input  :
           ctrlIndx : index of target control within the dialog
           txtData  : (by reference) receives a copy of the Textbox text

        Returns:
           'true' if a dialog is currently under edit, AND
                  if 'ctrlIndx' refrences a control of the correct type
                  for the operation
           else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For Textbox controls (ftTB) within a dialog, retrieve a copy of current text data.

- bool Dialog_SetText ( short ctrlIndx, const gString& txtData,
  `` acAttr color = acaUSEDFLT, bool refresh = true );

        Input  :
           ctrlIndx : index of target control within the dialog
           txtData  : (by reference) text which will replace the current text
           color    : (optional, default: acaUSEDFLT)
                      if specified this is the new color attribute for the
                      control, else control attribute is unchanged
           refresh  : (optional, default: true)
                      if 'true',  refresh the display after update
                      if 'false', display is not refreshed

        Returns:
           'true' if a dialog is currently under edit, AND
                  if 'ctrlIndx' refrences a control of the correct type
                  for the operation
           else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For Textbox (ftTB) and Scrollbox (ftSB) controls only, replace existing display text for the control.
  Optionally, set new base color attribute for the control.

  The display is updated by default, but update can be delayed by resetting the `'refresh'` parameter.

- bool Dialog_SetAttr ( short ctrlIndx, const acAttr* acaArray,
  `` short acaCnt, bool refresh = true );

        Input  :
           ctrlIndx : index of target control within the dialog
           acaArray : pointer to an array of acAttr color attributes, one
                      attribute for each text row of the control.
           acaCnt   : number of attribute values in the 'rowAttr' array (>zero)
                      The minimum _practical_ value is two(2).
           refresh  : (optional, default: true)
                      if 'true',  refresh the display after update
                      if 'false', display is not refreshed

        Returns:
           'true' if a dialog is currently under edit, AND
                  if 'ctrlIndx' refrences a control of the correct type
                  for the operation
           else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  Specify an array of color attributes, one for each item (row) displayed in the control. Only certain control types accept multi-color attributes:
  Scrollbox controls (ftSB)
  Multi-row Menus (ftMB)
  Please see colorConfig and skField config example for details on constructing an array of color attributes for use within the target control.

  The display is updated by default, but update can be delayed by resetting the `'refresh'` parameter.

- bool Dialog_GetItem ( short ctrlIndx, gString& itemText,
  `` short& itemNum, bool select = true );

        Input  :
           ctrlIndx : index of target control within the dialog
           itemText : (by reference) receives text of the highlighted line item
           itemNum  : (by reference) receives the (0-based) item number (index)
                      of the highlighted item
           select   : (optional, default: true)
                      if 'true'  return the user 'selected' item (if any)
                                 else, return highlighted item
                      if 'false' return the highlighted item
           clear    : (optional, default: false)
                      if 'true'  clear (reset) any current "selection" and
                                 refresh the control to erase the selection
                                 indicator.
                      if 'false' selection is not modified

        Returns:
           'true' if a dialog is currently under edit, AND
                  if 'ctrlIndx' refrences a control of the correct type
                  for the operation
           else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For Menus and Scrollbox controls within a dialog, return the data for the highlighted “item”.

  1. An `"item"` is the data for a display row within the control. Generally, this is the highlighted item i.e. the text under the cursor.
     Exception: If the user has “selected” a menu item via the `Enter or Space` keys, then the “selected” item, rather than the highlighted item will be returned.
  2. The `"item number"` is the index of the of the row containing the item.
     1. The optional `'select'` parameter specifies whether the “selected” item (if any) should be returned or if the highlighted item should always be the returned item.
        A "selected" item is an item for which the user has highlighted an item and then pressed the Enter or Space key.
  3. The `"item text"` is the text displayed on that row.
     1. For Menu controls, this is the display text excluding the border characters. Any newline character and leading/trailing whitespace will also be removed.
        `Example: "│Clear Bookmarks │\n" becomes`
        `"Clear Bookmarks"`
        If the menu item includes a “hotkey” indicator (caret `'^'`), then the menu text will include the caret:
        `"Clear ^Bookmarks"`.
     2. For Scrollbox controls, this is the display text excluding the newline character and any leading/trailing whitespace.
        `Example: " The cow in the meadow goes moo. \n" becomes`
        `"The cow in the meadow goes moo."`

     Clear Parameter

     If the `'clear'` parameter is set, then before return, the current item selection (if any) will be cleared and the associated selection indicator, if visible will be removed.
     This is useful if the item selection has already been handled or if item selection is unneeded.
     Note that there is a potential timing issue for clearing the ’sitem’ selection member. If this method is called from within a callback in response to selection keystroke (Enter/Space), then the actual selection has not yet occurred. In this case, the callback would need to signal that the selection keycode has been handled. To do this, the callback would return an alternate keycode instead of the Enter/Space. Suggestions: return NULLCHAR to indicate that the keycode has been handled, or return wcsTAB to move the input focus to the next field.
     Please see Dialog Callback for more information on callback functions.

     Please refer to the getItem method in the chapter on skField Public Methods for a technical description of `'items'` and item selection.

- bool Dialog_SetItem ( short ctrlIndx, short itemNum, bool refresh = true );

        Input  :
           ctrlIndx : index of target control within the dialog
           itemNum  : index (0-based) of the item to be set as selected
                      Note: If valueos out-of-range, then nearest _valid_
                            item will be selected.
           refresh  : (optional, default: true)
                      if 'true'  refresh the display
                      if 'false' display is not updated

        Returns:
           'true' if: a) a dialog is currently under edit,
                      b) 'ctrlIndx' refrences a control of the correct type
                         for the operation
                      c) the target control _does not_ have input focus
           else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For Menus and Scrollbox controls within a dialog: set the `"selected item"` explicitly. This will draw user’s attention to the item and indicate the current selection. Note that items are zero-based; that is, the first item is item zero(0).

  The target control must not have input focus when this method is called.

  Scrollbox Context Menu ┌──────────────────────────────────────────┐ ╔═════════════╗ │ There once was a man from Kirkuk, │ ║ Pigs Grunt ║ │▷Who was known far and wide for his luck, │━┳━║ Birds Fly ║ │ Till while jogging one day, │ ┃ ║ Cows Moo ║ └──────────────────────────────────────────┘ ┃ ║ Goats Bleat ║ ┃ ╚═════════════╝ Item #1 is "selected": ━━━━━━━━━━━━━┛

  Within Scrollbox controls, the “selected” item is indicated by an arrow at the left edge of the text; while for Menus, the “selected” item is displayed in bold/italic font.

  If successful, control is refreshed to visually indicate the selected item.

- bool Dialog_GetState ( short ctrlIndx, bool& rbState );

        Input  :
           ctrlIndx : index of target control within the dialog
           rbState  : (by reference) receives the current state of the control

        Returns:
           'true' if a dialog is currently under edit, AND
                  if 'ctrlIndx' refrences a control of the correct type
                  for the operation
           else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For binary-state controls within a dialog, return the current ’state’ flag value: `'set'` or `'reset'`.
  Currently, the binary state flag applies only to Radiobutton controls.

- bool Dialog_GetStateXOR ( short ctrlIndx, short& rbIndx );

        Input  :
           ctrlIndx : index of target control within the dialog
           rbIndx   : (by reference) receives index of XOR group member
                      whose state flag is currently set

        Returns:
           'true' if a dialog is currently under edit, AND
                  if 'ctrlIndx' refrences a control of the correct type
                     for the operation, AND
                  if the target control is a member of an XOR group
                     then 'rbIndx' receives the target index
           else 'false' ('rbIndx' receives 'fCnt')

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For binary-state controls within a dialog which are configured as XOR group members, return the index of the control within the group whose binary state is ’set’.
  If the target is not a member of an XOR group, then the Dialog_GetState method should be called instead.

  Currently, the binary state flag applies only to Radiobutton controls.

- bool Dialog_GetField ( short ctrlIndx, const skField*& skfPtr );

        Input  :
           ctrlIndx : index of target control within the dialog
           skfPtr   : (by reference) receives a pointer to _constant_ skField
                      object. Access to all public data members is available.
                      Access to 'const' methods (if any) is also available.

        Returns:
           'true'  if a dialog is currently under edit, AND
                   if 'ctrlIndx' refrences a control of the correct type
                   for the operation
           else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For controls within a dialog, return a pointer to the specified control object. This is a const pointer, meaning that the public data may be analyzed, but no data within the object may be modified.

  The example below retrieves the dimensions of the control and formats a paragraph of text according to the dimensions. The new text is then written to the target control.

         gString gs( "Four score and seven years ago"
                     "...shall not perish from the earth." ) ;
         const skField* skfPtr = NULL ;
         if ( (this->win->Dialog_GetField ( fldTXTBOX, skfPtr )) )
         {
            short fldHeight = skfPtr->hgt ;
                  fldWidth  = skfPtr->wid ;
            this->win->FormatParagraph ( gs, fldHeight, fldWidth,
                                         false, false ) ;
            this->Dialog_SetText ( fldTXTBOX, gs,
                                   acAttr(acaFG_BLUE | acaBGb_RED) ) ;
         }

- Dialog_Hilite ( short ctrlIndx, bool set, int begin, int len, acAttr txtmod = acaREVERSE );

        Input  :
           ctrlIndx : index of target field
           set   : if 'true',  highlight the text segment
                   if 'false', clear the highlight
           begin : index of first (leftmost) character to highlight
                   (referenced only when 'set' != 'false')
           len   : number of characters in highlighted segment
                   Note: If segment spans rows, be sure to include
                         the newlines in the count.
                   (referenced only when 'set' != 'false')
           txtmod: (optional, default:acaUSEDFLT)
                   text modifier attribute for highlighted text segment
                   - If specified, text modifier attribute for highlighted
                     text segment. One of the following:
                      acaBOLD      bold-text modifier
                      acaITALIC    italic-text modifier
                      acaUNDERLINE underline-text modifier
                      acaOVERLINE  overline-text modifier
                      acaXOUT      x-out (strikethrough) text modifier
                      acaBLINK     blinking-text modifier
                      acaCONCEAL   concealed (invisible) text
                      acaREVERSE   reversed fgnd/bkgnd (default)
                      Note: OR'd combinations of these modifiers are not allowed.
                   - If not specified, then use previously-specified modifier
                     (if any), else acaREVERSE (fg/bg attributes reversed)
            center: (optional, default: true)
                    if set, assure that highlight is within visible
                            space by adjusting the IP if necessary.
                    if reset, do not adjust IP
                            (highlighted text may or may not  be visible).

        Returns:
           'true'  if highlight set/cleared
           'false' a) 'fIndx' references an upsupported control type
                   b) parameter out-of-range

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For Textbox controls only (ftTB), highlight a segment of text using one of the text-modifier attributes. If the target field is currently visible, the field will be refreshed before return.

  Note that while any combination of the `acAttr` color attributes may be freely OR’d under most circumstances, for this method, exactly one text-modifier attribute may be specified as the highlight attribute.

  Please see HilightFieldText for a techninal description of this functionality.

- bool Dialog_SetFocus ( short ctrlIndx );

        Input  :
           ctrlIndx : index of target control within the dialog

        Returns:
           'true' if a dialog is currently under edit, AND if 'ctrlIndx'
                 refrences a control of the correct type for the operation
                 AND if the target control is not set as read-only
           else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For controls within a dialog, set the input focus to the specified control.

- bool Dialog_SetReadOnly ( short ctrlIndx, bool read_only );

        Input  :
           ctrlIndx : index of target control within the dialog
           read_only: if 'true',  set field as read-only
                                  (cannot receive input focus)
                      if 'false', reset the read-only flag
                                  (can receive input focus)

        Returns:
           'true' if a dialog is currently under edit, AND if 'ctrlIndx'
                 refrences a control of the correct type for the operation
                 AND if the target control does not currently have input focus
           else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For controls within a dialog, set or reset the read-only flag.
  If the read-only flag is set, then control cannot receive the input focus.

- bool Dialog_Scroll ( short ctrlIndx, int& steps, bool head = false, bool tail = false);

        Input  :
           ctrlIndx : index of target control within the dialog
           steps    : (by reference) number of steps to scroll
                      This value is ignored if 'head' or 'tail' flag is set.
                        scroll == 0, no scrolling will occur, but on return,
                                     value will be _current_ item/IP.
                        scroll >  0, scroll forward toward tail of data
                        scroll <  0, scroll backward toward head of data
           head     : (optional, default: false) if specified, move to head
                      of data (overrides value in 'steps')
           tail     : (optional, default: false) if specified, move to tail
                      of data (overrides value in 'steps')

        Returns:
           'true' if a dialog is currently under edit, AND if 'ctrlIndx'
                 refrences a control of the correct type for the operation
                  -- On return, 'steps' will contain the currently referenced
                     item number, or for Textbox controls, the IP.

           else 'false' ('steps' is not modified)

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  For controls with a visible cursor position: Textbox (ftTB), Scrollbox (ftSB) or Context Menus (ftMB) only.

  1. Textbox Controls: Scroll horizontally, right or left, one character per step.
  2. Scrollbox Controls:
     Scroll vertically, up or down, one line item per step.
  3. Menu Controls:
     Scroll vertically, up or down, one item per step. Wrap-around will not occur. Note that only "context" menus (multi-row, stand-alone menus) are supported by this method.

  Scrolling is managed by the control’s `'ip'` (Insertion Point) member. Position of the highlight (Menus or Scrollbox controls) or visible cursor (Textbox controls) is calculated based on the value of `'ip'`.
  The `'steps'` value is range checked to prevent the insertion point from overruning the data.

  The `'head'` and `'tail'` flags override the value in `'steps'`, and the `'head'` flag overrides the `'tail'` flag.

  Special case: If both `'head'` and `'tail'` are reset and if `'steps'` is set to zero, then the current position is reported, but not modified.

- bool Dialog_Write ( const wchar_t* txt, short yOff, short xOff,
  `` bool clear = false, acAttr color = acaUSEDFLT );
- bool Dialog_Write ( const char* txt, short yOff, short xOff,
  `` bool clear = false, acAttr color = acaUSEDFLT );

        Input  :
           txt    : text to be written to dialog interior.
                    Either: wchar_t* or char*
           yOff   : position: offset in rows from top of dialog interior
                    with zero(0) being the top row.
           xOff   : position: offset in columns from left edge of dialog
                    Note that all dialog text is automatically indented by
                    one column from both the left and right borders, so an
                    xOff value of zero will display text starting in column 1.
           clear  : (optional, default: false) clear the target row before
                    writing the data.
           color  : (optional, default: acaUSEDFLT)
                    if specified this is the color attribute used to write
                    the text. Otherwise, text will be written using the
                    dialog's interior attribute.

        Returns: 'true' if a dialog is currently under edit
                  else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  Write one line of text to the interior of the dialog.

  1. Text will be truncated if necessary to fit within the available space.
  2. Static text may not occupy the same space as a control object. If it does, it will be invisible.
  3. Note that the text is written directly to the display.
     Neither the text nor the color attribute are stored.
  4. CAUTION! - Do not overwrite control objects within the dialog!
     Although the text data are truncated if necessary to prevent incursion into the dialog border, at this time, programatic testing for overwrite of control objects is considered too expensive an operation.

     If you are uncertain about positioning of static text data within the dialog, it is recommended that a read-only Textbox control be defined for display of transitory messages.

- bool Dialog_Refresh ( bool full = false );

        Input  : full : (optional, default: false)
                        if 'false' redraw the interior of the dialog only
                                   this includes the static text data and
                                   all controls
                        if 'true', redraw the dialog border, then redraw
                                   the dialog interior

        Returns: 'true' if a dialog is currently under edit
                  else 'false'

  Note: This method is active only when a dialog (ACDlg object) is open;
  and only if a callback method was specified when dialog was created.

  Refresh (redraw) the dialog. This method may be called from within the application-level callback to restore the display in case the dialog has been obscured by another operation.

  If the parent window has also been obscured by the operation, refresh the parent window first, then refresh the dialog window.

#### Utility Methods

- short FormatParagraph ( gString& gsTxt, short maxRows, short maxCols,
  `` bool trunc = true, bool hypenbrk = false, short *truncIndex = NULL );

  This is a pass-through to the acFormatParagraph method.

- void ParagraphSize ( const gString& gs, short& msgHeight, short& msgWidth );
- void ParagraphSize ( const gString& gs, int& msgHeight, int& msgWidth );

        Input  :
           gs        : (by reference) text to be analyzed
           msgHeight : (by reference) receives number of text rows
           msgWidth  : (by reference) receives number of text columns

        Returns: nothing

  Calculate the dimensions (height and width) of the specified block of text.

  This method can be used to measure the height in rows and width in columns for a paragraph of text data. This is useful for determining how the text will fit within the window, or the dimensions required for a field in which to display the text. Note that the number of text rows is determined by the number of newline characters (`'\n'`) found (excluding trailing newline, if any).
  Dimensions are calculated as shown in the following example.

        ACWin *win( . . . ) ;
        short txtRows, txtCols ;

        gString gsText =
          "There once was a man from Kirkuk, \n"
          "Who was known far and wide for his luck, \n"
          "Till while jogging one day, \n"
          "he looked the wrong way, \n"
          "Whereupon he was hit by a truck." ;

        win->ParagraphSize ( gsText, txtRows, txtCols ) ;
        gString bsOut( "\n\"Text Dimensions are %hd rows by %hd columns.\"\n",
                       &txtRows, &txtCols ) ;
        win->ttyWrite ( bsOut ) ;

        Yields:
          "Text Dimensions are 5 rows by 41 columns."

  Programmer’s Note: This method is overloaded for pointers to int32_t. The author has found that it is too easy to get confused between 32-bit text indices and 16-bit window coordinates.
- bool isPrint ( wchar_t wkey );

        Input  : keycode to be tested

        Returns: true if a "graphing" character, else 'false'

  A locale-aware version of the `'std::isprint'` function.

  The locale-aware version of ’isprint’ takes into account all graphing characters of all languages supported by the Unicode standard. This means that whatever input language is being used for the application, all codepoints of that language will be handled as expected.

  Whitespace Keycodes:

  Canon says that the Space `' '`, Enter `'\n'`, Tab `'\t'` and similar codepoints are classed as whitespace rather than graphing characters; however, canon is wrong on this issue.
  This method recognizes these as graphing characters simply because when written, they cause updates to the display.

  Keycodes reserved by the AnsiCmd library:

  A small range of Unicode codepoints is reserved by the library for assignment to decoded ANSI escape sequence, control codes, “conditioned” keys and ALT-key combinations.
  These reserved keycodes consist primarily of arrows, geometric shapes, and typographic symbols. These keycodes are not integral to any written language, and should seldom, if ever be needed in daily user interactions.

  The range of keycodes in this group are technically graphing characters but have been reassigned by the AnsiCmd library, and will not be reported as graphing characters by this method. Most of these are assigned to:
  `1) wcsALT_A - wcsALT_RB`
  `2) wcsCTL_A - wcsCTL_7`
  `3) wcsF01 - wcsCF12`
  `4) various "conditioned" keys, cursor-movement keys, etc.`
  The exclusion range is defined by the constants RESKEY_MIN and RESKEY_MAX which correspond to keycode assignments wcsF01 and wcsALT_RB, respectively. Note that not all keycodes within this range are currently assigned. Some are reserved for future development.

  Line-drawing characters, bullet characters and similar keycodes defined by the AnsiCmd library fall outside the reserved range, and therefore ARE reported as graphing characters.

  If any codepoints within the reserved range needs to be displayed within a specific project, this should not be a problem so long as the AnsiCmd user-interface methods do not see them and try to “interpret” them.

  It may be educational to study the full Unicode character table which can be found at: `https://www.utf8-chartable.de/`

- bool EnableFootnotes ( bool enable );

        Input  : enable: set   : enable output from the Footnote method.
                         reset : disable output from Footnote method.

        Returns: current state of the footnote flag

  Enable or disable output to the window written through the ’Footnote’ group of methods described below.

- void Footnote ( const gString& msg, short pause, acAttr color = acaUSEDFLT, bool center = false );
- void Footnote ( const wchar_t* msg, short pause, acAttr color = acaUSEDFLT, bool center = false );
- void Footnote ( const char* msg, short pause, acAttr color = acaUSEDFLT, bool center = false );

        Input  :
           msg   : text of message to be written.
                   -- Message will be truncated if necessary to the
                      width of the window minus 4.
                   -- If 'msg' is an empty string, then erase any
                      existing message and restore the border.
           pause : time in tenths-of-a-second to wait before erasing message
                   a value of zero(0) indicates that message is to
                   remain visible on return.
           color : (optional, existing border attributes by default)
                   foreground/background color attributes for message display
           center: (optional, 'false' by default)
                   if 'true',  center the message horizontally
                   if 'false', message is positioned at left edge of the space

        Returns: nothing

  Write a message in the lower border of the window. This could be a message to the user, or could be a temporary diagnostic message used during development. Optionally, wait, a moment, then erase the message, (see `'pause'` argument).

  For best visual presentation, the first and last characters of the message should be spaces, but this is not enforced.

  Pleasse refer to the `Test_SoftEcho` method or refer to the example output in the diagram below.

- void Sidebar ( const gString& msg, bool left, acAttr color = acaUSEDFLT, short offset = ZERO, bool clear = false ) ;
- void Sidebar ( const wchar_t* msg, bool left, acAttr color = acaUSEDFLT, short offset = ZERO, bool clear = false );
- void Sidebar ( const char* msg, bool left, acAttr color = acaUSEDFLT, short offset = ZERO, bool clear = false );

        Input  :
           msg   : text of message to be written.
                   -- Message will be truncated if necessary to the
                      height of the window minus 4.
                   -- If 'msg' is an empty string, then erase any
                      existing message and restore the border.
           left  : if 'true',  message is displayed in left edge border
                   if 'false', message is displayed in right edge border
           color : (optional, existing border attributes by default)
                   foreground/background color attributes for message display
           offset: (optional, zero by default) Specify the offset
                    (number of rows) from vertically centered position.
                   if  0,  message is vertically centered
                   if <0,  message is offset upward from centered by
                           specified number of rows.
                   if >0,  message is offset downward from centered by
                           specified number of rows.
           clear : (optional, 'false' by default)
                   if 'true',  clear any existing message from the border
                               before writing the new message
                   if 'false', existing messages are unaffected
                               (unless the new message overwrites an old one)

        Returns: nothing

  Display a message in the left or right border of the window.
  The Sidebar may have no practical value, but it’s fun. :-)

          ┌────────┤  Title  ├──────────┐
          ┴                             │
          H                             │
          i                             ┴
          ┬                             M
          │                             o
          │                             m
          │                             !
          │                             ┬
          │                             │
          │                             │
          └─────┤ Smelly Footnote ├─────┘

        ACWin *win = new ACWin ( ... ) ;
        win->SetTitle ( "  Title  " ) ;
        win->Sidebar ( "Hi", true, acaATTR_DFLT, -2) ;
        win->Footnote ( " Smelly Footnote ", 0, acaATTR_DFLT, false ) ;
        win->Sidebar ( "Mom!", false, acAttr(acaFG_GREEN | acaBG_BLUE), 0) ;

  NOTE: A live test is under conditional compile in the Test_Dialog method.

  Technical note on original cursor position. Ideally, the cursor position on exit should be the position on entry; however, saving the original position via a call to acGetCursor() is functional, but UNBEARABLY slow (> 0.5 seconds). Instead, before return, the field with focus is refreshed, positioning the cursor in that field. There is no guarantee that is where the cursor originally was; therefore, it is recommended that caller consider explicitly setting cursor position on return.
- bool DrawBox ( WinPos wpOrig, short height, short width, LineType lType, acAttr bxAttr, bool clear );

        Input  : pos   : offset from upper-left corner of text area to
                         upper-left corner of box (0-based)
                 height: number of rows for box
                 width : number of columns for box
                 lType : (optional, ltSINGLE by default) line style
                         member of enum LineType: (ltSINGLE or ltDUAL)
                 bxAttr: (optional, acaUSEDFLT by default)
                         If specified, these are the color attributes used.
                         If not specified, stored text attributes are used.
                 clear : (optional, 'false' by default)
                         if 'false', interior of box is cleared using 'bxAttr'
                         if 'true',  interior of box is cleared using the interior
                                     color attributes of the parent window

        Returns: 'true'  if box fits within the window text area
                 'false' if invalid offset or dimensions specified

  Draw a rectangle within the window’s text area.

  The position, dimensions, line style and color attributes may be specified. See the example below.

  Note that the minimum dimensions for the rectangle are two rows by two columns (2x2). At the minimum dimension, of course there is no space for text within the box.

- WinPos DrawLine ( const WinPos& wpOrig, short length, bool vertical, LineType lType,
  `` wchar_t begChar, wchar_t endChar, acAttr lnAttr );

        Input  : pos     : offset from upper-left corner of window (0-based)
                 length  : length of the line: number of number of rows
                           (vertical), or number of columns (horizontal).
                 vertical: 'true'  : vertical line
                           'false' : horizontal line
                 lType   : (optional, ltSINGLE by default) line style
                            member of enum LineType: either ltSINGLE or ltDUAL
                 begChar : (optional, null character by default)
                            specify the beginning endpoint character
                 endChar : (optional, null character by default)
                            specify the final endpoint character
                 lnAttr  : (optional, acaUSEDFLT by default)
                           If specified, these are the color attributes used.
                           If not specified, stored text attributes are used.

        Returns: cursor position at the end of the line:
                 For horizontal lines, the column following the last character
                 (limited at right edge of window)
                 For vertical lines, the column below the last character
                 (limited at bottom edge of window)

  Draw a horizontal or vertical line within the window’s text area.
  — Horizontal lines are drawn left-to-right.
  — Vertical lines are drawn top-to-bottom.

  This is a specialized instance of the AnsiCmd acDrawLine() method. The only difference is that the parameters are range checked to fit entirely within the window. Note that if an endpoint of the line intersects the border of the window, the endpoint will be drawn using the color attributes of the border, while the portion of the line within the text area of the window will be drawn using the color attributes of the window interior, or the attributes specified by the optional `'lnAttr'` parameter.

  > Note: If the line intersects the window border, the endpoint character will be automatically selected to match the intersection of the drawn line and the border line style. As a corollary to this automatic character selection, avoid positioning the start of a line such that it would obscure the window title (if any). Definitions for the line-drawing characters may be found in `AnsiCmdDef.hpp`.

  #### Line-drawing Examples

  ┌───┬────────┤ Line-drawing Tests ├────────╥───┐ ├───┼──────────────────────────────────────╫───┤ │ │ ├──────────────────────┤ ║ │ │ │ ╠════════════════════════╣ ║ │ ╞═══╪══════════════════════════════════════╬═══╡ │ │ ┬ ╔════════════════════════╗ ╦ ║ │ │ │ │ ║ ║ ────────────────── │ ║ ║ ║ │ │ │ │ ║ ║ ══════════════════ │ ║ ║ ║ │ │ │ ┴ ╚════════════════════════╝ ╩ ║ │ └───┴──────────────────────────────────────╨───┘
- int LaunchDefaultApp ( const char* targFile, bool redirect = true );

        Input  :
           targFile : filespec of file to be processed by the external application
           redirect : (optional, 'true' by default)
                      if 'true',  redirect stdout and stderr to temp files
                      if 'false', allow stdout and stderr to write to the
                                  terminal window

        Returns:
           the child process ID (an integer value)
           returns minus one (-1) if child process was not created

  Launch the system default application for handling the specified type of file.

  Technical Description:

  Launching an external application is done by creating a child process to perform the actual launch, while the parent process continues execution of the application code. This operation is done via a call to the standard library’s `'vfork'` function.

  1. The `'targFile'` parameter:
     This is the filespec for the file to be processed by the external application. This may be either a full-path specification or a relative path; or if a `URL` is specified, then that page will be opened in the browser.
     `/home/sam/Documents/XmasList.html`
     `./XmasList.html`
     `"../../Music/Kansas/Dust In the Wind"`
  2. The `'redirect'` parameter:
     By default, the displayed startup information (if any) for the child process is redirected to temporary files to avoid trashing the parent application’s display. If desired, the startup information will be written to the terminal window (redirect==false); but in this case, the application’s display data should be saved before calling `LaunchDefaultApp`. (See HideWin).
  3. The `'xdg-open'` system utility:
     When called, this utility scans the system’s MIME-type (Multipurpose Internet Mail Extension) database to determine the user’s specified default application for processing files of that MIME type. For example:
     `win->LaunchDefaultApp ( ../Texinfo/ansicmd.html );`
     This will invoke the user’s default browser to display the specified HTML file. If the browser is not open, it will be opened. If the browser is already open, a new tab (or a new instance of the browser) will be created to display the file. The precise action is determined by the settings of the target application.
  4. Redirecting `stdin/stderr` streams:
     Redirection of a data stream is handled by the standard library’s `'dup2'` function. This is somewhat more complex than redirection using `'pipes'`. See the `'dup2'` documentation for details.
  5. See also ShellOut, below, which opens an external application in the current terminal window.
- int ShellOut ( const gString& shellCmd, acAttr textColor = acaUSEDFLT );

        Input  :
           shellCmd : (by reference) invoke the specified shell builtin
                      command, shell program or console utility program
                      - If an empty string, then invoke a copy of
                        the 'bash' shell.
                        NOTE: If the default shell IS NOT 'bash', then
                        'shellCmd' should be used to specify the target
                        shell program.
           textColor: (optional, default: acaUSE_DFLT)
                      specify an alternate foreground/background
                      color for text data written to stdout.
                      [This parameter is currently ignored.]

        Returns: exit code of child process
           Ideally, this is the exit code of the last utility run
           in the child process, but this cannot be guaranteed.

  Go to command shell in the current terminal window.

  1. Save the application window display data.
  2. Clear the terminal window
  3. Put the AnsiCmd engine (including ACWin object) into hibernation mode.
  4. Invoke the specified application (if any)
     If no application is specified, invoke `'bash'` (or current shell program).
     In this case, user will need to type `'exit'` to return to application.
  5. Wake the AnsiCmd engine from hiberation mode.
  6. Return control of the Input stream to the ACWin object.
  7. Redraw the application window.
     As a side effect, this also restores the color attributes.

  Important Note: This method should be called ONLY from the main application window. AND there should be no sub-dialogs open. If invoked from a sub-dialog, then the primary window’s display data will not be properly saved.

#### Development Support Methods

> > A beginning developer may ask: “Why are the debugging routines so fancy?” Answer: Writing the debugging routines is a concrete expression of the thought process which informs the overall project development. Highly recommended for all developers. (It’s almost as important as coffee :)

- void GetWinAttributes ( acaExpand& txtExp, acaExpand& bdrExp );

        Input  :
           txtExp : (by reference) acaExpand object to receive text attributes
           bdrExp : (by reference) acaExpand object to receive border attributes
        Returns: nothing

  Debugging method: Get a copy of the window attributes.

- WinPos GetWinConfig ( short& height, short& width );

        Input  :
           txtExp : (by reference) receives window height (rows)
           bdrExp : (by reference) receives window width (columns)
        Returns: window position (offset into terminal window)

  Debugging method: Get a copy of the window dimensions and position.

- const BlockFifo* GetFifo ( void );

        Input  : none
        Returns: const pointer to the private @b{BlockFifo} object.

  Debugging method: Get a pointer to the FIFO queue which contains the static text of the window. For an example, please refer to the `Test_Fifo` method in `AnsiCmdTest.cpp`. Run this test using: `epts --test=Ws`.

- void dumpConfig2Log ( const wchar_t* title );
- void dumpField2Log ( const skField* fptr, const wchar_t* title, bool verbose = false );
- void dumpMrp2Log ( const skField* fptr, const wchar_t* title = NULL, bool brief = false );
- void dumpFifo2Log ( const BlockFifo* bptr, const wchar_t* title = NULL );
- void dumpFifoRecord2Log ( const DataBlock* dbptr );

  Debugging methods: Write various diagnostic data to the debugging log file.

  During development a log file is created when the application is launched. This file is cryptically named: `"dbg.log"`. Startup and shutdown data are written to this file, and depending on which conditional-compilation declarations are enabled, a large amout of additional data are recorded in the log. See Build Options for more information.

  Please refer to the individual methods listed for an explanation of the data written in each case.

- void ACWin::Screenshot ( bool html = false, const char* desc = NULL );

        Input  :
           html : (optional, default == false) output format
                  true  : HTML markup
                  false : plain text
           desc : (optional, default == null pointer) discriptive text

        Returns: nothing

  Capture a screenshot of the specified `ACWin` object to the log file.
  The capture is performed in a sectioned format as shown, and the developer is then responsible for integrating the sections to produce the finished screenshot.

  1. Window border (including optional window title)
  2. Static text block(s)
     These are sequences of text which have been written directly to the interior of the window, bypassing the control objects.
  3. Array of controls, in indexed order. Each control is written with outline and label, if specified.

  This procedure is significantly different from the author’s NcDialog library (based on ncurses) which performs window capture in a fully-integrated way, including color attributes. The `AnsiCmd/ACWin/ACDlg` library, however, is a much simpler creature.

  Plain-text Screenshots

  For monochrome plain-text screenshots (Texinfo `'.info'` documents), it is likely more efficient to simply copy-and-paste from the terminal window, but if the `'html'` parameter is reset, a plain-text capture will be performed. See the Linux documentation for `Ctrl+Shift+c` and `Ctrl+Shift+v` copy-and-paste commands.

  HTML Screenshots

  For HTML documentation, copy-and-paste is inefficient and error prone, so it is likely more efficient to use this capture method. This is especially true for a developer who is not fluent in HTML/CSS markup because placeholder `HTML/CSS3` style instructions are embedded in the screen-capture.

  The HTML output is placed inside a `<div class="tscap">...</div>` pair of tags which defines the dimensions, font family, basic color scheme and so on.

  Each row of the window border is bracketed by a placeholder sequence:
  `<span class="xxxx">...</span>` which provides a method for specification of color attributes for the left and right borders. Example:
  `<span class="bl_r">┌─────┐</span>`
  `<span class="bl_r">│</span> Hi! <span class="bl_r">│</span>`
  `<span class="bl_r">└─────┘</span>`
  which specifies blue text with foreground and background attributes reversed.

  > > ┌─────┐ │ Hi! │ └─────┘

  Please refer to the CSS class definitions in `infodoc-styles.css` for a description of the color-attribute classes.

  Each object within the window is also enclosed within a similar sequence.

  For greater control over the color palette, instead of calling out the pre-defined color attribute classes, the `<span class="xxxx;">` tag may be replaced with something similar to:
  `<span style="color:#0033FF; background-color:#99FF99;">`
  This tag specifies “web-safe” foreground and background color attributes. Please run the color tests (test C) included in this package, and visit the author’s website for a document “HTML/CSS Color Chart” describing web-safe colors.

  Hotkey designators are displayed using the ’underline’ text-modifier attribute. For these characters, a callout for the the CSS `"ulin"` class is embedded in the HTML output. For example the text of a Pushbutton may be written as: `"Buy Some ^Jiǎozǐ Today"`
  The caret character `('^')` indicates that the next character is the hotkey character, ’J’ in this example. Thus the HTML would be:
  `<span class="xxxx">Buy Some <span class="ulin">J</span>iǎozǐ Today</span>`
  This will cause the ’J’ to be underlined in the output.

  The primary test window for this functionality is Test_Cookie, which is a simple window used in the Texinfo documentation.
  (See skForm Class.)

  Note that the `Screenshot` method is huge compared to its actual usefulness, so be sure its conditional-compilation is disabled:
  `#define DEBUG_PHOTO (0)`
  when the method is not in use. See Building from Source for details.

  > Editor’s Note: Your humble author designed, tested and wrote the documentation for this routine in two days, all on battery-backup, while the power was out and snow and ice covered everything. Some exciting Spring Festival (春节假期) for 2025, Year of the Snake!

### skForm Class

Communication between the application and the user is the most complex (and most error prone) task for the application developer. Most of us would prefer to avoid user interactions as much as possible; however, without users (filthy beasts as they may be) there wouldn’t be much need for applications.

When designing an application, it must be assumed that the user interface section will not only require more code and more development time than any other section; it will require the developer to compensate for users’ (often illogical) assumptions about the program, and their blithe refusal to read the documentation.
The `skForm` and `skField` interface classes are your humble author’s attempt to make this process as painless as possible.

#### User Interaction

Some developers will want to write directly into the terminal window, and read the user’s responses directly from the window. The `AnsiCmd` primitives acRead, acWrite, ttyWrite, etc. are designed for this type of interaction.

Others will want to design an array of text-input fields and other types of controls for user interactions.
These controls are defined by Some-Kind-of-Form i.e. the `'skForm'` class.
Both the `ACWin` class (window) and the `ACDlg` class (dialog) support skForm-class objects. Within the skForm object, an array of `'skField'` objects defines the individual controls for user interaction.

If the ACWin constructor is called without specifying an skForm object, a default skForm object is created based on the size of the window. The default skForm object will be created with one(1) text-box (ftTB) skField object which takes the dimensions of the window interior.

To achieve direct control over the way the skForm object is configured, a pointer to an initialized skForm object is passed to the `ACWin` or `ACDlg` constructor.

    // Define and initialize an skForm/skField object.
    skForm* skfp = new skForm
    {
       FLD_COUNT,
       new skField[FLD_COUNT]
       {
          . . .
       },
       // Initialize remaining skForm parameters to default values.
       . . .
    } ;

    // Create a window.
    ACWin *win = new ACWin
          ( winROW, winCOL,                // position (upper-left corner)
            winHEIGHT, winWIDTH,           // dimensions (height, width)
            ltSINGLE,                      // border style
            bdrAttr,                       // border attributes
            intAttr,                       // interior attributes
            "  Secrets of the Universe  ", // window title
            skfp                           // pointer to skForm object
          ) ;

    // Create a dialog within a parent window
    this->win->Dialog
          ( dlgHgt, dlgWid,       // dialog dimensions
            skfp,                 // pointer to skForm object
            staticText,           // text written directly to dialog interior
            dlgTitle,             // dialog title
            ZERO, -1,             // dialog offset within parent window
            ltDUAL,               // border style
            acaUSEDFLT,           // border color attribute
            this->dlgAttr,        // interior color attribute
            0, 1,                 // interior text offset
            nonmember_dlgCallback // address of callback function
          ) ;

The position and dimensions of each field must fall entirely within the text area of the window, and the fields should not overlap (unless the obscured field(s) are set as “hidden”).

Although range checking and automatic positioning and size adjustments of the controls is performed, an over-caffinated developer could still cause chaos, so it is important to carefully verify the parameters which define the individual controls.

There are several ACWin objects and ACDlg invocations created in the test code included in this package. Some tests write text directly into the window, while others write into the defined fields (or some combination of the two). Please refer to those examples, as well as the discussion of skForm and skField classes below.

#### skForm Public Methods

The skForm-class object is a mostly passive construct, that is, the object doesn’t perform many tasks directly. Its primary function is to store and display information in an orderly and predictable way. The ACWin or ACDlg object updates this information in response to user activity.
Please see EditForm which acts as the gateway to the skForm data.

- skForm ( short fieldCount );

        Input  : fieldCount : number of skField objects
                              Range: 1 through 99

        Returns: implicitly returns a pointer to the object

  Simple constructor. Allocate resources for the skForm object and an array of skField objects. All data members receive default values.

  It is assumed that the application will populate all necessary data members after instantiation. Please see the initialization constructor below for more detailed information on the initialization of the individual data members.

  Technical Note: The default constructor (the constructor with no arguments) is set as private in order to protect the application layer from creating an unusable object.

- skForm ( short fieldCount, skField* fldArray,
  `` short fldIndex = ZERO, acAttr fldAttr = acaUSEDFLT,
  `` bool noisy = true, bool ioFlag = true, bool ioToggle = true,
  `` bool ioCursor = false,
  `` CurStyle insCursor = csBblock, CurStyle ovrCursor = csBuline );

        Input  : fldCount: number of objects in 'fldArray' (1-99)
                 fldArray: pointer to an array of skField objects defining
                           the form
                 //** Optional Arguments **
                 fldIndex: (optional, default: zero)
                           index of field which receives initial input focus
                 fldAttr : (optional, default: acaUSEDFLT)
                           For fields which change color when they receive
                           input focus, this is the focus color attribute.
                           -- acaUSEDFLT: If default attributes specified, then
                              when field receives input focus, the field's
                              embedded foreground and background attributes are
                              swapped.
                           -- If focus-color attributes are specified, then
                              when field receives input focus, this attribute
                              overrides the field's embedded attributes for as
                              long as the field holds focus, at which time the
                              embedded attributes are restored.
                 noisy   : (optional, default: true)
                           if 'true',  beep on unhandled keycode received
                           if 'false', silently discard the unhandled keycode
                 ioFlag  : (optional, default: set)
                           initial state of Insert/Overstrike flag
                           set  : Insert mode
                           reset: Overstrike mode
                 ioToggle: (optional, default: true)
                           if 'true',  user may toggle between Insert mode and
                                       Overstrike mode
                           if 'false', mode is fixed, and cannot be modified
                                       by user
                 ioCursor: (optional, default: false)
                           if 'true', shape of cursor changes to indicate
                                      current state of Insert/Overstrike flag
                           if 'false', cursor shape is not modified for
                                       Insert/Overstrike mode
                 insCursor: (optional, default: csBblock)
                            member of enum CurStyle indicating the cursor shape
                            to be used when in Insert mode.
                            (If 'ioCursor' flag is reset, then )
                            (only this cursor style is used.   )
                 ovrCursor: (optional, default: csBuline)
                            member of enum CurStyle indicating the cursor shape
                            to be used when in Overstrike mode.

        Returns: constructors _implicitly_ return a pointer to the object

  Initialization constructor.
  This constructor fully initializes the skForm data members AND transfers the data from caller’s skField array to the internal skField array.

  Important Note: The number of elements in `'fldArray'` must match the value in `'fldCount'`. If the array is larger than ‘fldCount’, then some field definitions may be discarded. If the array is smaller than ‘fldCount’, then a segmentation fault will be the likely result. Be Aware!

  Note that range checking and error correction are not performed by this constructor. Any needed corrections are made during instantiation of the parent window so that the values may be compared to the window definition.

- void operator= ( const skForm *skfp );

        Input  : (by reference) the skForm object containing source data

        Returns: nothing

  Assignment Operator: make a copy of the specified skForm object.
  The copy will include both the public and protected data members.

  If the assignment operator is used correctly, then source and target arrays should have the same number of elements; however, if the dynamic allocations do not match, the target allocations will be released and re-allocated to accomodate the data to be copied.

- ~skForm( void );

        Input  : none

        Returns: none

  Destructor: Release the dynamic allocation and delete the skForm object.

  For an “automatic” constructor allocation:
  `skForm skf( 6,`
  `new skField[6] = { ... },`
  `... );`
  The destructor will be invoked when the object goes out of scope.

  For a constructor created in dynamic memory:
  `sdForm* skf_ptr = new skForm`
  `( 6,`
  `new skField[6] = { ... },`
  `... );`
  The destructor is invoked directly:
  `delete skf_ptr;`

  > > Teacher Rant: Note that forgetting to delete a dynamically-allocated object when the task is complete would be considered as a "memory leak", a failure to return system resources once they are no longer needed. The author once spent five weeks chasing memory leaks in a multi-node Solaris system. It was not pretty. Please use extra care when working with dynamic memory allocations.

- bool skfProtectedMembers ( WinPos& p_base, wchar_t& p_pKey, short& p_seli, bool& p_foot, bool& p_dlg ) const;

        Input  :
           p_base : (by reference) receives offset for upper left
                     corner of parent window
           p_pKey : (by reference) receives most recent 'special'
                     keycode processed
           p_seli : (by reference) receives index of field containing
                     'selected' text (if any)
           p_foot : (by reference) receives the 'footer' flag
                     'true'  if Footer messages are enabled
                     'false' if Footer messages are disabled
           p_dlg  : (by reference) receives the 'dialog' flag
                     'true'  if skForm container is an ACDlg object
                     'false' if skForm container is an ACWin object

        Returns: 'true'  if AnsiCmd library debugging code is enabled:
                         (caller's parameters have been initialized)
                 'false' if AnsiCmd library debugging code is disabled:
                         (caller's parameters returned uninitialized)

  For Debugging Only.

  This method reports the “protected” data members of the skForm class.
  These values are not directly available at the application level, but may be useful during development.

#### skForm Data Members

- fCnt (internal use only)
  This is the number of elements in the `'fld'` array of skField objects. While this value is technically a public data member, it is set only once, during instantiation of the skForm object, and may not be modified after that.
- fld
  Pointer to an array of one or more `skField` objects which is dynamically allocated by the skForm constructor. Templates for these fields may be individually initialized by the application, then passed to the ACWin or ACDlg constructor, which performs range checking and adjustmens as necessary, and then copies the application’s values to the internal skForm object.
- fi
  Field Index. This value is used internally to track the index of the field which currently has the input focus. (default: zero)
  The initial value may be set to indicate the field with initial input focus, but is under control of the window during user interactions.
- faca
  If the field uses different color attributes based on whether the field has the input focus, this is the color attribute for when the field has input focus.
  For fields which do not include a visible cursor, use of this color is a visual indication of which field has focus.
- beep
  If set, this flag indicates that an auditory warning will sound when the user presses an invalid key. When reset, invalid keystrokes are silently discarded. (default: `'true'`)
  To modify this value, please see AlertEnable.
- ins
  Insert flag. When set, indicates Insert mode. When reset, indicates Overstrike mode. (default: `'true'`)
  This flag is referenced when user is modifying the text within a Textbox field (ftTB) to determine the input “mode”. The user can toggle between the modes by pressing the `Insert` key unless the `'togg'` flag is reset. (see below)
  To modify Insert key setup, please see InsertKey.
- togg
  If set, user may toggle the Insert/Overstrike mode. If reset, Ins/Ovr mode is locked in its current state and may not be modified by the user. (default: `'true'`)
- insc
  If set, this flag indicates that the cursor style changes when the insert/overstrike mode is toggled. (default: `'false'`.)
  The cursor style for each mode may be specified using the `'icur'` and `'ocur'` members described below.
- icur
  If `'insc'` is set, this is the cursor style used when in Insert Mode.
  Default: `'csBblock'`. (ignored when `'insc'` is reset)
- ocur
  If `'insc'` is set, this is the cursor style used when in Overstrike Mode.
  Default: `'csBuline'`. (ignored when `'insc'` is reset)

> Protected Data Members

- base (‘protected’, internal use only)
  This is the zero-based offset from the upper-left corner of the ACWin (or ACDlg) object’s interior. Used for calculating the position of the visible cursor.
- pkey (‘protected’, internal use only)
  Previous Key: This value tracks the most recent user input value.
- seli (‘protected’, internal use only)
  Selection Index: This value tracks the index of the field (if any) which contains “selected” text. This facilitates communication with the system clipboard.
- foot (‘protected’, internal use only)
  Enables or disables the method used to write “footnotes”, that is, diagnostic messages to the lower border of the window.
  See EnableFootnotes for setting and resetting this flag.
- dlg (‘protected’, internal use only)
  Used to distinguish whether operating in the parent window or a child dialog window. (The `ACDlg` class is a derived class based on the `ACWin` class.)
  See ACDlg Class for additional information.

#### skField Public Methods

- skField ( FldType fldType, short fldHeight, short fldWidth,
  `` short fldOffsetY, short fldOffsetX,
  `` //* Optional Arguments *
  `` const char* fldText = NULL, acAttr fldAttr = acaATTR_DFLT,
  `` FloType fldFlow = floChar, bool readOnly = false,
  `` bool fldBorder = false, bool fldHidden = false,
  `` bool fldLocked = true, bool binState = false,
  `` wchar_t hotKey = NULLCHAR, wchar_t groupId = noGROUP );

        Input  :
           fldType    : field type, member of enum FldType
           fldHeight  : field height in rows
           fldWidth   : field width in columns
           fldOffsetY : vertical offset from parent window origin
           fldOffsetX : horizontal offset from parent window origin
           fldText    : (optional, default: an empty string "\0")
                        Initial text data. Data configuration is dependent
                        on the field type. See documentation for details.
           fldAttr    : (optional, default: acaATTR_DFLT)
                        color attribute for field
                        Note that for field types which change color when they
                        receive input focus, this is the non-focus color.
           fldFlow    : (optional, default: floDflt) text flow
                        Automatic text formatting option for the field.
                        Formatting option is dependent on field type, and is
                        fully configurable only for Textbox controls (ftTB).
           readOnly   : (optional, default: false)
                        if set,  field is view only, cannot receive focus
           fldBorder  : (optional, default: false)
                         if false, field has no border.
                            Exception: Menubox controls always have a border.
                         if true,  draw an outline around the field
                            Note: Default line type and color attribute will be
                                  used to draw the outline. For a non-default
                                  line type or attribute, see SetFieldOutline().
           fldHidden  : (optional, default: false)
                        if set, field is not displayed and cannot receive focus
           fldLocked  : (optional, default: true)
                        if set, field is always visible (unless obscured by
                                another field.)
                        if reset, field becomes invisible when it loses focus.
                                (This is primarily for menus.)
           binState   : (optional, default: false)
                        For binary-state controls only (Radiobuttons),
                        specifies the initial state: "set" or "reset".
           hotKey     : (optional, default: null L'\0')
                        if specified, this is the hotkey character for setting
                        focus to field. Please see documentation about
                        specification and use of hotkeys.
           groupId    : (optional, default: noGROUP)
                        For fields whih can be grouped(Menubox and Radiobutton)
                        this is the character used to identify the members
                        of the group.

        Returns: constructors _implicitly_ return a pointer to the object

  Initialization constructor.
  The first five(5) arguments are required. The remaining arguments are optional and if not specified, will receive default values.

  The `ACWin` class test methods provide several examples of `skField` initialization.
  A representative sample initialization (skForm Initialization) is shown below.
  See test W, sub-test `'f'` for additional information.

- skField ( void );

        Input  : none

        Returns: constructors _implicitly_ return a pointer to the object

  The default constructor creates an skField object and initializes all members to their default values. This constructor has little practical value, but it remains a public method for those who wish to experiment.
  See the initialization constructor above for a more robust implementation.

- ~skField ( void );

        Input  : none

        Returns: nothing

  Destructor.

  The destructor is like the cleaning crew that comes into your Cabo hotel room after Spring Break. All resources allocated from the system are returned to the system, the mini-fridge is restocked and the iguana you forgot was in the shower is returned to the wild.
  (Lo siento mucho, Abue; tenía 19 años y estaba un poco fuera de control.)

- void operator= ( const skField& skf );

        Input  : (by reference) the skField object containing source data

        Returns: nothing

  Assignment Operator: make a copy of the specified skField object.
  The copy will include both the public and protected data members.
  See also the skForm operator=() above.

- bool outlineConfig ( LineType lType, acAttr lAttr = acaUSEDFLT );

        Input  :
           lType   : line type for border, member of enum LineType
                     ltSINGLE (default), ltDUAL, ltHORIZ (invisible border)
           lAttr   : (optional, default: acaUSEDFLT) border color attribute
                     if not specified, takes attribute of window interior
                     -- Note that this parameter does not apply to menu
                        controls which take their outline color from the
                        menu data.

        Returns: 'true'  if successful
                 'false' if field type does not allow borders

  Set the line type and attribute for the field outline.

  The data members which contain these values are ’protected’, that is, they are not available at the application level. This skField public method is provided so these values can be initialized before the window or dialog is instantiated. The configured fields will be displayed when the window(dialog) is opened.

  1. Note that this method should be called ONLY before the window (or dialog) constructor is called. To initialize the border after the window/dialog is created, call the ACWin-class SetFieldOutline method instead.
  2. Field outlines are incompatible for Menu controls (ftMB) because menus have integrated borders.
  3. Because this call does not reference the parent window(dialog), error checking of positioning or interference with the border and with other fields cannot be performed here. For this reason, use caution when initiating these values.
  4. This method is intended primarily for initializing the skForm/skField object to be used as a parameter when invoking a full-initialization dialog; however, it is possible to use this method when initializing the skForm/skField object to be used as a parameter when defining an ACWin object. In this case, use extra care in positioning the specified control.

  Please see skField config example below for an example of using `outlineConfig`.

- bool labelConfig ( const char* labText, acAttr labAttr = acaUSEDFLT, bool center = false);

        Input  :
           labText : display text, optionally including a "hotkey" character.
                     A hotkey is specified using the CARET character ('^')
                     followed by the ASCII character which indicates the@item
                     keycode to be used as a hotkey. (see example above)
           labAttr : (optional, default: acaUSEDFLT) color attribute for label
                     If not specified label color is set to color of parent
                     window interior
           center  : (optional, default:'false') horizontal offset
                     if set, center the label horizontally above the field
                     if reset, label offset is in the same column as the
                               left edge of the field

        Returns: 'true'  if successful
                 'false' if field type does not allow external label

  Specify label text, color and position.

  The data members which contain these values are ’protected’, that is, they are not available at the application level. This skField public method is provided so these values can be initialized before the window or dialog is instantiated. The configured fields will be displayed when the window (or dialog) is opened.

  Note that this method should be called ONLY before the window (or dialog) constructor is called. To initialize the border after the window is created, call the ACWin-class SetFieldLabel method instead.

  The following control types will accept labels: 1) ftTB - Textbox 2) ftSB - Scrollbox 3) ftMB - Menu Note that only certain menus may have labels. a) Context menus i.e. multi-row menus which are not group members. b) Menubar menus i.e. single-row menus which anchor a group of menu controls. External labels are incompatible for Pushbuttons (ftPB) and Radiobuttons (ftRB) because the field text is the label. See below for a label configuration method specifically for Radiobuttons.

  Please see skField config example below for an example of using `labelConfig`.

- bool labelConfig ( acAttr labAttr, bool lableft = false );

        Input  :
           labAttr : color attributes for Radiobutton label
                     If acaUSEDFLT specified, then label color is set to color
                     of parent window interior
           lableft : (optional, default:'false') horizontal offset
                     if set, label is displayed to the left of the control
                     if reset, label is displayed to the right of the control

        Returns: 'true'  if successful
                 'false' if incorrect field type

  Specify label color attributes and position.

  This overload is designed for Radiobutton controls (ftRB) only.
  To initialize labels for other types of controls, see above.

  By default Radiobutton labels inherit the color attributes of the parent window/dialog and the label is positioned to the right of the field.
  This method allows direct specification of the label attributes and optionally allows the label to be positioned to the left of the control.

  The data members which contain these values are ’protected’, that is, they are not available at the application level. This skField public method is provided so these values can be initialized before the window or dialog is instantiated. The configured fields will be displayed when the window(dialog) is opened.

  Note that this method should be called ONLY before the window (or dialog) constructor is called.

        skForm* skfp( ... ) ;
        // Field definition and formatting for a Radiobutton control:
        // The caret character, if present, indicates the hotkey
        // character for setting input focus to target field.
        // Define the text and position of the control
        short row_offset = 2, col_offset 14 ;
        const char* rbDef = "[♦] Comp^uter Science" ;

        // By default the field and label would be displayed as:
              [♦] Computer Science
                    ▔
        // If label configuration with field/label swap, the overall
        // position within the window will be unchanged, but field
        // and label will swap positions as shown.:
        skfp->fld[n].labelConfig ( acAttr(acaFG_BLUE|acaUSEDFLT), true );
              Computer Science [♦]
                  ▔

  Note that a space after the closing brace will automatically be removed, and a space will be appended to the label text:
  `"[♦] Computer Science"` becomes
  `"Computer Science [♦]"`
  See AcEdit Demo App, `'Compare Files'` dialog for a working example of this option.

- bool colorConfig ( const acAttr* rowAttr, short rowCnt );

        Input  :
           rowAttr: pointer to an array of acAttr color attributes, one
                    attribute for each text row of the control.
           rowCnt : number of attribute values in the 'rowAttr' array
                    Value must be greater than zero, and the minimum
                    _practical_ value is two(2)

        Returns:
           'true'  if successful
           'false' if field type does not support per-row attributes
                   or if 'rowCnt' less than minimum

  Specify an array of color attributes, one for each item (row of text data) within the control.

  Customization of text color attributes is often useful to enhance readability of multi-row controls which contain fixed display text. For multi-row Menu controls (ftMB) and Scrollbox controls (ftSB) only, color attributes for each individual display row may be specified.

  The data member which contains these color values is ’protected’, that is, it is not available at the application level. This skField public method is provided so that custom color attributes may be specified, one attribute per text row, after the skField object has been instantiated, but before the window (or dialog) constructor is called.
  The reonfigured field will be displayed when the window(dialog) is opened.

  The following control types support custom color attributes:
  These control types are designed to contain read-only data; (the data may may not be edited under user control); therefore, it is possible to embed color attributes within the displayed text.

  1. ftMB - Menu
     - All items within a menu are visible simultaneously whenever the menu itself is visible. Therefore one custom color must be specified for each item. Do not specify attributes for the upper or lower borders. - Note that the specified attributes apply only to the text displayed within the control, and not to the borders drawn around the text. - Only multi-row (multi-item) menus support custom colors. A single-row menu (menu bar) is excluded, because it has only one row, and therefore only one color.
  2. ftSB - Scrollbox
     - Scrollbox controls may contain any number of text items, although the number of items visible at any moment is determined by the height of the control. Therefore, a custom color must be specified for each item (row) whether it is visible or not. - Please note that if text data provided for a Scrollbox control is incorrectly formatted, it will be automatically reformatted to fit the control. If this happens, the color attribute specified for each row may not be as expected. Beware!

  Any valid `acAttr` color attribute bitfield may be specified.
  The acUSEDFLT value indicates that the target item will use the attribute specified in the skField’s ’aca’ member. This is the attribute for the control as a whole.

  Please refer to the example below.

  IMPORTANT NOTE:

  This method includes some defensive programming; however, it is not possible to anticipate all potential foolishness, so be careful! Applying per-item color attributes must rely on text data formatting which has not yet been programatically validated.

  This method should only be called for controls within a dialog (ACDlg) object, and only if you are certain that the text to be displayed within the control has been properly dimensioned, ensuring that the attribute count will equal item count.

  For controls within a window (ACWin) object, please use the SetFieldAttr method instead. Using `SetFieldAttr` will be safer because it will be called after the control dimensions and text formatting have been verified.

  skField config example

      // Create and initialize an skForm object with an array of three(3)
      // skField objects: a Textbox, a Context Menu and a Pushbutton.
      sdForm* skf_ptr = new skForm
              ( 3,
                new skField[3] =
                {
                  { ftTB, ... }, // Textbox      (index 0)
                  { ftMB, ... }, // Context Menu (index 1)
                  { ftPB, ... }, // Pushbutton   (index 2)
                },
                ... );

      // Specify that an outline is to be drawn around
      // the Textbox control.
      skf_ptr->fld[0].outlineConfig ( ltDUAL,
                                      acAttr(acaFG_BLUE | acaBG_CYAN) );

      // Specify a label for the Textbox control
      skf_ptr->fld[0].labelConfig ( "Date Of Birth " );

      // Specify a label for the Menu control,
      // (centered, with contrasting color).
      skf_ptr->fld[0].labelConfig ( "  Education Level  ",
                                    acaFG_BLACK | acaBG_GREY), true );

      // Specify an array of per-item color attributes for the Menu.
      // In this example, progressive web-safe RGB colors are built.
      // The divider item inherits the color of the menu control.
      // (Note the extra element appended for safety.)
      acaExpand acex ;
      el00 = acex.buildRgb( true, wsrgbBLACK,
                            true, WebSafeRGB(wsrgbBROWN + wsrgbSHADE_MED));
       ...
      el10 = acex.buildRgb( true, WebSafeRGB(wsrgbRED + 9),
                            true, WebSafeRGB(wsrgbGREY + wsrgbSHADE_MED));

      short COLOR_ELEMENTS = 11;
      acAttr acArray[COLOR_ELEMENTS + 1] =
         { el00, el01, el02, el03, el04, el05, el06,
           acaUSEDFLT, el08, el09, el10, acaUSEDFLT };

      skf_ptr->fld[1].colorConfig ( acArray, COLOR_ELEMENTS );

  ┌────────────────── Biographical Data ──────────────────┐ │ │ │ Education Level │ │ ┌──────────────────────────┐ │ │ ╔Date Of Birth ═════╗ │ Primary School Primate │ │ │ ║02/29/1996 ║ │ Middle School Muskrat │ │ │ ╚═══════════════════╝ │ High School Hyena │ │ │ │ Associate of Animals │ │ │ │ Bachelor of Bulldookie │ │ │ │ Master of Monkey Dung │ │ │ │ Piled Higher and Deeper │ │ │ │ ──────────────────────── │ │ │ │ School of Hard Knocks │ │ │ │ Ain't Got None │ │ │ │ Don't Wanna Know Nothin' │ │ │ └──────────────────────────┘ │ │ │ │ CLOSE │ └───────────────────────────────────────────────────────┘
- bool getItem ( gString& iTxt, short& iNum, bool selnum = false ) const;

        Input  :
           iTxt  : (by reference) receives item text data
           iNum  : (by reference) receives the index of the "item" referenced
                   by the 'ip' member (item referenced by the cursor)
                   (This is the 0-based item index.)
           selnum: (optional, default: false) for multi-row controls only
                   if set AND if a previously "selected" item (sitem >= zero),
                      return index of "selected" item.
                   if reset, return index of item containing the IP.

        Returns: 'true'  if supported target control type (ftMB || ftSB), AND
                         if item identified
                 else 'false'

  For Menus (ftMB) and Scrollbox controls (ftSB), retrieve the index of the `"item"` (row) containing the insertion point (`'ip'`). Generally, this is the currently hightlighted item or the item which was highlighted when the control lost focus.

  The `'getItem'` method returns both the item index and the actual text of the item.

  The optional `'selnum'` parameter may be used to report either the target control’s highlighted item or the item (if any) “selected” by the user via the `Enter` or `Space` key.

  The text of a menu item may contain an embedded hotkey indicator which is identified as the character following the caret (`'^'`). Example `"Sa^ve file"` where the `'v'` is the hotkey character.
  This is described more fully in the chapter skField Data Members.

  This method will typically be called from an application callback function or immediately after a dialog window has closed.
  See EstablishCallback or the Dialog method’s `'callbk'` parameter for more information on establishing and using callbacks.

  Also, see GetFieldItem which is a form-oriented method which provides information similar to `getItem`.

  Understanding “Items”

  For purposes of this discussion, an “item” is a row of text displayed within the control.
  For example, the following diagram shows the different types of menus: a) context menu, b) menu group sub-menu, and c) the ‘Menubar’ (single-row menu).

           Context Menu          Group Submenu
         ┌────────────────┐
         │Open a file     │    │Open a file     │ <-- iNum == zero
         │Save file       │    │Save file       │
         │Close file      │    │Close file      │
         │Exit Application│    │Exit Application│ <-- iNum == 3
         └────────────────┘    └────────────────┘

         Example menubar:
         ----------------
                | File  Edit  View  Help |
                  ↥     ↥     ↥     ↥
           item:  0     1     2     3

  Scrollbox controls (ftSB) typically contain plain, paragraph-oriented text data, not itemized data records; however, if desired, the application may define each display row of the Scrollbox control as a data item. This implements what is essentially a scrolling menu for situations where there are a large number of items to be displayed.
  The following example is taken from the AcEdit Demo App which displays a list of files in the current directory, and asks the user to select a file to be edited. This type of control can accomodate any reasonable number of items.
  The `'▶'` indicator character, identifies the current item, and when the user presses the `Enter` or `Space` key, that item is “selected”. In the example, the indicator is on `AcEdit.cpp` and its item index is four(4).
  When the Scrollbox loses focus, the selection indicator will be replaced by the `'▷'` character.

      ╔══════╣  Open a File For Editing  ╠════════╗
      ║  .. parent directory                      ║
      ║  > 1_TestData                             ║
      ║  · ace                                    ║
      ║  · ace.cfg                                ║
      ║▶ · AcEdit.cpp                             ║ <-- iNum == 4
      ║  · AcEdit.hpp                             ║
      ║  · AcEdit.o                               ║
      ║  · AcEditCfg.cpp                          ║
      ║  · AcEditCfg.o                            ║
      ║  · dbg.log                                ║
      ║  · gString.hpp                            ║
      ║ ───────────────────────────────────────── ║
      ║             OPEN       CANCEL             ║
      ╚═══════════════════════════════════════════╝

- bool skField::setHiliteMod ( acAttr txtMod );

        Input  :
           txtmod:
              text modifier attribute for highlighting text segments.
              One of the following text modifier attributes:
               acaBOLD      bold-text modifier
               acaITALIC    italic-text modifier
               acaUNDERLINE underline-text modifier (not recommended)
               acaOVERLINE  overline-text modifier
               acaXOUT      x-out (strikethrough) text modifier
               acaBLINK     blinking-text modifier
               acaCONCEAL   concealed (invisible) text
               acaREVERSE   reversed fgnd/bkgnd (default)
              The specified modifier flag _should not_ also be set
              as an element of control's base color attribute.
              Note: OR'd combinations of these modifiers are not allowed.

        Returns:
           'true'  if highlight attribute set successfully
           'false' if a) invalid modifier specified and discarded.
                         (default modifier, acaREVERSE, will be used)
                      b) field type does not support text highlighting

  For Textbox (ftTB) controls, set the text-modifier attribute to be used for highlighted substrings.

  The data member which contains this value is ’protected’, that is, it is not available at the application level. This method can be called for any Textbox field in an initialized skForm object, before the window/dialog has been defined.

      //* Define an skForm object with two controls. *
      skForm* skfp = new skForm
      (
         fldCOUNT,
         new skField[fldCOUNT]
         {
            //* Field index 0: ftTB (Textbox: fldTB_SEGMENT) *
            {
               ftTB,             // field type
               . . .
            },
            //* Field index 1: ftPB (Pushbutton: fldPB_FWRD) *
            {
               ftPB,                            // field type
               . . .
            },
         } ;
         . . .
      );

      //* Set the modifier for text highlight *
      skfp->fld[0].setHiliteMod ( acaITALIC );

      //* Define an ACWin object *
      ACWin *win = new ACWin
            ( winROW, winCOL,           // position (upper-left corner)
              winHEIGHT, winWIDTH,      // dimensions (height, width)
              ltDUAL,                   // border style
              acaBorder,                // border attributes
              acaInterior,              // interior attributes
              " Highlight Field Text ", // window title
              skfPtr
            ) ;

  To set the hilight modifier after the window has been created,
  please see SetHilightMod or HilightFieldText.

  Notes:

  1. The specified value will replace any previous highlight attribute.
  2. If the HilightFieldText() method is called with any attribute value other than the default (acaUSEDFLT), that value will replace any value set by this method.
  3. This method does not refresh the display, so the new highlight attribute will not be visible until the next time the field is refreshed.
- bool getHilite ( int& begin, int& len, gString& gsTxt );

        Input  :
           begin : (by reference) receives index of first (leftmost)
                   character of highlighted text segment
           len   : (by reference) receives the number of characters in
                   the highlighted segment
           gsTxt : (by reference) receives a copy of the highlighted text
           hmod  : (optional, default:null pointer) if specified, target
                   receives current text-modifier attribute used to highlight
                   the text segment

        Returns:
           'true'  if highlighted text data successfullly captured.
           'false' a) target field contains no highlighted/selected text data
                   b) field type does not support text highlighting
                   If 'false', then 'begin' and 'len' are set to zero,
                   'hmod' is set to acaPLAINTEXT and 'gsTxt' is cleared
                   (set to empty string).

  Returns a copy of highlighted text segment within a Textbox (ftTB) field.
  This method was developed primarily for use during development; however, it may have other uses.

  Conceptually similar to copying a “selected” text substring to the clipboard, except that the data are returned directly to caller without accessing the clipboard.

  Technical Note: This method does not distinguish between “highlighted” text and “selected” text.
  The text delimited by the `'sela'` and `'selb'` members is returned regardless.

  Example:
  This method is used in the callback function for the Test_Hilite method of the `AnsiCmd` test suite. Refer to `thtCallback() in AnsiCmdTest.cpp` for details.

  gString gsOut, gs ; skField skfld ; int get_beg, get_len ; acAttr get_hmod ; win->GetFieldData ( ctrlIndex, skfld ) ; skfld.getHilite ( get_beg, get_len, gs, &get_hmod ) ; gsOut.compose( " Capture Highlight '%S' beg:%d len:%d hmod:%08X ", gs.gstr(), &get_beg, &get_len, &get_hmod ) ; win->Footnote ( gsOut.gstr(), 35 ) ;

  Please see HilightFieldText for more information on text highlighting.

#### skField Data Members

The data members of the `skField` class support multiple types of user interface controls (see UI Control Types).

Most of the members are public, that is, the application can initialize them and monitor modification arising from user interactions. Other members are “protected”, meaning that they are not directly available to the application. These members must be protected to maintain data integrity; however, most can be read and modified indirectly using public methods of the `ACWin` class, the `skForm` class, the `skField` class, or some combination of these.

Some public members must be initialized explicitly, while others can be used with default values. These defaults are listed here.

Public Data Members

- type
  Field Type: Specifies the type of field as a member of enum FldType. The type of field defines how the user interacts with the field.
  See UI Control Types for notes on the individual control types.
- hgt
  Height: This is the number of vertical rows for the field.
  Minimum: 1 row for most types, but 2 rows for Menus
  `` and Scrollbox controls.
  Maximum: Height of parent window minus 2.
- wid
  Width : This is the number horizontal columns for the field.
  Minimum: 1 column, but 3-6 columns is the practical
  `` minimum for most types.
  Maximum: Width of parent window minus 2.
- orig
  This is the 0-based offset from the skForm’s `'base'` coordinates, which in turn is the 1-based offset from the upper-left corner of the terminal window.
  Note that within an ACWin object, `'skForm.base'` is the same as the `'txtBase'` member of the ACWin object.
  Minimum: 0,0 which is the upper left corner of the container.
  Maximum: Height of (container-2) minus `'hgt'`.
  `` Width of (container-2) minus `'wid'`.
- txt
  Text displayed in the field.
  The initial text required for a control depends upon the control type, its dimensions and other factors. Pushbuttons, Radiobuttons, Menus and Scrolbox controls, for instance, contain only fixed text which is set when the control is initialized.
  In contrast, Textbox controls may initially be empty or may contain any reasonable amount of formatted or unformatted text, which may then be updated either programatically or through user interaction.

  The text of each field is managed within a gString object.
  Please see gString Text Tool for more information.
  The amount of storage space allocated is calculated dynamically up to a limit if gsALLOCMAX (1.0 Megabyte).
  To modify field text, please see SetFieldText.

- aca
  Optional parameter, default: acaUSEDFLT.
  This member holds the color attributes of the field, which is a `logical OR` of enum acAttr values. If the default value is used, then field colors will inherited from the window interior attributes.
  To modify this value, please see SetFieldAttr.
- flow
  Optional parameter, default: floChar for multi-row textbox, floShift for all other types.
  Flow control (multi-row Textbox fields only): This field contains a value from enum FloType and indicates the type of automatic formatting to be performed.
  Please see SetFieldFlow for a description of formatting options.
- ip
  Optional parameter, default: zero(0), upper left corner of field.
  Insertion Point: This is the character index for the logical cursor position within the field. The position of the visible cursor is calculated from this value, and user input is inserted into the text at that point.
  To modify this value, please see SetFieldIP.
- ro
  Optional parameter, default: false.
  Read Only: If set, the field cannot receive input focus. This means that the contents may be read but the data may not be modified under user control.
  If reset, the field can receive input focus, and for Textbox controls, the user can modify the text of the field.
  To modify this value, please see SetReadOnly.
- bdr
  Optional parameter, default: false.
  This flag may be set (`'true'`) to indicate that a border is to be drawn around the field.
  Note that the `'bdr'` flag is public and may therefore be specified during instantiation; however the `'btype'` (border line type) and `'battr'` (border line color) are protected members, so if a non-default border is needed, it should be set after opening the window.
  All types of controls support borders, except Menus (ftMB), for which the border is built into the text of the control.
  Please see SetFieldOutline method for details.
- hide
  Optional parameter, default: false (except for menus).
  If the field is set to hidden, it is not visible, and it will become visible and available to the user only if the associated hotkey (if any) is pressed; or if the application re-enables display of the field.
  Menu controls are a special case, in that they are automatically set as invisible when they lose focus.
  Please see SetFieldHidden method for details.
- lock
  Optional parameter, default: true (except for menus).
  The `'lock'` flag is primarily used to control visibility and accessibility of menu controls when they receive and lose the input focus.
  When the `'lock'` flag is set, it indicates that the control is always visible in the window regardless of whether it has focus (unless is obscured by another control). When `'lock'` is reset, the menu field will be set as invisible and inactive when it loses focus (see ’hide’ flag).
  Exception: A Menubar control stays open if any member of its group has focus. This flag may also be used in combination with the `'hide'` flag to de-activate other types of fields which are not currently in use. This prevents wasted time refreshing fields which are fully obscured by other fields.
  Currently, this flag is initialized during instantiation and may not be modified under program control. This decision may be revisited in a later release.
- state
  Optional parameter, default: false.
  For Radiobuttons and other binary-state controls, this flag indicates the current state (set or reset i.e. `'true'` or `'false'`).
  Please see SetFieldState for more information.
- hkey
  Optional parameter, default: null character (’\0’), no hotkey assigned.
  Hotkey assigned to the control.
  Valid values are the `GUI` keys (wcsALT_A, etc.) and function keys (wcsF01, etc.).
  For Pushbuttons (ftPB) and Radiobuttons (ftRB), the hotkey (if any) is embedded within the text of the control, so for those control types, the `'hkey'` value is ignored.

  While direct specification of hotkeys is valid for all other control types, this is recommended only for Menu controls because Menu controls have no label.
  For all other control types it is recommended that if a hotkey is desired, it should be embedded in the field label.
  See SetFieldLabel and SetFieldHotkey methods for details.

- grp
  Optional parameter, default: noGROUP i.e. null character (’\0’)
  For Radiobuttons, Menus and other control types which can be grouped.
  Group members are identified by their shared use of this character. Any wchar_t (wide) character may be specified as the group indicator. This value is set during initialization and may not be modified afterward.
- mrptr
  This is a public const pointer to the protected MRParse object defined within this class. Because it is a “const MRParse*”, this means that the application layer may `VIEW BUT NOT MODIFY` the text-parsing data. Please study the MRParse class for a description of these data.
  Please see GetFieldData for accessing these data.
  See also the dumpMrp2Log method.

Protected Data Members

- mrp (‘protected’ member, internal use only)
  The `MRParse` object contains analytical data on the field contents including the number of text rows and the relative display position of the data within the control. Also included is both the logical and physical cursor position within the field.
  These data are primarily for multi-row text fields; however, the information is also used to initialize the data contained by other control types.
  To examine how this analysis is performed in the source code, see the private method: `'parseFieldText'`.
  Please see GetFieldData for accessing a copy of these data.
- lab (‘protected’ member, internal use only)
  This member contains the label text (if any) for the control.
  Please see SetFieldLabel for initializing a control label.
- lpos (‘protected’ member, internal use only)
  This is the display position for the control label relative to the container window.
- lattr (‘protected’ member, internal use only)
  Color attributes for the label text (if any).
  Please see SetFieldLabel for initializing a control label.
- battr (‘protected’ member, internal use only)
  Color attributes for the control outline (if any).
  Please see SetFieldOutline for initializing a control outline.
- cur (‘protected’ member, internal use only)
  This is a WinPos object and contains the 0-based offset from the control’s `'orig'` coordinates which defines the position of the visible cursor. This value is dynamically calculated from the `'ip'` (insertion point) member.
- btype (‘protected’ member, internal use only)
  If an outline for the control has been specified, this is the outline type, a member of `enum LineType`, either `ltSINGLE` or `ltDUAL`.
  Please see SetFieldOutline for initializing a control outline.
- sitem (‘protected’ member, internal use only)
  For Menu (ftMB) controls and Scrollbox (ftSB) control only, the index of the ‘selected’ item.
  Please see GetFieldItem for retrieving this value.
- iAttr (‘protected’ member, internal use only)
  By default, text data within a control is displayed using a single color attribute. For item-oriented data however, (specifically menu items), each item may be displayed in a different color. Both menus (ftMB) and scrollbox (ftSB) controls support item-oriented, multi-color data.
  Please see SetFieldAttr or the colorConfig `skField`-class method for details.
- rbch (‘protected’ member, internal use only)
  For Radiobutton (ftRB) controls only, the display character used to indicate the “set” state of the control. Note that this character is extracted from the initialization text for the Radiobutton control.
  Example: `"[♦] ^Authorize daily cookie delivery"`
- off (‘protected’ member, internal use only)
  Text Offset: Used when scrolling text vertically within a field to indicate the index of the first character of the top visible row.
- shft (‘protected’ member, internal use only)
  Text Shift: Used when scrolling text horizontally within a field to indicate the offset from the beginning of the text row to the first (leftmost) visible character.
- sela and selb (‘protected’ members, internal use only)
  These members are delimeters (indices) for “selected” text within the field. Selected text is identified by being underlined within the control.
  Selecting text is related to copy-and-paste operations. Text selection and the Copy, Cut and Paste operations are performed within Textbox (ftTB) controls only. Please see test T for functional examples of these operations.
  Invoke this test using: `./epts --test=Tea`

#### UI Control Types

Field Types

The types of user-interface controls `"fields"` are defined by the `FldType` enumerated type.

// Field Type for controls defined by the skField class enum FldType : short { ftPB, // PushButton (select) ftRB, // Radio Button (on/off) ftTB, // Text Box (edit text) ftSB, // ScrollBox (view and scroll text) ftMB, // Menu Box (select item) } ;

The data for each control type is initialized as an instance of the `skField` class.
See skField Data Members for a discussion of each data member.

`"Your focus determines your reality."`
`-- Qui-Gon Jinn`

To understand input fields, it is important to understand the concept of “input focus”. Input focus, or just “focus” can be defined as the point where keyboard input is received and processed.

Just at the terminal’s `'stdin'` stream receives key input from the user, the control which is currently monitoring the `stdin` stream (the control with focus) receives the key input and decides whether to process it directly (retain focus), or pass it on to another control (transfer focus).

In general focus is transferred in response to one of the cursor keys:
Tab, Shift+Tab, Up/Down/Right/Left Arrow, PageUp, PageDown, Home, End; or by receipt of the “hotkey” assigned to a control. Under some circumstances, the Enter or Space keys can also trigger a shift in focus.

- Pushbutton (ftPB):
  The most simple type of control is the `"Pushbutton"`.
  Pusbutton controls process only two keycodes: `'Enter' and 'Space'`. Thus to “push” a Pushbutton means to press the Enter or Space key while the control has focus. The application will then determine what action is taken in response.
  `▒▒▒OK▒▒▒ ▒▒CANCEL▒▒`
- Radiobutton (ftRB):
  Radiobuttons are very similar in function to Pushbuttons in that they respond directly only to the `'Enter' and 'Space'` keys.

  Radiobuttons are so called because their function resembles that of the buttons on archaic car radios. They have two states: either “ON” or “OFF”.

  A Radiobutton can be a stand-alone control, or can be configured as a member of an XOR Radiobutton group. The term“XOR” is nerd-speak for “Exclusive OR”, meaning that exacty one button of the group may be ON at any given moment. All other buttons of the group are reset (OFF) when any member of the group is set (ON).
  `[ ] Small`
  `[◆] Medium`
  `[ ] Large`
  `[ ] Extra Large`
  `[ ] XX Large`
  `[ ] XXX Large`

  If an application-level callback function is active, it can immediately respond to the control’s change in state, or action can be deferred until the window or dialog is closed, or until some other criteria are met.

- Textbox (ftTB):
  Textbox controls are as the name implies a way to collect text data from the user. The input can be monitored on a per-character basis or collected as a unit when user shifts the focus to another control. Textbox controls may optionally be outlined.
  ┌─────────────────┤ ZMail - Create ├─────────────────┐ │Dear Mom and Dad, │ │Sorry I won't be able to make it home for Christmas │ │this year, but if you could send me $500, I'd be │ │happy to get you a Christmas gift. │ │ -- Your loving daughter, Anita │ └────────────────────────────────────────────────────┘

  One special characteristic of Textbox controls is that they can receive data directly from the clipboard or send data to the clipboard.
  See Communicate With System Clipboard for more information.

- Scrollbox (ftSB):
  The function of a Scrollbox control depends upon the type of data it contains. The Scrollbox can display plain, paragraph-oriented text data, or it can be configured as a scrolling list of items. Scrollbox controls may optionally be outlined.

  When configured to display ordinary text, the user may scroll upward and downward through the data. Horizontal scrolling is not supported.

  ┌─────────────────────────────────────────────────────┐ │ There once was a man from Kirkuk, │ │ Who was known far and wide for his luck, │ │ Till while jogging one day, he looked the wrong way,│ │ Whereupon he was hit by a truck. │ └─────────────────────────────────────────────────────┘

  When configured as a list of individual item (one per line), then the user can scroll through the data and “select” any item, just as an item is selected from a Menu control (see below).

  ┌Select Your Ride────────────────────┐ │ 1951 Studebaker Starlight Coupe │ │▶ 1967 Chevy Camero │ │ 1971 Dodbge Super Bee │ │ 1977 Ford Bronco │ └────────────────────────────────────┘
- Menu (ftMB):
  Menu controls are a special case in that there are three distinct types of menus, each performing a different task:
  1. Menubar: The Menubar is a single-row menu that acts as a anchor point for a group of menus which are functionally tied together. This is a common construct used in almost every `GUI` application.
     A Menubar may be initially invisible, but if desired, can be locked in the visible state.
     The Firefox browser menubar is:
     `File Edit View History Bookmarks Tools Help`
     `▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔`
     Each item in the Menu bar is associated with at least one sub-menu, which together form the menu system for the application.
  2. Sub-menu:
     Sub-menus are menus attached to a Menubar (as described above). A sub-menu is invisible by default, and is opened by an action taken on the Menubar, or in combination with the Menubar via an application-defined hotkey.
     FILE EDIT HELP ▔▔▔▔▔▔▔│▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔│▔▔▔▔▔▔▔▔ │Copy Selection (C-c)│ │Cut Selection (C-x)│ │Paste Clipboard (C-v)│ │Find Text (C-f)│ └──────────────────────┘
  3. Context Menu
     A “Context menu” is a stand-alone menu that operates in a specific “context”. (duh!)

     A context menu is generally defined as invisible until it is needed; and becomes invisible again after a selection is made. It is possible, however, to lock a context menu in the visible state.

     ┌─────────────────┐ │View Contents │ │View file Stats │ │Open (execute) │ │Find Link Target │ │Cancel │ └─────────────────┘

     The context menu shown is from the author’s `FileMangler` application
     See By the Same Author for a description.

Numerous functional examples of these controls are available throughout the test applications included in the `AnsiCmd` library.
Please see Development and Testing for a general description of the tests available. Specifically, the tests listed under test W and test D, which contain subtests for Windows, skForm/skField and Dialogs invoked with:
`./epts --test=W`
`./epts --test=D`
The `AcEdit` application includes a functional set of controls in an (almost) real-world context.
`cd AcEdit`
`./ace`

#### skForm Initialization

To create an skForm template, allocate a new object specifying the number of fields, the global parameters and the definition for each field.

┌─────────┤ ACWin-class Window ├─────────┐ │ ┌────────────────────────────────────┐ │ │ │ Me love cookies! Cookie! │ │ │ └────────────────────────────────────┘ │ │ │ │ [♦] Authorize daily cookie delivery │ │ │ │ Close Window │ │ │ └────────────────────────────────────────┘

Define the skForm template:
This example creates an skForm object with three(3) fields: a Textbox (ftTB), a Radiobutton control (ftRB) and a Pushbutton control (ftPB).

Note that many parameters of these constructors have default values, but for clarity, they are explicity initialized here. See skForm and skField initialization constructors, above for details.

The working code for this example can be found in the `'Test_Cookie'` method in `AnsiCmdTest.cpp`.

//* Focus Color: for controls which can change color when * //* they have input focus. (Pushbuttons, Radiobuttons) * acAttr focusAttr = acAttr(acaFGb_GREY | acaBG_RED) ; //* Non-Focus (embedded) color for Pushbuttons and Radiobuttons. * acAttr nonFocus = acAttr(acaFG_BLACK | acaBG_RED) ; WinPos wpul( 1, 2 ) ; // vertical/horizontal offsets const short pbFIELD = 2 ; // index of pushbutton field const short FLD_COUNT = 3 ; // number of fields skForm *skfPtr = new skForm ( FLD_COUNT, // number of skField objects in 'fldArray' new skField[FLD_COUNT] // array of field definitions { //* Field index 0: ftTB (Textbox) * { ftTB, // field type 1, // field height (in rows) winWIDTH - 6, // field width (in columns) wpul.row, wpul.col, // Y/X offset in window " Me love cookies! Cookie!",// initial field text acAttr(acaFG_DFLT | acaBG_CYAN), // color attributes for text floShift, // text formatting option (text-editor mode) ZERO, // insertion point (cursor offset) false, // user accessible (not read-only) true, // field outline enabled false, // field is visible (not hidden) true, // access lock enabled false, // binary state not applicable to ftTB NULLCHAR, // no hotkey specified noGROUP // not a group member }, //* Field index 1: ftRB (Radiobutton) * { ftRB, // field type 1, // field height (in rows) winWIDTH - 6, // field width (in columns) short(wpul.row += 3), wpul.col, // Y/X offset in window // field text with Hotkey '^A' "[♦] ^Authorize daily cookie delivery", acAttr(acaFG_BLUE | acaBG_GREY), // color attributes (non-focus) floShift, // text formatting option ZERO, // insertion point (cursor offset) false, // user accessible (not read-only) false, // field outline enabled false, // field is visible (not hidden) true, // access lock enabled true, // initial binary state: 'set' NULLCHAR, // no hotkey (embedded in text) noGROUP // not a group member }, //* Field index 2: ftPB (Pushbutton) * { ftPB, // field type 1, // field height (in rows) 16, // field width (in columns) short(wpul.row += 2), // Y/X offset in window short(winWIDTH / 2 - 9), " ^Close Window ", // field text with Hotkey '^C' nonFocus, // color attributes floShift, // text formatting option ZERO, // insertion point (cursor offset) false, // user accessible (not read-only) false, // field outline enabled false, // field is visible (not hidden) true, // access lock enabled false, // initial binary state: 'reset' NULLCHAR, // no hotkey (embedded in text) noGROUP // not a group member } }, //* Optional skForm arguments * // 'fldIndex' index of field with initial focus (the Pushbutton) pbFIELD, // 'fldAttr' color attributes for control with focus focusAttr, // 'noisy' beep on unhandled keycode received true, // 'ioFlag' initial state of Insert/Overstrike flag true, // 'ioToggle' user access to Insert/Overstrike mode true, // 'ioCursor' enable cursor shape change for Insert/Overstrike true, // 'insCursor' cursor shape when Insert mode csBblock, // 'ovrCursor' cursor shape when Overstrike mode csBuline ) ;

The initialized skForm template is then passed as a parameter for the ACWin constructor. See ACWin constructor.

ACWin *winPtr = new ACWin ( winROW, winCOL, winHEIGHT, winWIDTH, ltSINGLE, acAttr(acaFGb_BROWN | acaBG_BLUE), acAttr(acaFG_RED | acaBG_GREY), " ACWin-class Window ", skfPtr // partially-initialized skForm object ) ; //* The setup data may now be safely deleted. (prevent memory leaks) * delete skfPtr ; skfPtr = NULL ; //* Open the window (make it visible) * winPtr->OpenWindow () ; //* Get User Input : Returns when Pushbutton control is selected,* //* either by "pressing it" (Enter/Space) or via hotkey (ALT+C). * short fieldIndex ; // on return contains index of exit field winPtr->EditForm ( fieldIndex, pbFIELD ) ; //* Close the window and delete the ACWin object.* winPtr->CloseWindow (); delete winPtr;

Note that the example above does not specify a callback function. The `'EditForm'` method returns when user the selects the Pushbutton control. In the more sophisticated examples, the callback function determines when the edit loop should be terminated.
Please see EstablishCallback for more information.

User Interaction - the skForm class and skField class

Initialization of an `skForm` object as a parameter for creating an `ACWin` window is shown above.

Accessing the form provides a user interface, via the fields defined by the `skForm` object.

After the ACWin object has been created, and the window has been opened, the EditForm method is called to give the user access to the field(s).

Example of calling the EditForm method. This is a copy of the code used in the Test_Cookie test method. See screenshot above.

      //* Define an ACWin object *
      ACWin *winPtr = new ACWin
            ( winROW, winCOL,
              winHEIGHT, winWIDTH,
              ltSINGLE,
              acAttr(acaFGb_BROWN | acaBG_BLUE),
              acAttr(acaFG_RED | acaBG_GREY),
              "  Window Formatted With \"skForm\" ",
              skfPtr  // partially-initialized skForm object
            ) ;

      //* Open the window (make it visible) *
      winPtr->OpenWindow () ;

      //* Get User Input : Returns when enter key is pressed.*
      short fieldIndex ;   // on return contains index of exit field
      winPtr->EditForm ( fldIndex, wcsENTER ) ;

      //* Get a pointer to final field configuration, *
      //* and retrive final text and button state.    *
      const skForm* skfp = winPtr->GetForm () ;
      gString finalText = skfp->fld[0].txt ; // contexts of textbox
      bool finalRadio = skfp->fld[1].state ; // state of radiobutton flag

      //* Close the window and delete the object.*
      winPtr->CloseWindow () ;
      delete winPtr ;

`--- --- --- --- ---`
The `skForm` object is fully integrated into the ACWin-class window; however, it is possible to make it visually appear that the fields defined within the `skForm` object are independent from the enclosing window.
If desired, the `skForm` object can be displayed in an “invisible” (borderless) window. In fact, many of the `skForm` tests included with the AnsiCmd library use a borderless window. See the `Test_SoftEcho` tests for examples of this usage.

### Dialog sub-Windows

#### What is a Dialog?

A “window”, (ACWin Class) is a sub-window within the terminal window. In turn, a “dialog”, as defined within this project, is a sub-window created within the `ACWin` parent window.

Dialog sub-windows are based on the `ACDlg` class. The `ACDlg` class is constructed as a simplified version of the `ACWin` class and shares many characteristics with `ACWin`.

The greatest difference is that all methods and data of the `ACDlg` class are “protected”. This means that it’s methods and data are not directly available at the application level. All access is through specialized methods of the `ACWin` parent class.

A dialog may be invoked to alert the user to some issue or to gather information from the user which it would be inconvenient for the parent window to request directly.

Dialogs are self-contained objects—that is, there are no post-launch methods for modification of the displayed data, and for the “quick” dialog, there is no callback method for monitoring user activity within the dialog.
This is in contrast to the ACWin-class window which may be updated at any time under application control.

Two types of dialogs are defined:
1) the “quick” dialog, and
2) the “full initialization” dialog.

A common type of information dialog is to alert the user that she has made an invalid request.

┌───────────────────────────────────────────────┐ │ You may not delete the boot partition, Dummy! │ │ │ │ CLOSE │ └───────────────────────────────────────────────┘

A common type of decision dialog is to ask the user a yes-or-no question.

┌───────────────────────────────────────────────┐ │ Are you sure you want to discard your changes │ │ to this document? │ │ DISCARD CANCEL │ └───────────────────────────────────────────────┘

It is of course possible to configure the dialog to ask more complex questions, such as:

┌───────────────────────────────────────────────┐ │ >>> When will you pay your taxes? <<< │ │ │ │ [◆] April 15th [ ] December 31st │ │ [ ] When Hell Freezes Over │ │ │ │ ASK_AGAIN_TOMORROW BUZZ_OFF! │ └───────────────────────────────────────────────┘

Please refer to the chapter describing Dialog testing see test D for functional dialog examples.

The user interface for a dialog is an `skForm` structure, the same type of structure used by the parent window; however, for Quick dialogs, the skForm structure is automatically generated. For the full-initialization dialog, the application designer may specify all user-interface configuration parameters.
Please see skForm Class for a discussion of configuring the user interface.

#### Technical Info About Dialog Objects

#### Size and position of the dialog:

Three factors determine the dimensions of the dialog:

1) the dimensions of the parent window 2) the space needed to display the static text and dialog controls 3) the position of the dialog (offset within the parent window)

Validating the Parameters: A significant amount of defensive programming is needed to ensure that the dialog does not extend into or beyond the borders of the parent window. Even so, the application programer could trash the display if determined to do so. (Your mother would be so proud...)

Dialog height, width, vertical offset and horizontal offset may be specified directly as invocation parameters, or may be dynamically calculated based upon the dimensions of the static text to be displayed.

1. A height of zero (0) indicates that the vertical dimension should be derived from the height of the static text plus top and bottom borders (plus one row which is assumed to be occupied by one or more controls).
   1. If the dimensions of the received text will not fit within the available space, the text will be automatically reformatted based on the specified dialog width and vertical/horizontal offsets (if specified) and the space available for the dialog.
2. If a VALID height is specified (ZERO < dlgHgt < maxHgt), then that value will anchor the dimensioning calculations.
   1. If specified height is out-of-range, it will be set to the available height.
3. A width of zero (0) indicates that the horizontal dimension should be derived from the width of the static text plus left and right borders (plus 2 columns for left/right indentation).
4. If a VALID width is specified (ZERO < dlgWid < maxWid), the static text will be automatically reformatted as necessary to fit the specified dimension.
5. The number, width and position of the controls are also factors in determining the height and width of the dialog.
   Note that it is impractical to programatically resize the dialog to accomodate the defined controls. The only check is whether the size and position of controls violate the borders of the dialog object. Please use care in specifying the dialog dimensions to contain the defined controls.
6. Yes, there is method to this madness. This design fascilitates automatic resizing of the dialog (if necessary) while maintaining the relative positions of the dialog controls.

   If neither positioning nor dimensioning adjustments will keep the dialog within the available space, then the static text will be truncated and if necessary, the controls will be discarded. This guarantees that the dialog will open successfully, although its appearance may come as a surprise.

#### Positioning of Dialog Controls:

1. Vertical offset: orig.row
   1. Positive values specify an offset from the top border of the dialog.
      Range: 1 through dialog height minus one
      A value of zero(0) is not valid, and will be converted to 1.
      Example: For a dialog of 12 rows, the range would be:
      `1 <= offset <= 10`
   2. Negative values specify an offset from the bottom border of the dialog.
      Range: -1 through negative dialog height minus one
      Example: For a dialog of 12 rows, the range would be:
      `-1 >= offset >= -10`
2. Horizontal offset: orig.col
   This value represents the offset in columns from the center of the dialog.
   1. A zero(0) indicates that the control is centered between the left and right borders.
   2. A positive value is a rightward offset from the center.
   3. A negative value is a leftward offset from the center.

          Example:
          For a dialog with a width of 31 columns, the range would be:
          -14 <= offset <= 14
            11111987654321012345678911111
            43210         -         01234

          For a dialog of 30 columns, the range would be:
          -14 <= offset <= 13
            1111198765432101234567891111
            43210         -         0123

#### Quick Dialog Configuration

bool QuickDialog ( const gString& gsMsg, bool query, const char* title = NULL,
`` short height = 0, short width = 0, short vOff = 0, short hOff = -1,
`` short timeout = 0, bool dbg = false );

Description of Parameters

1. Only two(2) parameters are required:
   1) the message to be displayed
   2) the type of user interaction: informational or query.
   All other parameters are optional.
2. A title for the dialog window may optionally be specified.
   If specified, the dialog title will be displayed in the top border of the dialog and horizontally centered. See example below.
3. The dimensions (height and width) of the dialog are based on the text rows and columns required to display the formatted message data
   unless
   text would extend beyond the available vertical or horizontal space or would extend beyond the dimensions specified by the optional dimension parameters, in which case, the text will be automatically reformatted.
   - Note that if the text must be reformatted, the flag enabling
   line breaks on hyphen-like characters is set.
   Please see acFormatParagraph for a discussion of automatic text formatting.

   The optional `'height'` and `'width'` may be used to override the formatting of the message text `'gsMsg'`.

4. Minimum Dimensions:
   - The dialog height must be at least four(4) rows: top border, text row, pushbutton row and bottom border.
   - The dialog width must be at least four(4) columns PLUS the width of the pushbutton(s). The width of the pushbuttons is determined by the the label text and whether there is one pushbutton (info dialog) or two (decision dialog). The default (English) label text is of the form:
     `"__OK__ _CANCEL_"`
     (16 columns for a decision dialog, or six columns for an info dialog)
5. Maximum Dimensions:
   - The width of the dialog plus the horizontal offset must not cause the dialog to extend into the border of the parent window.
   - The height of the dialog plus the vertical offset must not cause the dialog to extend into the border of the parent window.
6. Dialog offset from from origin (upper-left corner) of parent window.
   The `'vOff'` parameter is the vertical offset from the top of the parent window.
   By default, `'vOff'` is set to zero, which means that the dialog is positioned at the top row of the parent window.
   The special value of -1 indicates that the dialog is to be vertically centered in the parent window.

   The `'hOff'` parameter is the horizontal offset from the left edge of the parent window.
   By default, `'hOff'` is set to -1 indicating that the dialog is to be horizontally centered in the parent window.

   If the combined offset and dialog dimension would obscure the parent window’s border, the dialog offset and/or dialog dimensions will be adjusted so that the dialog will be displayed entirely within the parent window.

   - In no case will the parent window’s border be obscured.
   - In no case will the dialog be less than minimum size in either dimension.
   - In no case will the dialog fail to open.
7. A QuickDialog window has either one or two Pushbutton controls which are automatically generated by the call.

   The language for the text of the pushbutton controls is matched to the active "locale" (at least for the languages we know): English, Spanish, Chinese (simplified) and Vietnamese. The language defaults to English if the locale is not one of the recognized locales.
   Our ancient Greek and Sanskrit would probably be worthless
   here, as they are under most circumstances. :-)
   `` संस्कृतं भव्यं लिखितभाषा अस्ति

         const short LANGS = 4 ;
         const wchar_t *ymsg[LANGS] =  // default pushbutton messages
         {
            L"  ^OK  ",                // English
            L" ^.好的 ",               // Zhongwen (Hǎo de)
            L" De ^Acuerdo ",          // Español
            L" ^Tốt "                  // Tieng Viet
         } ;
         const wchar_t *nmsg[LANGS] =
         {
            L" ^CANCEL ",              // English
            L"  ^,取消  ",             // Zhongwen (Qǔxiāo)
            L" ^Cancelar ",            // Español
            L" ^Hủy Bỏ  "              // Tieng Viet
         } ;

   Support for additional languages may be added easily by extending these arrays; testing for the associated system locale, and setting the language index accordingly.

   A special case of the information dialog is the “automatic-timeout” dialog which has no user-interface controls. It is displayed for a specified amount of time, then closes automatically.

8. The dialog’s message text (gsMsg) is positioned vertically at the top interior row of the dialog, and is indented horizontally by one column from the left edge of the dialog interior.

#### Full-initialization Dialog Configuration

bool Dialog ( short dlgHgt, short dlgWid, skForm* formDef,
`` const char* sTxt = NULL, const char* tTxt = NULL,
`` short vOff = -1, short hOff = -1, LineType ltype = ltSINGLE,
`` acAttr bdrAttr = acaUSEDFLT, acAttr txtAttr = acaUSEDFLT,
`` short tvOff = 0, short thOff = 1,
`` CUPTR callbk = NULL, bool dbg = false );

Description of Parameters

Three(3) parameters are required: dlgHgt, dlgWid and formDef.
All other parameters are optional, and if not specified, receive default values as described above.

1. ‘dlgHgt’ Dialog Height
   An absolute height (number of display rows) may be specified by setting the ’dHgt’ parameter to a value >= the arbitrary minimum of four(4) rows and less than the height of the parent window MINUS ’vOff’.
   Automatic calculation of the dialog height is specified by setting the ’dHgt’ parameter to zero. – If the display text is pre-formatted, then the height of the text (plus padding) determines the height of the dialog. – "padding" includes the upper and lower borders plus one(1) internal row. – If the dialog height cannot be determined directly from the source text, or if the source text is taller than the available space, then the text may be automatically reformatted (and if necessary, truncated) to fit within the available space. The dialog height will then be the height of the reformatted text plus padding. – See also the note below about dialog controls.
2. ‘dlgWid’ Dialog Width
   An absolute width number of display columns) may be specified by setting the ’dlgWid’ parameter to a value >= the arbitrary minimum of eight(8) columns and no larger than the interior width of the parent window MINUS ’hOff’.
   Automatic calculation of the dialog width is specified by setting the ’dWid’ parameter to zero. – If the display text is pre-formatted, then the width of the text (plus padding) determines the width of the dialog. – "padding" includes the left and right borders plus two(2) internal columns. – If the dialog width cannot be determined directly from the source text, or if the source text is wider than the available space, then the text may be automatically reformatted to fit within the available space. The dialog width will then be the width of the reformatted text plus padding. – See also the note below about dialog controls.
3. ‘formDef’ Controls defined by an skForm object
   For a detailed discussion of the `skForm` class and its `skField`-class array, please see skForm Class.

   All control types defined by enum FldType are supported within a dialog window, with the following limitations:

   - Although the skForm class does not place an upper limit on the number of controls, the range of controls in a dialog is limited to: `1 <= count <= MAX_DLG_CTRLS`
   - At least one defined control must be a Pushbutton (ftPB)
     To exit the dialog, the user must select any defined Pushbutton control, either by placing focus on the control and pressing the Enter (or Space) key, or via the hotkey defined for the control.
     Optionally, exiting the dialog can be signalled from within the callback function if specified. In that case, dialog exit via Pushbutton is not mandatory.
   - Textbox control (ftTB) height is limited to one row.
     (Although Textbox controls are designed as multi-row controls, the decision was made to limit the height within dialog windows in order to greatly simplify the user-interface algorithm. We may revisit this decision in a later release.)
   - Menu controls (ftMB) are supported, but are limited to `'context'` menus (multi-item stand-alone menus) only; AND unlike context menus defined in the parent window, the menu will automatically be set as always visible.
     (Enforcing menu visibility in this way significantly enhances the efficiency of the display refresh routine. We may revisit this decision in a later release.)
   - Control outlines and external labels:
     Within a dialog, the data members that define outlines and labels are ‘protected’ members; that is, they may not be directly modified at the application level. Two specialized public methods of the skField class are available to configure these options:

           bool outlineConfig ( LineType lType, acAttr lAttr );
           bool labelConfig ( const char* labText, acAttr labAttr, bool center );

     Please see skField Public Methods for details.

   - Color attribute customization:
     Customization of text color attributes is often useful to enhance readability. For multi-row controls which contain fixed display text, color attributes for each individual display row may be specified. These are multi-row Menu controls (ftMB) and Scrollbox controls (ftSB) only.

     Within a dialog, the data member which defines per-item color attributes is ‘protected’, that is, it may not be directly modified at the application level. A specialized method of the `skField` class is available to configure this option: `bool colorConfig ( const acAttr* rowAttr, short rowCnt );`
     Please see skField Public Methods for details.

4. ‘sTxt’ Static text within the dialog
   Static text is any text written directly to the dialog interior and that is not within any dialog control object.

   The static text and the controls may occupy the same space without error. For instance the text may be above, below and on either side of a control. Just be sure that the text is not obscured by the control. To do this, the static text should contain only spaces (or newlines `'\n'`) under the area occupied by the control and the control label (if any).

   For example, the following static text data will be rendered in a dialog with two Pushbutton controls as shown.

   "This application cannot honor your request\n" "for cookie delivery. Use DoorDash, OR:\n" "\n" "You may actually need to leave your parents'\n" "basement to find them. Sorry about that...\n" " " ;
   ┌──────────────┤ ACWin-class Window ├──────────────┐ │ │ │ ┌──────────────┤ Nerd Alert! ├───────────────┐ │ │ │ This application cannot honor your request │ │ │ │ for cookie delivery. Use DoorDash, OR: │ │ │ │ Call_A_Therapist │ │ │ │ You may actually need to leave your parents' │ │ │ │ basement to find them. Sorry about that... │ │ │ │ │ │ │ │ Exit_Dialog │ │ │ └──────────────────────────────────────────────┘ │ │ ┌────────────────────────────────────┐ │ │ │ Me love cookies! Cookie! │ │ │ └────────────────────────────────────┘ │ │ │ │ [♦] Authorize daily cookie delivery │ │ │ │ Close Window │ │ │ └──────────────────────────────────────────────────┘
5. ‘tTxt’ Text of dialog title
   If specified, the dialog title will be displayed in the top border of the dialog and horizontally centered.

   For optimal display, it is recommended that the first and last characters of the title text be spaces, although this is not enforced.
   Example: `" Nerd Alert! "`.
   The text will be truncated if necessary to fit within the width of the dialog.

   The title text will be bracketed by delimiter characters corresponding to the border style and color specified for the dialog as shown in the example above.

6. ‘vOff’ Vertical offset of dialog in parent window
   This is the (0-based) offset in rows from top of parent window. This parameter is optional, and the default value is minus one (-1), indicating that the dialog is to be centered vertically in the parent window.
7. ‘hOff’ Horizontal offset of dialog in parent window
   This is the (0-based) offset in columns, from left edge of the parent window. This parameter is optional, and the default value is minus one (-1), indicating that the dialog is to be centered horizontally in the parent window.
8. ‘lType’ Border style
   This optional parameter specifies the border style as a member of `enum LineType`. By default, the border is drawn with a single-width line (ltSINGLE), but a dual-width line (ltDUAL) may be specified.
9. ‘bAttr’ Border color
   This optional parameter specifies the border color attributes.
   By default, the dialog inherits the border colors from the parent window; however, any foreground/background color attribute may be specified.
   See acAttr Enumerated Type, for more information on color attribute specification.
10. ‘tAttr’ Interior text color
    This optional parameter specifies the color attributes for the interior of the dialog (static text and dialog background).
    By default, the dialog inherits the interior color attributes from the parent window; however, any foreground/background color attribute may be specified.
    See acAttr Enumerated Type, for more information on color attribute specification.
11. ‘tvOff’ Vertical offfset for static text
    This optional parameter specifies the vertical offset at which to draw the dialog static text.
    By default, `'tvOff'` is set to zero, indicating that the static text is to be drawn starting on the top row of the dialog interior.
    A positive value indicates an additional vertical offset.
12. ‘thOff’ Horizontal offfset for static text
    This optional parameter specifies the horizontal offset at which to draw the dialog static text.
    By default, `'thOff'` is set to one(1), indicating that the static text is to be drawn starting at one column from the left edge of the dialog interior. A positive value indicates an additional horizontal offset.
13. ‘callbk’ Pointer to a non-member callback function.
    The full-initialization dialog supports an external callback function which can be used to monitor user activity within the dialog window.

    The callback functionality for a dialog is identical in most respects to a callback function for the the parent window.

    1. The callback is invoked using the same `CUPTR` template (macro), but instead of calling the EstablishCallback method, the `CUPTR` is passed as a parameter to the `Dialog` method.
       The callback function is based on the the following template:
       `typedef wchar_t (*CUPTR)( short ctrlIndex,` `wchar_t wkey, bool firstTime );`
    2. User interactions with the dialog’s controls can be monitored and directed just as they are in the parent window; however, window-specific methods of the `ACWin` class are not applicable to dialogs.
    3. For this reason, the `ACWin` class defines several dialog-specific methods for use by dialog callback functions:
       Dialog_GetText Dialog_SetText Dialog_GetItem Dialog_GetState Dialog_GetStateXOR Dialog_GetField Dialog_Write Dialog_Refresh

       Please see Dialog-Oriented Methods for details.

    4. Each of these methods is demonstrated in the AcEdit Demo App utility. The developer may find it instructive to study this method; therefore, the full callback source (version 0.0.04) is presented below: (see example callback).
14. ‘dbg’ (for debugging only) If this flag is set, it allows the dialog window to remain open after control is returned to the application. This is useful during testing for verification that the reported results correspond to the visual data.

Example Dialog Callback

The working code for this example is located in the `AcEditMenu.cpp` module, `sfaCallback` method. This callback monitors user specification of a filename for the save-file-as operation. The user may traverse the the filesystem tree to select the target directory and specify a filename for the data to be written to that directory.

    //***** Static, non-member function directing *****
    //***** callback to member method.            *****
    static wchar_t nonmember_dlgCallback ( short ctrlIndex, wchar_t wkey,
                                           bool firstTime )
    {
       return ( (aceditPtr->sfaCallback ( ctrlIndex, wkey, firstTime )) ) ;
    }  //* End nonmember_dlgCallback() *

    //***** AcEdit member method invoked as the *****
    //***** Callback method for saveFileAs()    *****
    wchar_t AcEdit::sfaCallback ( short ctrlIndex, wchar_t wkey,
                                  bool firstTime )
    {
       static const char* Warn_Dupe[uilENV] =
       { // Warn field width is 28 columns.
          "Error, file already exists.",   // English
          "错误，文件已存在。",               // Zhongwen
       } ;
       static const char* Warn_Name[uilENV] =
       {
          "Invalid filename characters.",  // English
          "错误，文件名中包含无效字符。",      // Zhongwen
       } ;
       static const char* Warn_Access[uilENV] =
       {
          "Unable to access target dir!",  // English
          "无法访问目标目录！",               // Zhongwen
       } ;
       static const char* noName[uilENV] =
       {
          "  Filename not specified.",     // English
          "       未指定文件名。",           // Zhongwen
       } ;
       static const char* Cancel_Msg[uilENV] =
       {
          "    Operation Cancelled.",      // English
          "      重命名操作已取消。",         // Zhongwen
       } ;

       // dialog row where filter message is displayed
       const short filterMsgRow = 10 ;
       // set if warning message is visible
       static bool warnMsg = false ;
       gString gs, gsCwd, gsName, gsList ;
       const skField* skfPtr = NULL ;// pointer to a control within the dialog
       acAttr* acArray = NULL ;   // pointer to array of Scrollbox attributes
       short itemCnt ;            // number of items in Scrollbox control
       short item ;               // Scrollbox item selected
       bool  vfat ;               // state of text filter Radiobutton
                                  // (set==VFAT compatible)

       //*------------*
       //* First call *
       //*------------*
       if ( firstTime )
       { /* Nothing to do at this time. */ }

       //* If a warning message is currently displayed, erase it. *
       if ( warnMsg )
       {
          gs.clear() ;
          this->win->Dialog_SetText( sfaWARN, gs ) ;
          warnMsg = false ;
       }

       //* Note that the hotkey for a field has been automagically  *
       //* converted to wcsENTER.                                   *
       if ( (wkey == wcsENTER) || (wkey == wcsSPACE) )
       {
          switch ( ctrlIndex )
          {
             case sfaSAVE:
                // retrieve filename data
                this->win->Dialog_GetText ( sfaTEXT, gsName ) ;
                if ( (gsName.gschars()) > 1 )
                {
                   //* Validate the filename characters.                *
                   //* Radiobutton state determines which filter to use.*
                   this->win->Dialog_GetState ( sfaVFAT, vfat ) ;
                   if ( !(this->isFilename ( gsName, false, vfat )) )
                   {
                      //* Warn of invalid filename character(s) *
                      gs = Warn_Name[this->lang] ;
                      this->win->Dialog_SetText( sfaWARN, gs ) ;
                      warnMsg = true ;  // remember that warning was posted
                      wkey = NULLCHAR ; // keycode handled
                   }
                   else
                   {
                      // Get Scrollbox text. Compare user-provided filename
                      // with each filename in the array of filenames in CWD.
                      this->win->Dialog_GetField ( sfaCWD, skfPtr ) ;
                      gsCwd = skfPtr->txt ;
                      // pointer to source data
                      const wchar_t* wsrc = gsCwd.gstr() ;
                      wchar_t wtrg[MAX_FNAME] ;      // filename target buffer
                      int   wchars = gsCwd.gschars(),// source characters
                            si = ZERO,
                            ti = ZERO ;              // target index
                      bool match = false ;           // set if duplicate name
                      //* Step over the "parent-dir" item at top of list.*
                      while ( (si < wchars) && (wsrc[si] != NEWLINE) )
                         ++si ;
                      ++si ;

                      //* Extract each filename *
                      for( ; si < wchars ; ++si )
                      {
                         while ( (wsrc[si] != NEWLINE) &&
                                 (wsrc[si] != NULLCHAR) )
                            wtrg[ti++] = wsrc[si++] ;
                         wtrg[ti] = NULLCHAR ; // terminate the string
                         ti = ZERO ;           // reset target index
                         gs = wtrg ;           // load raw data item
                         gs.shiftChars( -3 ) ; // discard item prefix
                         gs.strip() ; // strip leading/trailing whitespace
                         //* Compare with user's filename *
                         if ( (gsName.compare( gs )) == ZERO )
                         { match = true ; break ; }
                      }

                      //* If user's data matches an existing    *
                      //* filename in CWD, warn of duplication. *
                      if ( match )
                      {
                         gs = Warn_Dupe[this->lang] ;
                         this->win->Dialog_SetText( sfaWARN, gs ) ;
                         warnMsg = true ;  // remember that warning was posted
                         wkey = NULLCHAR ; // keycode handled
                      }

                      //* Else, a valid, non-duplicate filename    *
                      //* specified. Signal that dialog s/b closed.*
                      //* Filename is in Textbox control.          *
                      else
                         wkey = wcsCTL_4 ;
                   }
                }
                else     // empty filename string
                {
                   gs = noName[this->lang] ;
                   this->win->Dialog_SetText( sfaWARN, gs ) ;
                   this->win->nsleep ( 20 ) ;
                   wkey = wcsCTL_4 ;
                }
                break ;

             case sfaCANCEL:                  // Cancel pushbutton
                gs = Cancel_Msg[this->lang] ;
                this->win->Dialog_SetText( sfaWARN, gs ) ;
                this->win->nsleep ( 16 ) ;
                wkey = wcsCTL_4 ;
                break ;

             case sfaCWD:         // Scrollbox display of CWD files
                //* Get a copy of "selected" item *
                if ( (this->win->Dialog_GetItem ( sfaCWD, gs, item )) )
                {
                   // isolate indicator character
                   wchar_t indyChar = *gs.gstr() ;
                   gsName = &gs.gstr()[2] ;    // item text without prefix

                   //* Move to parent directory or subdirectory *
                   if ( (indyChar == PCHAR) || (indyChar == DCHAR) )
                   {
                      //* Get filespec of CWD *
                      if ( !(this->getCWD ( gsCwd )) ) { gsCwd = L"." ; }
                      if ( indyChar == PCHAR )   // moving to parent directory
                      {
                         gs = gsCwd ;
                         this->ExtractPathname ( gsCwd, gs ) ;
                      }
                      else                       // moving to subdirectory
                         gsCwd.append( "/%S", gsName.gstr() ) ;

                      if ( (this->setCWD ( gsCwd )) )
                      {
                         //* Scan new CWD and format the entries.  *
                         // Create an array of color attributes to *
                         //* match the records                     *
                         this->win->Dialog_GetField ( sfaCWD, skfPtr ) ;
                         itemCnt = this->readCwd ( gsList, acArray,
                                                   skfPtr->wid ) ;
                         // Update text data, and array of color attributes.
                         // Programmer's Note: Refresh is not performed after
                         // text update, but is performed only after attribute
                         // update.
                         this->win->Dialog_SetText ( ctrlIndex, gsList,
                                                     acaUSEDFLT, false ) ;
                         this->win->Dialog_SetAttr ( ctrlIndex, acArray,
                                                     itemCnt ) ;

                         // release the dynamic allocation
                         if ( acArray != NULL )
                         { delete[] acArray ; acArray = NULL ; }
                         //* Signal caller that operation is compete.*
                         wkey = NULLCHAR ;
                      }
                      else
                      { //* Malformed filespec OR user lacks read access *
                         gs = Warn_Access[this->lang] ;
                         this->win->Dialog_SetText( sfaWARN, gs ) ;
                         warnMsg = true ;  // remember that warning was posted
                         wkey = NULLCHAR ; // keycode handled
                      }
                   }
                   else                    // non-directory filename
                      this->win->Dialog_SetText ( sfaTEXT, gsName ) ;
                }
                // else(call is unlikely to fail)
                break ;

             case sfaVFAT:
                //* State of Radiobutton is being toggled.          *
                //* Match the filter message with Radiobutton state *
                //* NOTE: The state flag has not yet been updated   *
                //* at this point, so the sense is reversed.        *
                this->win->Dialog_GetState ( sfaVFAT, vfat ) ;
                gs = sfaFilterMsg[this->lang][(vfat ? 0 : 1)] ;
                this->win->Dialog_Write ( gs.gstr(), filterMsgRow, 0, true ) ;
                break ;
          } ;
       }
       return wkey ;

    }  //* End sfaCallback() *

## Development and Testing

The methods described in this chapter test all major functionality of the AnsiCmd class and the AnsiCmd library as a whole.

These methods are not required for application development, and are therefore under a conditional compile directive so they can be disabled in a production build. The `EarthPoints` test application includes these tests in order to demonstrate all AnsiCmd functionality.
Please see Build Options for more information on conditional compilation options.

Each test may be invoked through a command line option. Please see Invoking - AnsiCmd Tests for a list of available options.

The following is a list of the primary test methods found in the `AnsiCmdTest.cpp` source file.
Each method header contains detailed information about that test, and exhaustive comments are sprinkled throughout the test code to indicate what is being tested, how it is being tested, and why it is being tested. These comments should answer most questions about the AnsiCmd library, and at the very least, they offer an example of how code should be commented.

> Editorial: Many students misunderstand the purpose of comments within the source code. Comments DO NOT explain what your code does. Rather, comments describe what your code is intended to do. That is why comments are (nearly) always written before the code itself. Comments explain to you what needs to be done, so that after the code is written and fully functional, you can compare the code with the comments to see if they agree; and if not, adjust the one that is incomplete. — Software Sam

Many of these methods also invoke support methods for user interface duties or for various often-used calculations.

Note also that many of these test methods write diagnostic data to the debugging log: `"dbg.log"` created in the source code directory.

- void ansiTest_Menu ( dbgArgs& args );
  See Invoking - AnsiCmd Tests

  This method is called from the application layer by the public method:
  ansiTest which determines whether the conditionally-compiled test code is present in the library.

  `ansiTest_Menu` is the entry point for invoking the individual tests.
  The command-line arguments are validated and formatted as call parameters, and the appropriate test (or test sub-menu) is invoked.

- void Test_4Bit ( void );
  See test C (f) invocation option.
- void Test_Bg ( void );
  See test C (b) invocation option.
- void Test_8bitColor ( void );
  See test C (t) invocation option.
- void Test_RGB ( wchar_t rgbTest );
  See test C (r) invocation option.
- void Test_Greyscale ( void );
  See test C (g) invocation option.
- void Test_AixFgBg ( void );
  See test C (a) invocation option.
- void Test_acaExpand ( void );
  See test C (d) invocation option.
- void Test_acaExpandSwap ( void );
  See test C (s) invocation option.
- void Test_AltFonts ( aeSeq fg );
  See test F invocation option.
- void Test_CursorPos ( aeSeq fg );
  See test P invocation option.
- void Test_Erasures ( aeSeq fg );
  See test E invocation option.
- void Test_AsciiCodes ( aeSeq fg );
  See test A invocation option.
- void Test_Ideogram ( aeSeq fg );
  See test `I` invocation option.
- void Test_UnbufferedInput ( aeSeq fg );
  See test T (i) invocation option.
- void Test_TermFlags ( aeSeq fg );
  See test T (t) invocation option.
- void Test_ModFlags ( aeSeq fg );
  See test T (m) invocation option.
- void Test_NonBlock ( aeSeq fg );
  See test T (b) invocation option.
- void Test_RawInput ( aeSeq fg );
  See test T (r) invocation option.
- void Test_OutputStream ( aeSeq fg );
  See test T (o) invocation option.
- void Test_SoftEcho ( wchar_t eOpt, aeSeq fg );
  See test T (e) invocation option.
- void Test_Write ( aeSeq fg );
  See test T (f) invocation option.
- void Test_Window ( aeSeq fg );
  See test W (w) invocation option.
- void Test_Form ( aeSeq fg );
  See test W (f) invocation option.
- void Test_Wrap ( aeSeq fg );
  See test W (t) invocation option.
- void Test_WinDefault ( aeSeq fg );
  See test W (d) invocation option.
- void Test_Fifo ( aeSeq fg );
  See test W (s) invocation option.
- void Test_Menu ( aeSeq fg );
  See test W (m) invocation option.
- void Test_Hilite ( aeSeq fg );
  See test W (h) invocation option.
- void Test_Cookie ( aeSeq fg );
  See test W (e) invocation option.
- void Test_Box ( aeSeq fg );
  See test W (b) invocation option.
- void Test_Line ( aeSeq fg );
  See test W (l) invocation option.
- void Test_Clipboard_API ( aeSeq fg );
  See test W (x a) invocation option.
- void Test_Clipboard_Win ( aeSeq fg );
  See test W (x w) invocation option.
- void Test_Tfman ( aeSeq fg );
  See test W (x t) invocation option.
- void Test_LaunchExt ( wchar_t opt, aeSeq fg );
  See test W (x) invocation option.
- void Test_Dialog ( wchar_t tst );
  See test D invocation option.
- void Test_Sandbox ( wchar_t parmA, wchar_t parmB );
  See test S invocation option.

  This method is provided so that the application developer can write experimental code and test it before moving it to the application. Because this is an AnsiCmd-class member method, the test code has access to all the internal functionality of the library.

  The Test_Sandbox method is presented here in its entirety.
  This is the best ride in the amusement park. Have fun!!

      void AnsiCmd::Test_Sandbox ( wchar_t parmA, wchar_t parmB )
      {
         gString gsOut( "Welcome to the Sandbox!\n" ) ;
         this->ttyWrite ( gsOut ) ;

         //* Create Tests Here... *

         //* --- End of Sandbox Area - Do Not Modify This Line --- **
         this->acSetCursor ( aesCUR_ABSPOS, (this->termRows - 1), 1 ) ;

      }  //* End Test_Sandbox() *

## Building from Source

### Tools

The `AnsiCmd` library and the `EarthPoints` test application are written in C++ and are built with the GNU C++ compiler and linker. No additional link libraries or third-party tools are needed.

- GCC (G++) version 8 and above, (support for C++17 or greater).

### Compiling

The AnsiCmd library is compiled using the GNU/G++ compiler which is invoked through the ’gmake’ (’make’) utility. The compile and linking instructions are contained in the file named ’Makefile’.

Examples: gmake all gmake clean gmake gmake buildlib # build the AnsiCmd library only

### Build Options

Conditional compilation directives control the build options, both for the `AnsiCmd class` library and the `EarthPoints` application.

Four major conditional-compilation directives control most, if not all the sub-directives. The first is the `INCLUDE_API` directive which enables or disables inclusion of the high-level constructs related to the creation of window objects and user-interface controls.
The second is the `DEBUG_ANSICMD_TEST` directive which enables the test suite located in `AnsiCmdTest.cpp`.
The other two directives manage the debugging code embedded within the `AnsiCmd` library methods. These embedded tests are used to verify algorithm design and functionality for the library as a whole.
These are the `DEBUG_ANSICMD` and `DEBUG_LOG` directives. All other debugging code is designed to be subordinate to these. If these two are enabled, debugging code (other than the test suite) is potentially enabled. If these two directives are disabled, then all debugging code is disabled.

Because the `AnsiCmd class` as well as the `EarthPoints` application are primarily experimental in design, a large number of conditional-compilation directives are defined to assist in development and debugging of the code. The following is a list of the directives which persist beyond the immediate needs of the programming day.

Please see Development and Testing for more information.

#### AnsiCmd Class Directives

1. DEBUG_ANSICMD
   This directive is defined in `AnsiCmd.hpp`, and is the master directive for all debugging code within the AnsiCmd class.
   `#define DEBUG_ANSICMD (1)` debugging code is compiled.
   `#define DEBUG_ANSICMD (0)` debugging code is excluded.

   All other debugging directives in the AnsiCmd source code are nested within this directive. Setting the definition to zero SHOULD disable all debugging code within the AnsiCmd class, including all the testing methods (grouped under `DEBUG_ANSICMD_TEST`).

2. DEBUG_ANSICMD_TEST
   This directive is defined in `AnsiCmd.hpp`, and controls whether the test suite is included in the library build. This directive should be enabled when linking with the `EarthPoints` application, so that all tests and diagnostic code will be available. The test suite is optional when linking the library with the other demo apps. If present, it will not affect the functionality of those apps; however, disabling the test suite will reduce the size of the compiled library by approximately 500Kb.
3. DEBUG_LOG
   This directive is defined in `AnsiCmd.hpp`, and controls whether a log file will be created to contain miscellaneous debugging information.

   If enabled (1), the file will be created in the source code directory with the name: “`dbg.log`”. If a file of that name already exists, it will be overwritten. The file is closed before the program exits.

   The log file contains detailed data on the program execution sequence and the results of specific operations. For instance it can report configuration data or interim results of binary operations such as:
   `decode( fgIndex:04 hue:00 shade:00 r:0 g:0 b:0 )`
   `( bgIndex:02 hue:00 shade:00 r:0 g:0 b:0 )`
   `---r brfc --mods--- --bgnd--- --fgnd---`
   `b0000-0000-0000-0111-0000-0010-0000-0100`

4. Default Configuration
   As distributed, the package should have `INCLUDE_API` directive, as well as the `DEBUG_ANSICMD`, `DEBUG_LOG` and `DEBUG_ANSICMD_TEST` directives enabled, which in turn enables the tests of library functionality in the `EarthPoints` application.
   To verify this, after unpacking the archive, use the `'grep'` utility to display the debugging directives:
   `grep -n '#define DEBUG_' *.[hc]pp | grep '[(]1[)]'`
   `` (This is why OCD is not really a “disorder” at all. :-)

   As a convenience, a small Perl utility, `'report.pl'` is included in the distribution archive. This utility will report the current state of the conditional-compile directives described above.
   This utility is also invoked by the Makefile when performing a clean build:
   `gmake all`

5. Embedded Debugging Directives
   These directives may be enabled temporarily to verify intermediate states of data and execution flow for a particular section of the code. These directives typically affect only one method, or a small group of related methods. These directives may affect overall library functionality and so should be disabled when not being directly monitored.

   - DEBUG_CURPOS
   - DEBUG_SEQUENCE
     These directives are defined within the `acGetCursor` method, in the `AnsiCmd.cpp` module.

     The test code uses the debugging log file (see above) to report the transmission of the `ANSI` escape sequence commands and the capture of the response.

     The `ANSI` escape sequence for get-cursor-position is the most complex of the escape sequences defined by the standard. This is because after issuing the command, the response is returned to the application as an escape sequence via `'stdin'`. This opens the possibility of trashing the display.

     For this reason, special attention is given to the algorithm used to capture the incomming data. — It works, but keep an eye on it.

   - DEBUG_SOFTKEY
     This directive is defined within the `specialkeyDecode` method, in the `AnsiCmd.cpp` module.

     The test code uses the debugging log file (see above) to report the captured byte sequences, convert them to standard keycodes and determine whether the keycode belongs to the group of “special” i.e. cursor-control keys.

   - DEBUG_FI
     Located in the `acFlushIn` method in `AnsiCmd.cpp` to verify terminal configuration flags for flusing the input stream.
   - DEBUG_BSR
     Located in the `breaksignalReceived` method in `AnsiCmd.cpp`, this enables monitoring of the break signal (`Ctrl+C key`) capture and processing.
   - DEBUG_SSR
     Located in the `suspendsignalReceived` method in `AnsiCmd.cpp`, this enables monitoring of the suspend signal (`Ctrl+Z key`) capture and processing.
   - DEBUG_skForm
     This directive is defined within the `init_skForm` method, in the `AnsiCmdWin.cpp` module.

     The test code uses the debugging log file (see above) to report the contents of the the skForm object’s data members.

   - DEBUG_SHIFT_TEXT
     This directive is defined within the `shiftFieldText` method, in the `AnsiCmdWin.cpp` module. This method implements block-shift of text within the target field.
   - DEBUG_skpInterRow
   - DEBUG_skpDeleteChar
     These directives report intermediate processing of the “special” keycodes.
   - DEBUG_normalkeyProc
     This directive reports intermediate processing of the “normal” (graphing) keycodes.
   - DEBUG_wpos2tpos
     This directive is located in the `wpos2tpos` method which converts window-relative coordinates to terminal-relative coordinates. (currently unused)
   - DEBUG_SA
     This directive is located in the `acSetAttributes` method and validates decoding of color-attribute bitfields and transmitting the corresponding `ANSI` escape sequences to set the attributes.
   - DEBUG_TERMSETUP
   - DEBUG_TS_PAUSE
     These directives are defined in the `ansicmdSetup` method which parses command-line arguments related to terminal configuration.
   - DEBUG_EOTOFF
   - DEBUG_ipOffset
     These directives are defined within the `eotOffset` and `ipOffset` methods, respectively, and report the interim results when calculating the cursor position within a field under edit.
   - DEBUG_RGB_WEB
     This directive is defined within the `trgbStepWeb` method, in the `AnsiCmdTest.cpp` module.

     This method displays the supported “web-safe” colors by setting the background color attribute. The directive is used to temporarily render the web-safe colors by setting the foreground instead of the background.

   - DEBUG_TestWindow
     This directive is defined within the `Test_Window` method, in the `AnsiCmdTest.cpp` module. (currently unused)
   - DEBUG_TEXTBOX
     This directive is defined within the `ddzCallback` method, in the `AnsiCmdTest.cpp` module. This is the callback method which monitors real-time user interaction within an ACDlg class window—specifically for testing scrolling of text data within a field.
   - DEBUG_TFBDR
     This directive is defined within the `Test_Form` method, in the `AnsiCmdTest.cpp` module. Optionally test field outline for Radiobutton controls.(currently unused)
   - DEBUG_ACWCB
     This directive is defined at the top of the `AnsiCmdApi.cpp` module. Report the intermediate results of interaction with the system clipboard.
   - DEBUG_decode
   - DEBUG_update
   - DEBUG_modify
   - DEBUG_compose
   - DEBUG_swap
   - DEBUG_buildRgb
   - DEBUG_build8bit
     This group of directives manages debugging information for the acaExpand class which is used to encode, decode and apply color-attribute data.
6. INCLUDE_API
   This directive controls compilation of methods and data for the high-level functionality of the `AnsiCmd` library.

   The `API` methods are used by the `EarthPoints` application for optional output of the coordinate reports to an `ACWin-class` object; however, `EarthPoints` will build successfully even when this directive is disabled (set to zero). But in this case, the windowed output option will not be available.

   The `API` methods are required by the `AcEdit` application which integrates both `ACWin-class` and `ACDlg-class` objects into the application design.

   The `API` methods are not used in the CsvView application which is implemented using only the low-level `AnsiCmd` methods.

   Therefore, when building the `AnsiCmd` library, keep in mind the application to which the library will be linked, and set or reset this directive as needed.

   - INCLUDE_WAYLANDCB
     This is a sub-directive under control of the `INCLUDE_API` directive and is defined in `AnsiCmd.hpp`.
     The `INCLUDE_API` directive enables the local clipboard which is available only within the application itself.
     When `INCLUDE_WAYLANDCB` is enabled, access to the Wayland (system) clipboard becomes available through the WaylandCB class, assuming the connection with the system can be established.
     The system clipboard connection requires installation of the Linux utility: `'wl-clipboard'`.
     `sudo dnf install 'wl-clipboard'`
     `sudo apt-get install 'wl-clipboard'`
     For details, please see the documentation included as part of the standalone `WaylandCB` package.
     (See By the Same Author.)
     Please see AnsiCmd Clipboard Access which describes the clipboard interaction methods.

> #### ACWin-class and ACDlg-class Directives

> Within the `API` group of methods, some additional directives are defined. All debugging directives in this group are contained within the global `DEBUG_ANSICMD` directive, so disabling this global debugging directive will also disable all `API` debugging code.

> - DEBUG_WDUMP — enable write of config data to log
> - DEBUG_FDUMP — enable write of field data members to log
> - DEBUG_MDUMP — enable write of field MRParse data to log
> - DEBUG_FIFO — enable write of BlockFifo data to log
> - DEBUG_PHOTO — enable screenshot (for documentation)
>   These directives are defined within the `AnsiCmdWin.hpp` module and control output of various groups of `ACWin` configuration information to the debugging log file.
> - DEBUG_PHOTO2 — located in the `Screenshot` method. Supports screenshot capture.
> - DEBUG_KPUSH — enable support methods of KeycodePush group
> - DEBUG_GFD — request copy of skField data structure
> - DEBUG_PFT — parsing algorithm for field text
> - DEBUG_SKP — special-key processing for ’flowing’ text
> - DEBUG_skpST — special-key processing for ’shifted’ text
> - DEBUG_skpInterRow — calculate inter-row offset
> - DEBUG_DELCHAR — algorithm for deleting a character
> - DEBUG_NKP — filter and process ’normal’ keycodes
>   These directives are defined within the `AnsiCmdWin.cpp` module and are related to identification and processing of “special” keycodes received from the user.
> - DEBUG_CBGET_FLOW — paste to control with ’flowing’ text
> - DEBUG_CBGET_SHFT — paste to control with ’shifting’ text
> - DEBUG_CBGET_OVER — overflow of field during paste
>   These directives are defined within the `AnsiCmdSkf.cpp` module and are used to validate the functionality of the local clipboard “paste” operation for Textbox fields.
> - DEBUG_skForm — range-check top-level skForm members
> - DEBUG_IMF — verify array of skField objects
> - DEBUG_IMM — validate data for Menubox controls
> - DEBUG_ISB — validate data for Scrollbox controls
>   These directives are defined within the `AnsiCmdSkf.cpp` module and validate initialization of the `skForm` and `skField` objects.
> - DEBUG_CCFG —
> - DEBUG_SB —
> - DEBUG_MB — These directives are defined within the `AnsiCmdSkf.cpp` module and validate per-row color attribute configuration for Menu and Scrollbox controls.
> - DEBUG_SA — color attribute bitfield initialization
> - DEBUG_TERMSETUP — display terminal setup options
> - DEBUG_TS_PAUSE — after report, pause for user response
>   These directives are defined within the `AnsiCmdApi.cpp` module and validate terminal window color-attribute initialization and parsing of command-line parameters for terminal configuration, respectively.
> - DEBUG_QDialog
>   This directive is defined within the `AnsiCmdDlg.cpp` module and validates configuration of the QuickDialog invocation.
> - DEBUG_Dialog
> - DEBUG_ADJ
>   These directives are defined within the `AnsiCmdDlg.cpp` module and validate configuration of the full-initialization dialog. Dialog invocation.
> - DEBUG_ED_CLIP
>   This directive is defined within the `AnsiCmdDlg.cpp` module and monitors user interaction within the `editDialog` method.

#### EarthPoints Application Directives

1. DEBUG_EPNTS
   This directive is defined in the `EarthPoints.hpp` module.
   It controls debugging code specifically designed to test parsing of GPS data and calculation of arc distances.
2. DEBUG_PARSE
   This directive is defined in the `EarthPoints.hpp` module.
   It controls debugging code for parsing the user’s command line input.
3. DEBUG_PVALUE
   This directive is defined in the `EarthPoints.hpp` module.
   It controls debugging code for parsing GPS values in degrees and radians.
4. DEBUG_VERBOSE
   This directive is defined in the `EarthPoints.hpp` module.
   As the name implies, it enables additional debugging information for verification of data operations.
5. DEBUG_GCLA
   This directive is defined within the `GetCommandLineArgs` method, in the `EpParse.cpp` module.

   The results of parsing the command-line arguments are written to the terminal window, and the application then waits for the user to press the ENTER key before continuing program execution.

### Testing the Build

To test the build, invoke with a request for the EarthPoints version number. You should get something similar to the following:

./epts --version EarthPoints (epts) v:0.0.07 Copyright(c) 2022-2026 The Software Samurai ======================================================================== License GPLv3+: GNU GPL version 3 <http://gnu.org/licenses/gpl.html> This is free software: you are free to modify and/or redistribute it under the terms set out in the license. There is NO WARRANTY, to the extent permitted by law.

#### Installing the Documentation

Documentation for the `AnsiCmd` library is provided in both Texinfo (info) format and HTML format.

To view the HTML-format documentation, navigate to:
`AnsiCmd/Texinfo`
then load the `'ansicmd.html'` document into your favorite browser. Note that the `'infodoc-styles.css'` CSS style definition file must be in the same directory as the HTML document.

To view the Texinfo (info) documentation, navigate to:
`AnsiCmd/Texinfo`
then view the documentation using the following command:
`info -f ansicmd.info`

Follow these steps to install the `AnsiCmd` documentation into the ‘info’ database.

1. Note that installing the documentation is not necessary, but is recommended. Not only is it convenient to have the documentation always available, but it is a useful skill for when you begin installing documentation for your own applications!
2. Adding an ‘info’ document to the info-reader database (or removing a document from the database) is easy, but it does require ‘SUPERUSER’ (‘root’) user privilege. If this makes you nervous, please make a backup copy of the ‘dir’ (info directory) file before modifying it.
3. Open a terminal window.
4. Navigate to the directory which contains the `'ansicmd.info'` documentation.
   Example: cd ~/MySoftware/AnsiCmd/Texinfo (substitute your actual installation path)
5. Locate the master Info system directory file: ’dir’.
   For local users, this is typically:
   `/usr/local/share/info/dir`

   For global system users, this is typically:
   `/usr/share/info/dir`

6. Copy the document to the directory where you found the info ’dir’ file.
   Example: sudo cp −−preserve=timestamps ansicmd.info /usr/local/share/info/. (substitute the actual path to the directory containing the 'dir' file) Enter your password when prompted.
7. Navigate to the Info target directory.
   `cd /usr/local/share/info`
8. Verify that the document was copied correctly.
   `ls -l ansicmd.info`
9. Add the menu entry.
   sudo install-info −−dir-file=dir −−info-file=ansicmd.info −−name='AnsiCmd-class Library' −−debug Note that this is a single command, typed all on one line even though it may look strange as printed here. Enter your password when prompted.
10. Verify the install.
    Type the following command: info

    This will open the top-level menu of the Info system.
    Verify that your new entry is beautifully displayed and that the new Info document is accessible:

    First, press the forward-slash key `'/'` (search)
    Then, type: AnsiCmd-class Library`` (and press ENTER)
    The highlight should now be on the menu entry.
    Press ENTER (RET) key again, and verify that the main page of the AnsiCmd documentation is displayed.
    Then, exit the Info system: `'q'` (quit).

11. If the menu item is not present OR if the new Info document is not accessible, then try the installation again.

    If you want to remove the menu entry, use the command:

    sudo install-info −−dir-file=dir −−info-file=ansicmd.info −−name='AnsiCmd-class Library' −−remove −−debug Again, this is a single command, typed all on one line. Enter your password when prompted.

## gString Text Tool

’gString’ is a small, fast and flexible way to seamlessly convert, format and analyze both UTF-8 and wchar_t (’wide’) text.

### Introduction to gString

#### Introduction to a Wider World

Modern applications must be designed for a worldwide audience, and for this reason, the application designer must plan for multi-language support.

Fortunately, the Universal Character Set standard ISO/IEC 10646 and UTF-8, the most popular and flexible method of character-encoding smoothly provide all the character sets, alphabets and special characters which are currently in general use.

Unfortunately, the C and C++ languages offer only minimal support for internationalization. std::string and std::wstring are nothing more than a cruel joke to a serious application designer. The GTK+ toolkit’s Glib::ustring class is an excellent internationalization tool, but it requires installation of the GTK+ toolkit’s ’glib’ and ’glibmm’ libraries.
For more information on Glib::ustring, see: https://developer.gnome.org/

’gString’ falls halfway between the full feature set of Glib::ustring and the meaningless garbage that is std::string. ’gString’ consists of one C++ header file and one C++ source code module. ’gString’ is integrated into the NcDialog API library, but may also be compiled independently as a small (16Kb) link library or the source may be embedded directly into your application.

#### Preparing to Support Multiple Languages

Here are the basic ideas you will need to understand in order for your application to smoothly support multiple languages.

1. ASCII (American Standard Code for Information Interchange) is only the very first step in character encoding. It is an ancient and venerable encoding, but supports only the 95 printable characters of the basic Latin alphabet.
   If you think you can say "你是在欺骗自己！" in ASCII, you’re just deluding yourself!
2. NEVER assume that one character can be represented with one byte.
3. NEVER assume that one character is one display column in width.
4. The idea that text flows from left-to-right, may only be PROVISIONALLY assumed, because again: "!איר זענט נאָר דילודינג זיך" you’re just deluding yourself.
5. NEVER assume that "everyone reads English, so why bother?". Native speakers of Spanish, French, Chinese, the various flavors of Arabic and others (i.e. your potential customers) all have a significant impact on the daily events of our planet, so include them when planning for your next killer app.

See also a discussion of multiple-language support in the NcDialog API.

### gString Public Methods

What follows is a list of all public methods of the gString class.
Methods are arranged in functional groups.

gString Method Name | Chapter Reference
--- | ---
gString [constructor] | see gString Instantiation
~gString [destructor] |
operator= | see Assignment Operators
compose | see Formatted Assignments
formatInt | see Integer Formatting
gstr | see Data Access
ustr |
copy | see Copying Data
operator<< |
substr |
append | see Modifying Existing Data
insert |
limitChars |
limitCols |
shiftChars |
shiftCols |
padCols |
strip |
erase |
replace |
loadChars |
textReverse |
formatParagraph |
compare | see Comparisons
compcoll |
operator== |
operator!= |
find |
findlast |
after |
findr |
findx |
scan |
gscanf | see Extract Formatted Data
gschars | see Statistical Info
gscols |
utfbytes |
isASCII |
clear | see gString Miscellaneous
wAlloc |
uAlloc |
freeSpace |
reAlloc |
Get_gString_Version |
dumpGstring |
dbMsg |

### gString Instantiation

The following are the ’constructors’ for the gString class.

For those new to C++, a constructor creates an ’instance’ of the class. An instance is a particular, named object, and can be thought of as a complex variable.

- gString ( void ) ;

        Input  :
           none
        Returns:
           nothing

  Constructor: Initialize members to default values (NULL string).

- gString ( int32_t charAlloc );

        Input  :
           charAlloc : storage capacity
              interpreted as the maximum number of wchar_t (32-bit) characters
              for the storage buffer.
              Range: gsALLOCMIN <= charAlloc <= gsALLOCMAX
              -- The minimum allocation of gsALLOCDMIN will result in the
                 same storage capacity at the default constructor.
              -- The maximum allocation of gsALLOCMAX is 1000 times the
                 minimum allocation.
              The specified value is normalized by rounding upward to the
              nearest multiple of gsALLOCMIN.

        Returns: nothing

  Constructor: Initialize members to default values with empty string.

  This constructor is used to specify the initial storage capacity for the gString object. This may be useful if it is known that the data the object will hold will be larger than the default storage capacity.
  For more information, see Dynamic Memory Allocation.

- gString ( const char* usrc, int32_t charLimit = -1 ) ;

        Input  :
           usrc     : pointer to a UTF-8-encoded, null-terminated string
           charLimit: (optional, -1 by default) maximum number of source
                      characters to be stored (not including nullchar).
                      This is the number of characters (NOT the number of
                      UTF-8 bytes).
                      If not specified, then all source data will be stored
                      up to the maximum storage limit.

        Returns: nothing

  Constructor: Convert specified UTF-8-encoded source to gString.

- gString ( const wchar_t* wsrc, int32_t charLimit = -1 ) ;

        Input  :
           wsrc      : pointer to a wchar_t-encoded, null-terminated string
           charLimit : (optional, -1 by default)
                       maximum number of characters from source array to
                       convert

        Returns: nothing

  Constructor: Convert specified wchar_t (’wide’) source to gString.

- gString ( short iVal, short fWidth, bool lJust = false,
  `` bool sign = false, bool kibi = false, fiUnits units = fiK ) ;
- gString ( unsigned short iVal, short fWidth, bool lJust = false,
  `` bool sign = false, bool kibi = false, fiUnits units = fiK ) ;
- gString ( int iVal, short fWidth, bool lJust = false,
  `` bool sign = false, bool kibi = false, fiUnits units = fiK ) ;
- gString ( unsigned int iVal, short fWidth, bool lJust = false,
  `` bool sign = false, bool kibi = false, fiUnits units = fiK ) ;
- gString ( long int iVal, short fWidth, bool lJust = false,
  `` bool sign = false, bool kibi = false, fiUnits units = fiK ) ;
- gString ( unsigned long int iVal, short fWidth, bool lJust = false,
  `` bool sign = false, bool kibi = false, fiUnits units = fiK ) ;
- gString ( long long int iVal, short fWidth, bool lJust = false,
  `` bool sign = false, bool kibi = false, fiUnits units = fiK ) ;
- gString ( unsigned long long int iVal, short fWidth, bool lJust = false,
  `` bool sign = false, bool kibi = false, fiUnits units = fiK ) ;

        Input  :
           iVal  : value to be converted
                   Supported value range: plus/minus 9.999999999999 terabytes
           fWidth: field width (number of display columns)
                   range: 1 to FI_MAX_FIELDWIDTH
           lJust : (optional, false by default)
                   if true, strip leading spaces to left-justify the value
                   in the field. (resulting string may be less than fWidth)
           sign  : (optional, false by default)
                   'false' : only negative values are signed
                   'true'  : always prepend a '+' or '-' sign.
           kibi  : (optional, false by default)
                   'false' : calculate as a decimal value (powers of 10)
                             kilobyte, megabyte, gigabyte, terabyte
                   'true'  : calculate as a binary value (powers of 2)
                             kibibyte, mebibyte, gibibyte, tebibyte
           units  : (optional) member of enum fiUnits (fiK by default)
                    specifies the format for the units suffix.
                    Note that if the uncompressed value fits in the field,
                    then this parameter is ignored.

        Returns: nothing
           Note: if field overflow, field will be filled with '#' characters.

  Constructor: Convert specified integer value to gString.
  Please see Integer Formatting `'formatInt'` method group for formatting details.

- gString ( const char* fmt, const void* arg1, ... )
  `` __attribute__ ((format (gnu_printf, 2, 0))) ;

        Input  :
           fmt       : a format specification string in the style of
                       sprintf(), swprintf() and related formatting
                       C/C++ functions.
           arg1      : pointer to first value to be converted by 'fmt'
           ...       : optional arguments (between ZERO and gsfMAXARGS - 1)
                       Each optional argument is a POINTER (address of) the
                       value to be formatted.
        Returns:
           nothing

  Constructor: Convert formatting specification and its arguments to gString. Please refer to the compose() method:
  (see Formatted Assignments) for more information.

  Technical Note: There is no constructor using a “`const wchar_t* fmt`” format specification because it would conflict with the constructor which limits the number of characters used to initialize the instance.

- ~gString ( void ) ;

        Input  :
           none
        Returns:
           nothing

  Destructor: Release all resources associated with the gString object.

  Object is destroyed either when it goes out of scope, or by explicitly deleting the object.

  For those new to C++, please note that if you use the ’new’ keyword to create objects, then those objects persist (take up space) until you explicitly delete them or until the application is closed, even if the pointer to the object has gone out-of-scope. See examples below.

  #### Examples

      void calling_method ( void )
      {
         gString *gsPtr = playful_kitten ( "Hello World!" ) ;

         // report contents of object created by called method
         wcout << gsPtr->gstr() << endl ;
         delete gsPtr ; // delete object created by called method
      }

      gString* playful_kitten ( const char* msg )
      {
         gString gs_local( "I love tuna!" ) ;  // local object
         gString *gsPtr1 = new gString,        // global object
                 *gsPtr2 = new gString(msg) ;  // global object (initialized)
         gString *gsArray = new gString[4] ;   // global array

         *gsPtr1 = gs_local ;   // be a kitten: play with the strings...
         gsArray[2] = *gsPtr2 ;
         gsArray[3] = "Scratch my belly!" ;
         gsArray[1] = gsArray[3] ;

         delete gsPtr1 ;      // delete object referenced by gsPtr1
         delete [] gsArray ;  // delete object array referenced by gsArray
         return gsPtr2 ;      // return pointer to object referenced by gsPtr2
                              // (caller is responsible for deleting object)
      }           // 'gs_local' goes out of scope and is destroyed here

#### Dynamic Memory Allocation

- During instantiation of a gString object, a dynamic memory allocation occurs; that is, memory is allocated from the “heap” which is RAM memory not directly controlled by the application.

  This is in contrast to the “stack” memory which is assigned to the application on startup.

- The dynamic allocation is initially the default value: gsALLOCDFLT. This is the number of UTF-32 (wchar_t) characters the object can hold.

  Storage capacity is automatically expanded as necessary to accomodate the size of the data assigned to the object.

- The exception to the default allocation is the gString constructor which takes as it argument a specific storage capacity, expressed as the number of UTF-32 (wchar_t) characters. Examples:
  `gString gs( gsALLOCMED ); gString gs( 2500 );`
  This constructor is described above.
- The DEFAULT storage capacity is the minimum capacity:
  `(gsALLOCDFLT == gsALLOCMIN)`
  Total dynamic allocation for the default storage capacity will be:
  `1K UTF-32 characters + 4K UTF-8 bytes + 1K 16-bit integers,`
  `or 4Kb + 4Kb + 2Kb == 10Kb (approximately).`
- The “medium” capacity, gsALLOCMED is four(4) times the minimum capacity, i.e. 4,096 wchar_t characters.
  This should handle all but the most extreme circumstances. Total dynamic allocation will be:
  `4K UTF-32 characters + 16K UTF-8 bytes + 4Kb 16-bit integers,`
  `or 16Kb + 16Kb + 8Kb == 40Kb (approximately).`
- The MAXIMUM storage capacity is one thousand (1,000) times the minimum allocation.
  This is 1,024,000 wchar_t characters. (Note the mixture of Kilo-byte and Kibi-byte math.) Total dynamic allocation will be:
  `1000K UTF-32 characters + 4000K UTF-8 bytes + 1000K 16-bit integers,`
  `or 1Mb + 1Mb + 500Kb == 2.5Mb (approximately).`
  This is enough memory to hold a short novel, and so the maximum allocation will be needed in only the most extreme cicumstances.
- The “reAlloc” method described in the chapter, gString Miscellaneous, may be used to manually increase or decrease the size of the storage buffers in increments of gsALLOCMIN.
- All methods which set or modify the stored text data implement automatic re-sizing of the data buffers.

  The ‘gsmeter’ test application reports all these methods to be fully functional; however, be aware that the allocation/reallocation algorithm is still young, relatively speaking, (about eight months as of May 2025); so if a problem arises, please drop the author a note.

  Please see gsmeter Test App for additional information; specifically the `R[a|b]` (reallocate) tests which exercise all methods that perform modifications to the size of the storage buffers.

### Assignment Operators

For those new to C++, an assignment operator assigns (initializes) the object to the left of the ’=’ using the data on the right of the ’=’. You may also hear the term ’overloaded operator’. This just means that the ’=’ assignment operator may be defined in more than one way, so it will perform different tasks according to the context or circumstance.

- void operator = ( const char* usrc ) ;
- void operator = ( const uint8_t* usrc ) ;

        Input  :
           usrc  : pointer to an array of UTF-8-encoded characters
        Returns:
           nothing

  Assignment operator: converts UTF-8-encoded source to gString.

- void operator = ( const wchar_t* wsrc ) ;

        Input  :
           wsrc  : pointer to an array of wchar_t 'wide' characters
        Returns:
           nothing

  Assignment operator: converts wchar_t (’wide’) source to gString.

- void operator = ( const gString& gssrc ) ;

        Input  :
           gssrc : gString object to be copied (by reference)
        Returns:
           nothing

  Assignment operator. Copies one gString object to another.

#### Examples

    char utf8Data[] = { "Youth is wasted on the young." } ;
    gString gs1, gs2 ;

    gs1 = utf8Data ;
    gs2 = gs1 ;
    wcout << gs2 << endl ;
     - - -> Youth is wasted on the young.

### Formatted Assignments

- const wchar_t* compose ( const wchar_t* fmt, ... )
  `` __attribute__ ((format (gnu_wprintf, 2, 0))) ;
- const wchar_t* compose ( const char* fmt, ... )
  `` __attribute__ ((format (gnu_printf, 2, 0))) ;

        Input  :
           fmt  : a format specification string in the style of sprintf(),
                  swprintf() and related formatting C/C++ functions.
           ...  : optional arguments (between ZERO and gsfMAXARGS)
                  Each optional argument is a POINTER (address of) the value
                  to be formatted.
                  - Important Note: There must be AT LEAST as many optional
                    arguments as the number of format specifiers defined in
                    the formatting string. Excess arguments will be ignored;
                    HOWEVER, too few arguments will result in an application
                    crash. You have been warned.
        Returns:
           const wchar_t* to formatted data

  Create formatted text data from a format specification string including between ZERO and gsfMAXARGS format specifications and their corresponding argument pointers.

      Supported data types:
       %d, %i  integer (decimal)
       %o      integer (octal)
       %u      integer (unsigned)
       %x, %X  integer (hex lower or upper case)
       %f      floating point (fixed point)
       %e, %E  floating point (scientific notation, lower/uppercase)
       %g, %G  floating point (normal/exponential, lower/uppercase)
       %a, %A  floating point (hex fraction)
       %c      character
       %C      character (alias for %lc)
       %s      string
       %S      string (alias for %ls)
       %p      pointer
       %b, %B  (extension to swprintf - see description below)
       %m      capture 'errno' description string (see /usr/include/errno.h)
       %n      number of characters printed so far
               (value written to corresponding argument's location)
       %%      literal '%'

      See man pages for the C/C++ function 'swprintf' or
      'Table of Output Conversions' for additional details.

#### Examples

    char      Greeting[] = { "Hello!" } ;
    int       iValue = 27064 ;
    long long int qValue = 7842561 ;
    long int  lValue = 485772 ;
    short int sValue1 = 28875, sValue2 = -261, sValue3 = 529 ;
    bool      flagValue = true ;
    float     fltValue = 278.5610234 ;
    double    dblValue = 9982.5610234 ;
    gString gs ;
    gs.compose( "%s - %d %12hd, %-hi, %#hx %08lXh %lld %hhd",
                Greeting, &iValue, &sValue1, &sValue2, &sValue3,
                &lValue, &qValue, &flagValue ) ;
    wcout << gs << endl ;
     - - -> Hello! - 27064        28875, -261, 0x211 0007698Ch 7842561 1
    gs.compose( "floating downstream:%10.2f and doubling our pace:%.4lf",
                &fltValue, &dblValue ) ;
    wcout << gs << endl ;
     - - -> floating downstream:    278.56 and doubling our pace:9982.5610

See also formatted instantiation: gString Instantiation.

#### Important Note on Formatting

Because THE PARAMETERS ARE POINTERS TO THEIR DATA, similar to the C/C++ library function ’sscanf’ and friends, the compiler cannot perform automatic promotions from short int* to int* or from float* to double*, and so-on as it would for swprintf.

This implementation was selected because a) it eliminates data-width conflicts when moving among hardware platforms, and b) it reduces code size while increasing performance.

This implementation relies on you, the designer, to use care that the data type you specify in the formatting string matches the data type of the variable referenced by its parameter pointer AND that you use the ’address-of’ (’&’) operator to reference non-pointer variables. Note also that ’literal’ values may not be used as parameters because literals have no address.

The following constructs will produce errors:

    gString gs ;
    char   grade = 'A' ;
    short  age   = 21 ;
    int    sat   = 1550 ;
    double gpa   = 3.75 ;

       // These examples fail to use the 'address-of' operator for the
       // referenced variables, and will cause a 'segmentation fault'
       // i.e. an application crash.
       gs.compose( "My grade is an %c", grade ) ;
       gs.compose( "I got a %d on my SAT.", sat ) ;
       // The above should be:
       gs.compose( "My grade is an %c", &grade ) ;
       gs.compose( "I got a %d on my SAT.", &sat ) ;

       // These examples use mismatched format-specification/variable
       // reference. This will result in either bad data out OR will
       // cause a memory-access violation.
       gs.compose( "I can't wait to be %d.", &age ) ;
       gs.compose( "My GPA is %1.3f", &gpa ) ;
       gs.compose( "The hex value of %c is: %#x", &grade, &grade ) ;
       gs.compose( "My GPA is %1.3lf", 3.88 ) ; // (literal value)
       // The above should be:
       gs.compose( "I can't wait to be %hd.", &age ) ;
       gs.compose( "My GPA is %1.3lf", &gpa ) ;
       gs.compose( "The hex value of %c is: %#hhx", &grade, &grade ) ;

Parameter Type Checking:
Unfortunately, type-checking of wchar_t formatting strings is not yet supported by the gnu (v:4.8.0) compiler, (but see wchar.h which is preparing for the future). Thus, use care when constructing your ’wchar_t fmt’ formatting string. The ’char fmt’ string IS type-checked.

IMPORTANT NOTE:
Depending on your compiler version, you may get a warning when using the `'%b'` binary format specification (described below):
`"warning: unknown conversion type character ‘b’ in format [-Wformat=]"`
This is because the preprocessor does not recognize our custom format specifier. If this happens, use a ’wchar_t’ (wide) formatting template to avoid the preprocessor type checking.

    Instead of:
          gs.compose( "bitmask: %b", &wk.mevent.eventType );
    Use this (not type checked by the preprocessor):
          gs.compose( L"bitmask: %b", &wk.mevent.eventType );

#### Formatted binary output (extension to swprintf)

We implement an extension to the swprintf output-conversion-specifiers for binary formatted output. We have found this formatting option useful when working with bit masks, for verifying bit-shifting operations during encryption/decryption and other uses.

- Base formatting specifier:
  %b , %B Note that the lower-case / upper-case variants have identical function, and indicate only the case of the identifier character. See format modifiers for data size.
- Format modifiers for data size are the same as for swprintf:
  hh , h , l , ll , L , q Examples: %hhb %hB %llB %qb
- Format modifier for prepending of a data-type indicator.
  '#' (hash character) This is the same principle as for prepending a '0x' indicator to hex output, and will place either a 'b' or 'B' character at the beginning of the output. Examples: %#hhb -> b0101.1010 %#hhB -> B0101.1010
- Format modifier for appending of a data-type indicator.
  '-#' (minus sign and hash character) Rather than prepending the indicator, the indicator will be append to the end of the output. Examples: %-#hhb -> 0101.1010b %-#hhB -> 0101.1010B
- Format modifier for specifying the group-seperator character.
  By default, the bit groups are seperated by a '.' (fullstop) character. To specify an alternate seperator character: % hB -> 0111 0101 1010 0001 (' ' (space) as seperator) %_hB -> 0111_0101_1010_0001 ('_' (underscore) as seperator) %#/hB -> B0111/0101/1010/0001 ('/' (slash) as seperator) %-#-hB -> 0111-0101-1010-0001B ('-' (dash) as seperator) Valid seperator characters are any printable ASCII character that IS NOT alphabetical, IS NOT a number, and IS NOT a '.'(fullstop)
- Format modifier for specifying bit grouping.
  By default, bits are formatted in groups of four (4 nybble); however, if desired, bits can be formatted in groups of eight (8 byte): %.8hB -> 01110101.10100001 %-.8hB -> 01110101-10100001 %# .8hB -> B01110101 10100001 %-#`.8hb -> 01110101`10100001b

#### Field-width specification (swprintf bug fix)

The standard library ’swprintf’ function has a design flaw for format specifications that include a field-width specifier.

’swprintf’ pads the string to the specified number of CHARACTERS, not the number of COLUMNS as it should do. For ASCII numeric source values this is not a problem because one character equals one display column. For string source data, however, if the source string contains characters that require more than one display column each, then the output may be too wide.

Therefore, for string-source-formatting specifications ONLY:
(examples: "%12s" "%-6s" "%16ls" "%5S" "%-24S")
we compensate for this ethnocentric behavior by interpreting the field-width specifier as number-of-columns, NOT number-of-characters. For non-ASCII string data, this will result in output that appears different (and better) than output created directly by the ’swprintf’ function.

#### Unsupported format specifications

Conversion modifiers that are not fully supported at this time:
’j’, ’z’, ’t’, ’%[’
Also, the ’*’ field-width specification or precision specification which uses the following argument as the width/precision value IS NOT supported.

### Integer Formatting

- bool formatInt ( short iVal, short fWidth,
  `` bool lJust = false, bool sign = false,
  `` bool kibi = false, fiUnits units = fiK ) ;
- bool formatInt ( unsigned short iVal, short fWidth,
  `` bool lJust = false, bool sign = false,
  `` bool kibi = false, fiUnits units = fiK ) ;
- bool formatInt ( int iVal, short fWidth,
  `` bool lJust = false, bool sign = false,
  `` bool kibi = false, fiUnits units = fiK ) ;
- bool formatInt ( unsigned int iVal, short fWidth,
  `` bool lJust = false, bool sign = false,
  `` bool kibi = false, fiUnits units = fiK ) ;
- bool formatInt ( long iVal, short fWidth,
  `` bool lJust = false, bool sign = false,
  `` bool kibi = false, fiUnits units = fiK ) ;
- bool formatInt ( unsigned long iVal, short fWidth,
  `` bool lJust = false, bool sign = false,
  `` bool kibi = false, fiUnits units = fiK ) ;
- bool formatInt ( long long iVal, short fWidth,
  `` bool lJust = false, bool sign = false,
  `` bool kibi = false, fiUnits units = fiK ) ;
- bool formatInt ( unsigned long long iVal, short fWidth,
  `` bool lJust = false, bool sign = false,
  `` bool kibi = false, fiUnits units = fiK ) ;

      Input  :
         iVal  : value to be converted
                 Supported value range: plus/minus 9.999999999999 terabytes
         fWidth: field width (number of display columns)
                 range: 1 to FI_MAX_FIELDWIDTH
         lJust : (optional, false by default)
                 if true, strip leading spaces to left-justify the value
                 in the field. (resulting string may be less than fWidth)
         sign  : (optional, false by default)
                 'false' : only negative values are signed
                 'true'  : always prepend a '+' or '-' sign.
         kibi  : (optional, false by default)
                 'false' : calculate as a decimal value (powers of 10)
                           kilobyte, megabyte, gigabyte, terabyte
                 'true'  : calculate as a binary value (powers of 2)
                           kibibyte, mebibyte, gibibyte, tebibyte
         units  : (optional) member of enum fiUnits (fiK by default)
                  specifies the format for the units suffix.
                  Note that if the uncompressed value fits in the field,
                  then this parameter is ignored.

      Returns:
         'true' if successful
         'false' if field overflow (field will be filled with '#' chars)
                 See notes below on field overflow.

Convert an integer value into a formatted display string of the specified width. Value is right-justified in the field, with leading spaces added if necessary (but see ’lJust’ parameter).

Maximum field width is FI_MAX_FIELDWIDTH. This is wide enough to display a 18-digit, signed and comma-formatted value: `'+9,876,543,210,777'`

Actual formatting of the value depends on the combination of: `a) magnitude of the value` `b) whether it is a signed value` `c) the specified field-width` `d) the specified suffix format` `e) locale-specific grouping of digits according the LC_NUMERIC locale` `environment variable` `Important Note: the 'C' (default) locale defines an empty string` `as the grouping separator character. Therefore, the locale should` `be explicitly set before calling this method. (This is done` `automatically when the NcDialog API is initialized.)` `f) See notes below on the possible reasons for field overflow:` `see field overflow` The following examples are based on the U.S. English locale: ‘en_US.utf8’.

#### Examples

    1) Simple comma formatted output if specified field-width is sufficient.
       345    654,345    782,654,345    4,294,967,295

    2) Output with values compressed to fit a specified field width.
       12.3K    999K    12.345M    1.234G    4.3G

    gString gs ;      // gString object

    3) Convert a signed integer value:
       int iValue = 28954 ;

       // field width == 8, right justified (note: compression unnecessary)
       gs.formatInt( iValue, 8 ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  :  28,954:

       // field width == 8, left justified (note: compression unnecessary)
       gs.formatInt( iValue, 8, true ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  :28,954:

       // field width == 6
       gs.formatInt( iValue, 6 ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  :28.95K:

       // field width == 6 with forced sign
       gs.formatInt( iValue, 6, false, true ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  :+29.0K:

       // field width == 5
       gs.formatInt( iValue, 5 ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  :29.0K:

       iValue = -28954 ;    // convert negative source value

       // field width == 8, right justified (note: compression unnecessary)
       gs.formatInt( iValue, 8 ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  : -28,954:

       // field width == 8, left justified (note: compression unnecessary)
       gs.formatInt( iValue, 8, true ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  :-28,954:

       // field width == 6
       gs.formatInt( iValue, 6 ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  :-29.0K:

       // field width == 5
       gs.formatInt( iValue, 5 ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  : -29K:

    4) Convert an unsigned long long integer value (field width == 11):
       unsigned long long int qValue = 39000009995 ;

       // decimal compression (gigabytes) with "official" IEC suffix
       gs.formatInt( qValue, 11, false, false, false, fikB ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  :39.000010gB:

       // binary compression (gibibytes) with "official" IEC suffix
       gs.formatInt( qValue, 11, false, false, true, fiKiB ) ;
       wcout << ':' << gs << ':' << endl ;
        - - >  :38.08595GiB:

Please see (NcDialog test application, ’Dialogw’ for more examples.)

#### Notes on the `formatInt` group

Optional specification of the units suffix for the ’formatInt’ methods. Units are specified using the optional `'units'` parameter, which is a member of the `'fiUnits'` enumerated type.. `enum fiUnits : short { fiK, // 'K' 'M' 'G' 'T' (default) fik, // 'k' 'm' 'g' 't' fiKb, // 'Kb' 'Mb' 'Gb' 'Tb' fikB, // 'kB' 'mB' 'gB' 'tB' ("official" metric 'kilo' designation) fiKiB, // 'KiB' 'MiB' 'GiB' 'TiB' ("official" binary 'kibi' designation) } ;` The ’formatInt’ methods use decimal (powers of 10) compression calculations by default. To use binary (powers of 2) compression, use the optional `'kibi'` parameter. `DECIMAL BINARY` `kilobytes (x/1000) kibibytes (x/1024)` `megabytes (x/1000000) mibibytes (x/1024000)` `gigabytes (x/1000000000) gibibytes (x/1024000000)` `terabytes (x/1000000000000) tebibytes (x/1024000000000)`

#### The kilo/kibi controversy

The IEC (International System of Quantities) recommends lower-case for metric (powers of 10) and upper-case for binary (powers of 2). However, unless you must be accurate in presenting the data according to IEC standard, it is recommended that you choose the format according to: your space requirements, visual appeal, and clear communication with your users.
If you blindly follow style standards against your own better judgement, then be forever labelled as a weenie.

#### `formatInt` field overflow

As described above, the actual formatting of a fixed-width integer field depends on a number of factors. Every effort is made to compress the data to fit within the field while retaining an accurate representation of the numeric value.

There are cases, however, where it is not possible to represent the data within the specified field width. When this occurs, the entire field will be filled with HASH characters `'#'`.

The specified field must be wide enough to accomodate either the entire, uncompressed value, or the combination of compressed value, units designator and sign (if any). The following situations may cause field overflow.

`a) Values <= -10.0 Tbytes or >= 10.0 Tbytes cannot be represented` `by `'formatInt'` methods.` `b) One-column fields can display values between `0 and 9`.` `Values outside this range will cause overflow.` `c) Two-column fields can display values between `-9 and 99`.` `Values outside this range will cause overflow.` `d) Three-column fields can display compressed data` `only if the combined width of value, sign and units require` `no more than three(3) columns.` `e) Four-column fields can display compressed data` `only if the combined width of value, sign and units require` `no more than four(4) columns.` `f) Five-column fields can accurately display any value IF` `the units designator requires only one(1) column.` `g) Six-column fields can accurately display any value IF` `the units designator requires no more than two(2) columns.`

Fields of seven(7) or more columns can display any formatted value without danger of overflow.

#### How To Set the Application Locale In C++

The `NcDialogAPI` library automatically sets the application locale according to the console window environment. Please see the NcDialog documentation, chapter: Multi-language Support for details.

In brief, the “locale” specifies the upper-/lower-case text rules, numeric formatting, language-specific punctuation, currency symbols and so on.

The application locale should be taken from the terminal environment if possible, This is done by creating an instance of the `"std::locale"` structure referencing the empty string (`""`).
`locale* locptr = new locale("");`
The captured locale is then made “global”, that is it replaces the so-called `"classic"` (C/C++ language) locale with the specified locale definition.
`locptr->global( *locptr );`
Please see the C++ documentation for `"std::locale"` for details.

### Data Access

- const wchar_t* gstr ( void ) const ;

        Input  :
           none
        Returns:
           const pointer to array of wchar_t characters

  Return a const pointer to the wchar_t (wide) character array.

- const wchar_t* gstr ( int32_t& charCount ) const ;

        Input  :
           charCount : (by reference, initial value ignored)
                       receives number of characters in array,
                       including null terminator
        Returns:
           const pointer to array of wchar_t characters

  Return a const pointer to the wchar_t (wide) character array, along with the number of characters in the array (including the null terminator).

- const char* ustr ( void ) const ;

        Input  :
           none
        Returns:
           const pointer to array of UTF-8 characters

  Return a const pointer to the char (UTF-8) character array.

- const char* ustr ( int32_t& charCount, int32_t& byteCount ) const;

        Input  :
           charCount : (by reference, initial value ignored)
                       receives number of characters in array,
                       including null terminator
           byteCount : (by reference, initial value ignored)
                       receives number of bytes in array,
                       including null terminator
        Returns:
           const pointer to array of UTF-8 characters

  Return a const pointer to the char (UTF-8) character array, along with the number of characters and the number of bytes in the array (including the null terminator).

#### Examples

    int32_t charCount, byteCount ;
    gString gs( "Wherever you go, there you are!" ) ;

    const wchar_t* wPtr = gs.gstr() ;
    const wchar_t* wPtr = gs.gstr( charCount ) ;
    const char* utf8Ptr = gs.ustr() ;
    const char* utf8Ptr = gs.ustr( charCount, byteCount ) ;

### Copying Data

- int32_t copy ( char* uTarget, int32_t maxBytes, int32_t maxCols = -1 ) const ;

        Input  :
           uTarget  : pointer to target array to receive UTF-8-encoded text
           maxBytes : maximum number of bytes to copy (incl. NULL terminator)
           maxCols  : (optional, default: -1, count bytes only)
                      maximum number of display-columns to copy
        Returns:
           number of bytes copied (incl. NULL terminator)

  Copy gString text to specified target buffer.

  Important Note: It is the caller’s responsibility to specify a target buffer large enough to hold the data. Be safe: `char ubuff[gs.utfbytes()];`

  Technical Note: If source data bytes greater than specified `'maxBytes'`,
  then copy data up to the complete UTF-8 character <= byte limit.
  This avoids writing an invalid character into the target array.

- int32_t copy ( wchar_t* wTarget, int32_t maxChars, int32_t maxCols = -1 ) const ;

        Input  :
           wTarget  : pointer to target array to receive wchar_t 'wide' text
           maxChars : maximum number of characters to copy (incl. NULL)
           maxCols  : (optional, default: -1, count characters only)
                      maximum number of display-columns to copy
        Returns:
           number of characters copied (incl. NULL terminator)

  Copy gString text to specified target buffer.

  Important Note: It is the caller’s responsibility to specify a target buffer large enough to hold the data. Be safe: `wchar_t wbuff[gs.gschars()];`

- std::wostream& operator<< ( std:wostream& os, const gString& gs2 );

        Input  :
           IMPLIED reference to the output stream
           IMPLIED reference to the gString object
        Returns: reference to the specified output stream

  !! NON-MEMBER METHOD !!
  Insertion operator: Copies the contents of the gString object into the ’wcout’ (wide) standard output stream.

  Note that due to the way the output stream is defined, you cannot mix ’cout’ (narrow) and ’wcout’ (wide) output streams indiscriminately. −− If ’wcout’ is called first, then ’cout’ is disabled. −− If ’cout’ is called first, then both narrow and wide channels are active. −− ’wcout’ handles both narrow and wide data, however, ’cout’ handles ONLY narrow data. This is not related to gString, but is a characteristic of the default C++ output stream itself. We recommend that you always use the ’wcout’ stream in console applications for both narrow and wide text data.
- std::ostream& operator<< ( std:ostream& os, const gString& gs2 );

        Input  :
           IMPLIED reference to the output stream
           IMPLIED reference to the gString object
        Returns: reference to the specified output stream

  !! NON-MEMBER METHOD !!
  Insertion operator: Copies the contents of the gString object into the ’cout’ (narrow) standard output stream.

  IMPORTANT NOTE: Access to the narrow output stream is provided for convenience only. It is recommended that the wide stream version (above), if available on your system, be used exclusively.
- int32_t substr ( char* uTarget, int32_t offset, int32_t charCnt ) const;
- int32_t substr ( wchar_t* wTarget, int32_t offset, int32_t charCnt ) const;
- int32_t substr ( gString& wTarget, int32_t offset, int32_t charCnt ) const;

        Input  :
           targ    : (by reference, initial contents ignored)
                     receives null-terminated contents of specified
                     character range
                     -- If target buffer is a char*, then data returned is
                        a UTF-8 text string.
                     -- If target buffer is a wchar_t*, then data returned is
                        a wchar_t (wide) text string.
                     -- If target buffer is a gString object, then both
                        UTF-8 and wchar_t data are returned
           offset  : character index at which substring begins
                     (this IS NOT a byte index)
           charCnt : number of characters to copy (not incl. NULL terminator)
        Returns:
           if target is a wchar_t* or gString object, then returns number of
             characters written to target (not including the NULL terminator)
           if target is a char*, then returns number of bytes written to
             target (not including the NULL terminator)

           Note: returns ZERO if either 'offset' or 'charCnt' out of range
           Note: If 'charCnt' extends beyond the end of the source data,
                 then returns the available data.

  Copy the specified character range to target buffer.
  These methods copy the indicated substring (null terminated) to the target buffer, leaving the original data unchanged.

  If you have a fixed-format field, then the offset and character count will be known in advance. Otherwise you can use the ’find()’ method to locate the substring to be copied.

  Important Note: It is the caller’s responsibility to specify a target buffer large enough to hold the data. If size of substring is unknown, be safe: `wchar_t wbuff[gs.gschars()];` or `char ubuff[gs.utfbytes()];`

  > Please Note: The number of bytes can NEVER be assumed to be the same as the number of characters.
  > Please refer to the ’Multi-language Support’ chapter of the `'NcDialog API'` documentation.

#### Examples

    gString gs( "That's not flying, that's falling -- with style!\n"
                "Buzz Lightyear" ) ;
    char    utf8Data[gs.gs.utfbytes()] ;
    wchar_t wideData[gs.gschars()] ;

    gs.copy( utf8Data, gs.utfbytes() ) ;
    gs.copy( wideData, gs.gschars() ) ;

    gString gstream( "You're a child's TOY! -- Woody" ) ;
    wcout << gstream << endl ;

    // get a copy of the first word starting with 'c'
    gString AusAnimal( "Aardvark Kangaroo Cockatoo Dingo Wombat " ) ;
    gString gsc ;
    int b = AusAnimal.find( " c" ) ;
    if ( b >= 0 )
    {
       int e = AusAnimal.find( L' ', b + 1 ) ;
       if ( e > b )
       {
          AusAnimal.substr( gsc, (b + 1), (e - b - 1) ) ;
          wcout << gsc << endl ;
       }
    }
     - - -> Cockatoo

### Modifying Existing Data

- int32_t append ( const wchar_t* wPtr ) ;
- int32_t append ( const char* uPtr ) ;
- int32_t append ( const wchar_t wChar ) ;

        Input  :
           wPtr  : pointer to array of wchar_t 'wide' text to be appended
                   OR
           uPtr  : pointer to array of char UTF-8 text to be appended
                   OR
           wChar : a single, 'wide' character
        Returns:
           number of characters in resulting string (incl. NULL terminator)
           Note: if value returned equals gsALLOCMAX, then
                 some data MAY HAVE BEEN discarded.

  Append text to existing gString text data up to a combined length of gsALLOCMAX. Characters in excess of the maximum will not be appended.

  #### Example

      gString gs( L"Be kind to your manager." ) ;
      gs.limitChars( gs.gschars() - 2 ) ;
      gs.append( L", and other lower forms of life." ) ;
      wcout << gs << endl ;
       - - -> Be kind to your manager, and other lower forms of life.

- int32_t append ( const wchar_t* fmt, const void* arg1, ... ) __attribute__ ((format (gnu_wprintf, 2, 0)));
- int32_t append ( const char* fmt, const void* arg1, ... ) __attribute__ ((format (gnu_printf, 2, 0)));

        Input  :
           fmt  : a format specification string in the style of sprintf(),
                  swprintf() and related formatting C/C++ functions.
           arg1 : pointer to first value to be converted by 'fmt'
           ...  : optional arguments (between ZERO and gsfMAXARGS - 1)
                  Each optional argument is a POINTER (address of) the value
                  to be formatted.

        Returns:
           number of characters in resulting string (incl. NULL terminator)
           Note: if return equals gsALLOCMAX, then
                 some data MAY HAVE BEEN discarded.

  Append formatted text data to existing gString text data up to a combined length of gsALLOCMAX. Characters in excess of the maxmum will not be appended.

  Please refer to the ’compose’ method (see Formatted Assignments) for more information on converting data using a format specification string.

  #### Example

      short gaddress = 2840 ;
      wchar_t gdirection = L'E' ;
      const wchar_t* gstreet = L"Colorado Blvd." ;
      double gcost = 29.95 ;
      gString gs( "Gorilla Men's Clothing" ) ; // existing text

      gs.append( ", %hd %C %S\n  Dress shirts on sale, $%.2lf.",
                 &gaddress, &gdirection, gstreet, &gcost ) ;

      wcout << gs << endl ;
       - - -> Gorilla Men's Clothing, 2840 E Colorado Blvd.
                Dress shirts on sale, $29.95.

- int32_t insert ( const wchar_t* wPtr, int32_t offset = 0 ) ;
- int32_t insert ( const char* uPtr, int32_t offset = 0 ) ;
- int32_t insert ( wchar_t wChar, int32_t offset = 0 ) ;

        Input  :
           wPtr  : pointer to array of wchar_t 'wide' text to be inserted
                   OR
           uPtr  : pointer to array of char UTF-8 text to be inserted
                   OR
           wChar : a single wchar_t 'wide' character
           offset: (optional, ZERO by default)
                   character offset at which to insert specified text into
                   existing text.
                   Note: if specified 'offset' > number of characters in
                         existing text, then acts like 'append' method.
        Returns:
           number of characters in resulting string (incl. NULL terminator)
           Note: if value returned equals gsALLOCMAX, then
                 some data MAY HAVE BEEN discarded.

  Insert text into existing gString text data up to a combined length of gsALLOCMAX. Characters in excess of the maximum will be truncated.

  #### Example

      gString gs( L"Remember to hurt people!" ) ;
      gs.insert( L"NOT ", 9 ) ;
      wcout << gs << endl ;
       - - -> Remember NOT to hurt people!

- int32_t insert( int32_t offset, const char* fmt, const void* arg1, ... );
- int32_t insert( int32_t offset, const wchar_t* fmt, const void* arg1, ... );

        Input  :
           offset: character offset at which to insert specified text into
                   existing text.
                   Note: if specified 'offset' > number of characters in
                         existing text, then data will be appended to existing text.
           fmt   : a format specification string in the style of sprintf(),
                   swprintf() and related formatting C/C++ functions.
                   Format spec may be either char data or wchar_t data.
           arg1  : pointer to first value to be converted by 'fmt'
           ...   : optional arguments (between ZERO and gsfMAXARGS - 1)
                   Each optional argument is a POINTER (address of) the value
                   to be formatted.

        Returns:
           number of characters in resulting string (incl. NULL terminator)
           Note: if value returned equals gsALLOCMAX, then
                 some data MAY HAVE BEEN discarded.

  Insert formatted text data into existing text data at the specified offset.

  Please refer to compose() method for more information on converting data using a format-specification string.

  #### Example

      const char* Month = "April" ;
      short       Date  = 28 ;
      gString gs( L"We have a date on to see the Yankees." ) ;
      int off = gs.find( "to see" ) ; // index insertion point
      gs.insert( off, "%s %hd ", Month, &Date ) ;
      wcout << gs << endl ;
       - - -> We have a date on April 28 to see the Yankees.

      gString gs( "drive above 90 kph!" ) ;
      gs.insert( ZERO, "%S", L"Don't " ) ; // insert at head of text
      int off   = gs.gschars() ; // index end-of-text
      int Speed = 55 ;
      gs.insert( off, L" Stay under %02d kph in the city.", &Speed ) ;
       - - -> Don't drive above 90 kph! Stay under 55 kph in the city.

- int32_t limitChars ( int32_t charCount ) ;

        Input  :
           charCount : maximum number of characters allowed in formatted data
                       (not including NULL) Range: 1 to storage limit.
        Returns:
           number of characters in the adjusted data (including NULL)

  Truncate the data to no more than charCount display characters.
  Insert a null terminator after the specified number of characters.

  #### Example

      gString gs( "This shirt is available in yellow or red." ) ;
      gs.limitChars( 34 ) ;
      gs.append( "only." ) ;
      wcout << gs << endl ;
       - - -> This shirt is available in yellow only.

- int32_t limitCols ( int32_t colCount ) ;

        Input  :
           colCount : maximum number of display columns allowed in formatted data
                      Range: 1 to storage capacity.
        Returns:
           number of columns needed to display the adjusted data
           Note: If specified column count occurs in mid-character, then the
                 partial character will be removed from the string.

  Truncate the data to no more than colCount display columns. Insert a null terminator after the number of characters required to fill the specified number of display columns.

  #### Example

      gString gs( "The manual is located at:\n"
                  "http://cdn.funcom.com/aoc/pdf/aoc_manual.pdf" ) ;
      gs.limitCols( 55 ) ;
      wcout << gs << endl ;
       - - -> The manual is located at:
              http://cdn.funcom.com/aoc/pdf/

      Note that there are 25 display columns for the first line, (the newline
      character requires no column), and 30 columns remain on the second line.

- int32_t shiftChars ( int32_t shiftCount, wchar_t padChar = L’ ’ ) ;

        Input  :
           shiftCount: < ZERO: shift data to the left, discarding the
                               specified number of characters from the
                               beginning of the array
                       > ZERO: shift data to the right, padding the vacated
                               positions on the left with 'padChar'
                       ==ZERO: do nothing
           padChar   : (optional, SPACE character, 0x20 by default)
                       when shifting data to the right, use this character
                       to fill the vacated character positions
                       NOTE: Specify a one-column character ONLY as the
                       padding character. (multi-column characters ignored)
        Returns:
           number of characters in adjusted array

  Shift text data by the specified number of characters.

      Note for writers of RTL (right-to-left) languages:
       In the above descriptions, the terms 'left' and 'right' are used for
       convenience, but actually 'left' refers to the head of the data
       and 'right' refers to the tail.

  #### Example

      gString gs( "Your balance is: 2,521,697.56 USD" ) ;
      gs.shiftChars( -17 ) ;
      wcout << gs << endl ;
       - - -> 2,521,697.56 USD
      gs.shiftChars( 5, L'#' ) ;
      wcout << gs << endl ;
       - - -> #####2,521,697.56 USD

      Note: For this example, the optional fill character used for
      right-shift is L'#'. The default fill character is space (L' ').

- int32_t shiftCols ( int32_t shiftCount, wchar_t padChar = L’ ’ ) ;

        Input  :
           shiftCount: < ZERO: shift data to the left, discarding the
                               number of characters equivalent to the
                               specified number of display columns
                               NOTE: May discard one extra column if count
                               falls within a multi-column character.
                       > ZERO: shift data to the right, padding the vacated
                               positions on the left with 'padChar'
                       ==ZERO: do nothing
           padChar   : (optional, SPACE character, U+0020 by default)
                       when shifting data to the right, use this character
                       to fill the vacated column positions
                       NOTE: Specify a one-column character ONLY as the
                       padding character. (multi-column characters ignored)
        Returns:
           number of display columns in adjusted array

  Shift text data by the specified number of display columns.

      Note for writers of RTL (right-to-left) languages:
       In the above descriptions, the terms 'left' and 'right' are used for
       convenience, but actually 'left' refers to the head of the data
       and 'right' refers to the tail.

  #### Example

      gString gs( "您的帐户余额是500元" ) ; // "Your account balance is 500 yuan"
      gs.shiftCols( -14 ) ;
      wcout << gs << endl ;
       - - -> 500元
      gs.shiftCols( 5, L'.' ) ;
      wcout << gs << endl ;
       - - -> .....500元

      Note: Most Chinese characters are two display columns wide,
      therefore we shift 14 columns (7 characters) out on the left.
      For this example, the optional fill character used for
      right-shift is L'.' (U+002E, ASCII full stop).
      The Chinese full-stop (U+3002) MAY NOT be used as a fill
      character because it is a two-column character.

- int32_t padCols ( int32_t fieldWidth, wchar_t padChar = L’ ’, bool centered = false );

        Input  :
           fieldWidth: number of columns for the adjusted data array
           padChar   : (optional, ASCII space 0x20 by default)
                       character with which to pad the data
                       Note: Specify a one-column character ONLY.
                             Multi-column characters will be ignored.
           centered  : (optional, 'false' by default)
                       if 'false', all padding will be appended at the end
                                   of the existing data
                       if 'true',  padding will be equally divided between
                                   the beginning and end of the existing data

        Returns:
           number of display columns in the adjusted array

  Append padding to the existing string data to achieve the specified number of display columns.

  If the `'centered'` flag is set, the padding will be divided equally between the beginning and end of the data to achieve the specified field width. Note that if an odd number of columns is to be added, then the odd column will be placed at the end of the data.

  The ‘padCols’ method calculates the number of padding characters needed to fill out the specified field width.

  The default padding character is the ASCII space character (20 hex).
  Any single-column character may be specified as an alternate padding character.

  Padding will be added until either the specified number of columns is reached, OR until the array contains the maximum number of characters (storage limit).

  If the fieldWidth specified is <= the current width of the data, then the data will not be modified.

  #### Example

      gString gs( "This is a test." );

      gs.padCols( 30 );              ==> "This is a test.               "
      gs.padCols( 30, L'#' );        ==> "This is a test.###############"
      gs.padCols( 30, L'#', true );  ==> "#######This is a test.########"

      // To create a right-justified field, use 'shiftCols' (see above):
      gs.shiftCols( (30 - gs.gscols()) );
                                     ==> "               This is a test."
      gs.shiftCols( (30 - gs.gscols()), L'#' );
                                     ==> "###############This is a test."

- int32_t strip ( bool leading = true, bool trailing = true );

        Input  :
           leading  : (optional, 'true' by default)
                      if 'true', strip leading whitespace
                      if 'false', leading whitespace unchanged
           trailing : (optional, 'true' by default)
                      if 'true', strip trailing whitespace
                      if 'false', trailing whitespace unchanged

        Returns:
           number of characters in modified string (incl. NULL terminator)

  Strip (remove) leading and/or trailing whitespace from the string data.

  `` Whitespace characters are defined as:
  `0x0020` single-column ASCII space
  `0x3000` two-column CJK space
  `0x0A` linefeed character
  `0x0D` carriage-return character
  `0x09` horizontal-tab character
  `0x0B` vertical-tab character
  `0x0C` formfeed character

  “Leading” whitespace is space characters from the beginning of the data to the first non-space character. “Trailing” whitespace is from after the last non-space character through the end of the data.

  By default, both leading and trailing whitespace will be removed; however, this action may be modified by resetting the appropriate parameter to ‘false’.

- int32_t erase ( const gString& src, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t erase ( const wchar_t* src, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t erase ( const char* src, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t erase ( wchar_t src, int32_t offset = 0, bool casesen = false, bool all = false );

        Input  :
           src    : source data to be matched, one of the following:
                    -- pointer to a UTF-8 string
                    -- pointer to a wchar_t string
                    -- a gString object containing the source (by reference)
                    -- a single, wchar_t character
           offset : (optional, ZERO by default)
                    character index at which to begin search
                    NOTE: This is a character index, NOT a byte offset.
           casesen: (optional, 'false' by default)
                    if 'false', then scan IS NOT case sensitive
                    if 'true, then scan IS case sensitive
           all    : (optional, 'false' by default)
                    if 'false', then only the first instance of the substring
                                will be deleted
                    if 'true',  then all instances of the specified substring
                                from 'offset' forward will be deleted

        Returns:
           index of first character following the deleted sequence
           Note: This is the wchar_t character index, NOT a byte index
           Returns (-1) if:
             a) no matching substring found
             b) 'offset' out-of-range
             c) 'src' is an empty string or a NULL character

  Scan the data for a matching substring, and if found, erase (delete) the first occurance of the substring, or optionally all instances of the substring from `'offset'` onward.

  Actual comparison is always performed against the ’wide’ character array using wcsncasecmp (or wcsncmp). Null terminator character IS NOT included in the comparison.

- int32_t erase ( int32_t offset = 0, int32_t length = gsALLOCMAX );

        Input  :
           offset : (optional, ZERO by default)
                    index of first character of sequence to be erased
                    NOTE: This is a character index, NOT a byte offset.
           length : (optional, gsALLOCMAX by default)
                    if not specified, then erase all characters from
                       'offset' to end of data
                    if specified, then erase the specified number of
                       characters beginning at 'offset'

        Returns:
           index of first character following the deleted sequence
           Note: This is the wchar_t character index, NOT a byte index
           Returns (-1) if:
             a) offset < ZERO
             b) offset >= number of characters in data
             c) length <= ZERO
           (data will not be modified)

  Erase (delete) the data sequence specified by ’offset’ and ’length’.

  ’offset’ is the index of the first character to be deleted, and ’length’ specifies the number of characters to delete.

  #### Example

  - If the ’length’ parameter specifies deletion of more characters than remain, then ’erase’ has the same effect as calling the `'limitChars'` method (i.e. truncates the string at `'offset'`).
  - If the defaults for both `'offset'` and `length'` are used, then the `'erase'` method has the same effect as calling the `'clear'` method (gString data are reset to an empty string).
  - Note that the NULL terminator will never be deleted.

  #### Examples for `'erase'`

      For the gString object containing the following verbal
      exchange, erase all occurances of the word 'crapweasel'.

      gString gs( "Ross : Are you familiar with the word crapweasel?\n"
                  "Paolo: No, I don't know crapweasel.\n"
                  "Ross : You're a huge crapweasel!" );
      int index = ZERO ;
      while ( (index = gs.erase( " crapweasel", index )) >= ZERO ) ;

      Yields:
        "Ross : Are you familiar with the word?\n"
        "Paolo: No, I don't know.\n"
        "Ross : You're a huge!"

      Find the substring, "the the" and erase the extra "the".
      gString gs1( L"There are seven candidates in the the Primary Election." );
      gString gs2( L"the " );
      int index = gs1.find( "the the" );
      gs1.erase( index, (gs2.gschars() - 1) );

      Yields:
        "There are seven candidates in the Primary Election."

- int32_t replace ( const wchar_t* src, const wchar_t* newtxt, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t replace ( const wchar_t* src, const char* newtxt, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t replace ( const wchar_t* src, const wchar_t newtxt, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t replace ( const char* src, const wchar_t* newtxt, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t replace ( const char* src, const char* newtxt, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t replace ( const char* src, const wchar_t newtxt, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t replace ( const wchar_t src, const wchar_t* newtxt, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t replace ( const wchar_t src, const char* newtxt, int32_t offset = 0, bool casesen = false, bool all = false );
- int32_t replace ( const wchar_t src, const wchar_t newtxt, int32_t offset = 0, bool casesen = false, bool all = false );

        Input  :
           src    : source data to be matched
                    -- pointer to a UTF-8 string
                    -- pointer to a wchar_t string
                    -- a single, wchar_t character
           newtxt : data to overwrite existing text
                    -- pointer to a UTF-8 string
                    -- pointer to a wchar_t string
                    -- a single, wchar_t character
           offset : (optional, ZERO by default)
                    character index at which to begin search
                    NOTE: This is a character index, NOT a byte offset.
           casesen: (optional, 'false' by default)
                    if 'false', then scan IS NOT case sensitive
                    if 'true, then scan IS case sensitive
           all    : (optional, 'false' by default)
                    if 'false', then replace only the first occurance found
                    if 'true',  then replace all occurances of the specified
                                substring

        Returns:
           'true' if successful
           returns 'false' if error (existing data not modified):
             a) no matching source substring found
             b) 'src' is a empty string or a null character
             c) offset < ZERO or offset is beyond existing data
             d) modifying the data would cause buffer overflow

  Replace the specified source substring, or optionally all matching substrings with the provided substring.

  Actual comparison is always performed against the ’wide’ character array using wcsncasecmp (or wcsncmp). Null terminator character IS NOT included in the comparison.

  #### Examples for `'replace'`

      Correct the spelling errors in the following data:
      gString gs( "The land near hare is full of Heres, hoping her and ther." ) ;

      bool okiday = gs.replace( L"hare", L"here" ) ;
      Yields:
        "The land near here is full of Heres, hoping her and ther."

      okiday = gs.replace( "Here", "Hare", ZERO, true ) ;
      Yields:
        "The land near here is full of Hares, hoping her and ther."

      okiday = gs.replace( L'p', L"pp" ) ;
      Yields:
        "The land near here is full of Hares, hopping her and ther."

      int index = gs.find( "her " ) ;
      okiday = gs.replace( "her", L"here", index, true, true ) ;
      Yields:
        "The land near here is full of Hares, hopping here and there."

      Then, replace all spaces ' ' with underscores '_'.
      okiday = gs.replace( L' ', L'_', ZERO, false, true ) ;
      Yields:
        "The_land_near_here_is_full_of_Hares,_hopping_here_and_there."

- int32_t loadChars ( const wchar_t* wsrc, int32_t charLimit, bool append = false );
- int32_t loadChars ( const char* usrc, int32_t charLimit, bool append = false );

  Load the specified number of characters from the source data. This is useful for extracting data from fixed-width fields when the contents of the field is unknown.
  `gs.loadChars( StreetAddress1, 48 );`

  By default, the new text REPLACES the existing text; however, the ’append’ parameter allows the new text to be appended to the existing text.

  The functionality is equivalent to the gString constructor which loads only the specified number of characters.
  See gString Instantiation.

        Input  :
           usrc     : pointer to a UTF-8 encoded string
           wsrc     : pointer to a wchar_t encoded string
           charLimit: maximum number of characters (not bytes) from source
                      array to load. Range: 1 through target storage capacity.
                      The count should not include the NULL terminator
           append   : (optional, 'false' by default)
                      if 'false', replace existing text with specified text
                      if 'true', append new text to existing text

        Returns:
           number of characters in modified string (incl. NULL terminator)

  #### Examples for `'loadChars'`

      Replace the existing text with the specified number of characters
      from the source text.

      const char* Piggy =  // (56 characters)
                 "Spider-pig, Spider-pig does whatever a Spider-pig does." ;
      gString gs( "Existing text." ) ;
      gs.loadChars( Piggy, 36 ) ;
      Yields:
        "Spider-pig, Spider-pig does whatever"

      Append specified number of characters from the source text to the
      existing text.

      gs.loadChars( " it's told, because it's stupid.", 11, true ) ;
      Yields:
        "Spider-pig, Spider-pig does whatever it's told,"

- int32_t textReverse ( bool punct = false, bool para = false, bool rjust = false );

  Reverse the order of characters in the text string.

  If RTL text data displayed by your application is not formatted as desired, then this method may be used to reverse the character order before writing to the display. This is useful for manipulating both RTL (Right-To-Left) language text and mixed RTL/LTR text.

  The ’para’ parameter is useful for outputting columns of numeric data or when the column labels are in an RTL language (see example below).

  Although modern web browsers (Firefox, Opera, Chromium, etc.) usually handle RTL text correctly, other applications often do not. This is especially true of terminal emulator software.

  See also a discussion of multiple-language support in the NcDialog API.

        Input  :
           punct : (optional, 'false' by default)
                   if 'false', invert entire string
                   if 'true' AND if a punctuation mark is seen at either end
                      of the string, invert everything except the punctuation
                      mark(s). typically one of the following:
                      '.' ',' '?' '!' ';' ':' but see note below.
           para  : (optional, 'false' by default)
                   if 'false', invert data as a single character stream
                   if 'true',  invert data separately for each logical line
                               (line data are separated by newlines ('\n')
           rjust : (optional, 'false' by default)
                   if 'false', do not insert right-justification padding
                   if 'true',  insert padding for each logical line to
                               right-justify the data
                               (used to right-justify LTR output)
                               Note that right-justification is performed
                               ONLY if the 'para' parameter is true.
                               Otherwise, 'rjust' will be ignored.

        Returns:
           number of wchar_t characters in gString object
           (if return value >= storage limit, data may have been truncated)

  #### Examples for `'textReverse'`

  Note that the const Hebrew strings are written canonically in the source, but are displayed incorrectly in the terminal window by the info reader and by the HTML browser (sorry about that).

      // Hebrew: "Are you ready for lunch?"
      // Sometimes the terminal will inappropriately move the punctuation
      // to the opposite end of the string.
      // To prevent this, use the 'punct' option.
      const wchar_t* const Lunch = L"?םיירהצ תחוראל ןכומ התא םאה" ;

      gString gs( Lunch ) ;
      gs.textReverse() ;
      wcout << gs.gstr() << endl ;

      OUTPUT (correct except punctuation) : האם אתה מוכן לארוחת צהריים?

      gs = Lunch ;
      gs.textReverse( true ) ;
      wcout << gs.gstr() << endl ;

      OUTPUT (correct): ?האם אתה מוכן לארוחת צהריים

      // When the 'punct' flag is set, both leading and trailing punctuation
      // are identified.
      // Questions in Spanish use a leading inverted question mark (U+00BF),
      // and a trailing ASCII question mark (U+003F).
      // Reverse the internal text but do not reverse the terminal punctuation.
      gs = "¿ozreumla le arap atsil sátsE?" ;
      gs.textReverse( true ) ;
      wcout << gs.gstr() << endl ;

      OUTPUT : ¿Estás lista para el almuerzo?

       = = = = =

      // Reverse multi-line text (paragraph formatting).
      // Ordinary ASCII text is used for this example
      // to demonstrate the reversal.
      // The example outputs to an NcDialog window referenced by NcDialog *dp
      const char* Vaccine = "Have you received your covid-19 vaccination yet?\n
                            "Protect yourself and others,\n"
                            "get your vaccination today!" ;
      gs = Vaccine ;
      // Write unmodified text as LTR data:
      dp->WriteParagraph ( 1, 1, gs, nc.grR, true, false ) ;

      OUTPUT: Have you received your covid-19 vaccination yet?
              Protect yourself and others,
              get your vaccination today!

      // Reverse the data, without punctuation processing or
      // right-justification. (Note: all parameters are optional,
      // but are shown here for clarity.)
      gs.textReverse( false, true, false ) ;

      // Write reversed text as LTR data:
      dp->WriteParagraph ( 1, 1, gs, nc.grR, true, false ) ;

      OUTPUT: ?tey noitaniccav 91-divoc ruoy deviecer uoy evaH
              ,srehto dna flesruoy tcetorP
              !yadot noitaniccav ruoy teg

      // Write the same data as RTL (note the X origin of 48):
      dp->WriteParagraph ( 1, 48, gs, nc.grR, true, true ) ;
      OUTPUT: ?tey noitaniccav 91-divoc ruoy deviecer uoy evaH
                                  ,srehto dna flesruoy tcetorP
                                   !yadot noitaniccav ruoy teg

      // Reload the source data and reverse it without punctuation processing,
      // but WITH right-justification padding.
      gs = Vaccine ;
      gs.textReverse( false, true, true ) ;

      // Write reversed text as LTR data.
      // Note that the padding character is ASCII space ' ',
      // however the '-' character is used here to show the padding position.
      dp->WriteParagraph ( 1, 1, gs, nc.grR, true, false ) ;

      OUTPUT: ?tey noitaniccav 91-divoc ruoy deviecer uoy evaH
              --------------------,srehto dna flesruoy tcetorP
              ---------------------!yadot noitaniccav ruoy teg

      // Write the same data as RTL (note the X origin of 48):
      dp->WriteParagraph ( 1, 48, gs, nc.grR, true, true ) ;

      OUTPUT: ?tey noitaniccav 91-divoc ruoy deviecer uoy evaH
              --------------------,srehto dna flesruoy tcetorP
              ---------------------!yadot noitaniccav ruoy teg

      // Combine RTL text with numeric (LTR) data.
      // Create an ASCII numeric time string.
      // Reverse the numeric string.
      // Insert a Hebrew label: "The current time is: "
      const wchar_t *timeLabel = L"השעה הנוכחית היא: " ; //(displayed incorrectly)
      short hours = 12, minutes = 32, seconds = 45 ;
      gs.compose( "%02hd:%02hd:%02hd", &hours, &minutes, &seconds ) ;
      gs.textReverse( false, true, false ) ;
      gs.insert( timeLabel ) ;

      // Write the data as RTL (note the X origin of 26):
      dp->WriteParagraph ( 1, 26, gs, nc.grR, true, true ) ;

      OUTPUT:
         12:32:45 :השעה הנוכחית היא

  Technical Note On Punctuation

  Determining which characters are and are not punctuation is locale specific (see the `'ispunct()'` C-language function).
  Rather than rely on the locale used by the application calling this method, we test against a list of the most common punctuation characters used in modern languages. If a punctuation character used by your application is not recognized as punctuation, please send us a note including the Unicode codepoint and we will add it to the list.

- int32_t formatParagraph ( int32_t maxRows, int32_t maxCols, bool trunc = true, bool hypenbrk = false,
  `` int32_t *truncIndex = NULL );

        Input  : maxRows  : maximum rows for message (>= 1)
                 maxCols  : maximum columns on any message row (>= 4)
                 trunc    : (optional, 'true' by default)
                            if 'true',  truncate the data if necessary to ensure
                                        that the data do not extend beyond the
                                        specified target area
                            if 'false', format the entire source text array, even
                                        if doing so requires violating the specified
                                        height of the target area (maxRows).
                                        (see also 'truncIndex' parameter)
                 hyphenbrk: (optional, 'false' by default)
                            if 'false', automatic line breaks occur at space ' '
                                        characters only (20h)
                                        Special Case: the following CJK ideographs
                                        are also recognized as whitespace for
                                        purposes of line formatting (see below)
                                         '、' comma U+3001 and
                                         '。' full stop U+3002
                            if 'true',  in addition to the space ' ' characters,
                                        enable line break at:
                                         ASCII hyphen    '-' (2dh)
                                         Unicode &mdash; '—' (2014h)
                                         Unicode &ndash; '–' (2013h)
                                         Unicode &minus; '−' (2212h)
                                         Unicode &shy;       (00ADh) (soft hyphen)
                 truncIndex: (optional, null pointer by default)
                             (referenced _only_ when the 'trunc' flag is reset)
                             If specified, points to a variable to receive the
                             index at which the data _would_have_been_ truncted to
                             fit the specified height of the target area if the
                             'trunc' flag had been set.
                             a) A positive value indicates that the data have not
                                been truncated, AND that the data extend beyond
                                the specified target area.
                             b) A negative value indicates that it was not necessary
                                to truncate the data i.e. the data fit entirely
                                within the target area.

        Returns: number of text rows in the formatted output

  Reformat the text so that when written to the display, it will fit within the specified rectangular area.

  The dimensions of the formatted text is specified as the number of text rows and columns, with a minimum of one(1) row by four(4) columns.

  Technical Description of the Line Break Algorithm

  Formatting is done in three steps:

  1. Remove all newlines from the text.
  2. Perform word wrap to limit the width of each row of the paragraph.
  3. If necessary, truncate the text to limit the height of the paragraph. (but see the `'trunc'` and `'truncIndex'` parameters)

  Token: A ‘token’ as used here is a series of printing characters delimited by whitespace characters. If line breaks on hyphen-like characters is enabled, those characters are also interpreted as token delimiters.

  1. Line breaks occur after the space character at the end of a token, i.e. a word. This means that the line is broken by placing the newline after the identified space character.
     Note: Currently the ASCII space character (20h) and the two-column CJK space (U+3000) are the only whitespace characters recognized.

     Special Case: CJK text seldom contains any spaces at all within a sentence, or even between sentences. Two-column punctuation is designed to provide a visual spacing effect. For this reason, we have made the design decision to process the following CJK ideographs as whitespace:
     `'、' comma U+3001 and '。' full stop U+3002`

     Caution: Tab characters (’\t’) _are not_ recognized as whitespace characters because they are effectively variable width characters. Don’t use them!
     For safety, if Tab characters are present in the text, they are silently removed.

     Optionally, the ASCII hyphen and the Unicode hyphen-like characters can be treated as if they were whitespace characters for purposes of the algorithm. (see the `'hyphenbrk'` parameter.) The characters included within this group are:

     NAME HTML TAG GLYPH UNICODE CODEPOINT ASCII hyphen '-' U+002D mDASH &mdash; '—' U+2014 nDASH &ndash; '–' U+2013 minus &minus; '−' U+2212 soft hyphen &shy; U+00AD
  2. When reformatting the data, it is possible that the text will be pushed beyond the specified number of rows. In this case, we have two options:
     a) Truncate the text after the last specified row is filled.
     b) Alert the caller about the number of rows actually required.
     Optionally, we can indicate the index of where we would have truncated the text so that caller can manually truncate the text if desired. (see the `'trunc'` and `'truncIndex'` parameters)
  3. It is possible that a single token (word) will be longer than the width of the target area. Handling this (unlikely) scenario complicates the line-break algorithm, but could come into play; for instance: filespecs, URLs, or some German words. :-)

     Filespecs and URLs should be parsed using specialized formatting methods.
     Long words can be a challenge during parsing of the data. Our solution is to define “long” tokens as those which are more than half the specified area width (`'maxCols'`).

     This method can optionally break after hyphens, but this may sometimes cause unintended breaks or confusing output. Use the `'hyphenbrk'` option wisely.

  4. Notes on automatic hyphenation:
     Technically, hyphens should be placed between syllables, but that would require a full dictionary of the target language.
     “Can open... worms everywhere.” (Thank you, Chandler Bing.)
     - The hyphen used is the the Unicode &ndash; U+2013. This facilitates stripping them from the text if the text is copied and pasted elsewhere.
       Note that ideally we would use the "soft hyphen," Unicode &shy; U+00AD, but unfortunately most non-word procesing applications interpret this as a zero-width character making it invisible under most circumstances.
     - Programmer’s Note: If the current character is the same width as the hyphen, then the hyphen will be at the right edge of the target area. Otherwise there will be a one-column gap at the end of the line.
     - Special case: For multi-column characters, it is assumed that the characters belong to the CJK character groups. (This may not be true, but multi-column characters seldom appear in Romance languages. Therefore, for multi-column characters only, hyphens are not inserted after mid-token line breaks because there is no way of knowing if we are breaking in mid-word or between words unless we have access to dictionaries for those languages. Again, “...worms everywhere.”

### Comparisons

- int32_t compare ( const char* uStr, bool casesen = true, int32_t length = -1, int32_t offset = 0 ) const;
- int32_t compare ( const uint8_t* uStr, bool casesen = true, int32_t length = -1, int32_t offset = 0 ) const;
- int32_t compare ( const wchar_t* wStr, bool casesen = true, int32_t length = -1, int32_t offset = 0 ) const;
- int32_t compare ( const gString& gs, bool casesen = true ) const;

        Input  :
           uStr     : (UTF-8 string) to be compared
             OR
           wStr     : (wchar_t string) to be compared
             OR
           gs       : (by reference) gString object containing
                      data to be compared
           casesen  : (optional, 'true' by default)
                      if 'true' perform case-sensitive comparison
                      if 'false' perform case-insensitive comparison
           length   : (optional, -1 by default. i.e. compare to end)
                      maximum number of characters to compare
           offset   : (optional, ZERO by default)
                      If specified, equals the character offset into the
                      gString character array at which to begin comparison.

        Returns:
           return value uses the rules of the 'wcsncmp' (or 'wcsncasecmp')
           library function (see string.h):
             ZERO, text data are identical
           > ZERO, first differing char of gString object is numerically larger.
           < ZERO, first differing char of gString object is numerically smaller.

  Compares the text content of the gString object with the specified text.

  The comparison is performed against the gString objects’ wchar_t character arrays. The character comparisons are numerical, not locale-based. This includes the relationship between upper-case and lower-case characters.
  For locale-specific comparisons, please see compcoll method below.

- int32_t compare ( const gString& gs, bool casesen = true ) const ;

        Input  :
           gs       : (by reference) object whose text is to be compared
           casesen  : (optional, 'true' by default)
                      if 'true' perform case-sensitive comparison
                      if 'false' perform case-insensitive comparison

        Returns:
           return value uses the rules of the 'wcsncmp' (or 'wcsncasecmp')
           library function (see string.h):
             ZERO, text data are identical
           > ZERO, first differing char of gString object is numerically larger.
           < ZERO, first differing char of gString object is numerically smaller.

  Compares the text content of two gString objects.

  The comparison is performed against the gString objects’ wchar_t character arrays. The character comparisons are numerical, not locale-based. This includes the relationship between upper-case and lower-case characters.
  For locale-specific comparisons, please see the `compcoll` method below.

- int32_t compcoll ( const wchar_t* wStr ) const;
- int32_t compcoll ( const char* uStr ) const;
- int32_t compcoll ( const gString& bs ) const;

        Input  : wStr     : (UTF-32 string) to be compared
                    OR
                 uStr     : (UTF-8 string) to be compared
                    OR
                 gs       : (gString object by reference) data to be compared

        Returns: using the rules of the 'wcscoll' library function (see wchar.h):
            ZERO, text data are identical
          > ZERO, first differing char of stored data is larger.
          < ZERO, first differing char of stored data is smaller.

  Compares the text content of the gString object with the specified text.

  The comparison is performed according to the active "locale" within the application. This comparison is known as the “collation order” or “dictionary order” comparison where lowercase letters are considered as less than their uppercase equivalents. Characters with diacritical markers and unitary character sequence (e.g. Spanish `'ll'`) will also be sorted according to the rules of the active locale.

  1. If the application has set the locale, the rules of that locale will be used for the comparison.
     Note that the comparison is always case sensitive.
  2. If the application has not specified the locale, then the so-called POSIX C/C++ pseudo-locale will be used.
  3. Note that for some languages, Chinese and Japanese for instance, there is no "dictionary" order for the characters. Instead, dictionaries rely on sound markers, e.g. pinyin transliteration, stroke count, or other criteria. The `'compcoll'` method is not effective for these languages.
  4. Note that if the source data contain mixed languages, the ’wcscoll’ function will be ineffective and misleading.
  5. Technical Note: The ’wcscoll’ librarary function is also considerably slower than the `'wcscmp'` (numeric comparison) function because it scans the data multiple times.
  Please see how to set locale for additional information. Note: Regardless of source data format, this method uses the C-library `'wcscoll'` function exclusively to perform the comparison.

  > Technical Note:

  > In the ASCII world, the letter `'A'` is numerically less than the letter `'a'`; however, in the world of locale-specific comparison, English lowercase is “less than” uppercase, so `'a'` is less than `'A'`.

  > Examples of string comparison using the collation algorithm:

  > 'abc' == 'abc' 'abc' < 'ABC' 'ABC' < 'abc' 'abc' < 'aBc' 'abc' < 'abC' 'abc' < 'abcd' 'abcd' > 'abC' 'abcd' < 'abCd' 'abC' < 'abcd' This would suggest that the collation algoorithm is essentially useless unless your project is to create a dictionary.

- bool operator == ( const gString& gs2 ) const ;

        Input  :
           gs2   : (by reference)
                   gString object containing string to be compared
        Returns:
           'true' if the strings are identical, else 'false'

  Comparison operator: Compares the text content of two gString objects.

  The comparison is performed against the wchar_t character arrays of the two objects. The comparison is is case-sensitive.

- bool operator != ( const gString& gs2 ) const ;

        Input  :
           gs2   : (by reference)
                   gString object containing string to be compared
        Returns:
           'true' if the strings are different, else 'false'

  Comparison operator: Compares the text content of two gString objects.

  The comparison is performed against the wchar_t character arrays of the two objects. The comparison is case-sensitive.

- int32_t find ( const char* src, int32_t offset=0, bool casesen=false, int32_t maxcmp= -1 ) const;
- int32_t find ( const wchar_t* src, int32_t offset=0, bool casesen=false, int32_t maxcmp= -1 ) const ;
- int32_t find ( const gString& src, int32_t offset=0, bool casesen=false, int32_t maxcmp= -1 ) const;
- int32_t find ( const wchar_t src, int32_t offset=0, bool casesen=false ) const;

        Input  :
           src    : source data to be matched, one of the following:
                    -- pointer to a UTF-8 string
                    -- pointer to a wchar_t string
                    -- a gString object containing the source (by reference)
                    -- a single, wchar_t character
           offset : (optional, ZERO by default)
                    character index at which to begin search
                    -- if out-of-range, then same as if not specified
           casesen: (optional, 'false' by default)
                    if 'false', then scan IS NOT case sensitive
                    if 'true, then scan IS case sensitive
           maxcmp : (optional, (-1) by default)
                    -- if not specified, then scan for a match of all
                       characters in 'src' (not including null terminator)
                    -- if specified, then scan for a match of only the first
                       'maxcmp' characters of 'src'
                    -- if out-of-range, then same as if not specified
        Returns:
           index of matching substring or (-1) if no match found
           Note: This is the wchar_t character index, NOT a byte index

  Scan the data for a matching substring and if found, return the index at which the first substring match begins.

  Actual comparison is always performed against the ’wide’ character array using wcsncasecmp (or wcsncmp). Null terminator character is not included in the comparison.

- int32_t findlast ( const char* src, bool casesen=false ) const;
- int32_t findlast ( const wchar_t* src, bool casesen=false ) const;
- int32_t findlast ( const gString& src, bool casesen=false ) const;
- int32_t findlast ( const wchar_t src, bool casesen=false ) const;

        Input  :
           src    : source data to be matched, one of the following:
                    -- pointer to a UTF-8 string
                    -- pointer to a wchar_t string
                    -- a gString object containing the source (by reference)
                    -- a single, wchar_t character
           casesen: (optional, 'false' by default)
                    if 'false', then scan IS NOT case sensitive
                    if 'true, then scan IS case sensitive

        Returns:
           index of last matching substring or (-1) if no match found
           Note: This is the wchar_t character index, NOT a byte index

  Scan the data for the last occurance of the matching substring and if found, return the index at which the substring match occurs.

  Actual comparison is always performed against the ’wide’ character array using wcsncasecmp (or wcsncmp). Null terminator character is not included in the comparison.

- int32_t after ( const char* src, int32_t offset=0, bool casesen=false ) const;
- int32_t after ( const wchar_t* src, int32_t offset=0, bool casesen=false ) const;
- int32_t after ( const gString& src, int32_t offset=0, bool casesen=false ) const;

        Input  :
           src    : source data to be matched, one of the following:
                    -- pointer to a UTF-8 string
                    -- pointer to a wchar_t string
                    -- a gString object containing the source (by reference)
           offset : (optional, ZERO by default)
                    character index at which to begin search
                    -- if out-of-range, then same as if not specified
           casesen: (optional, 'false' by default)
                    if 'false', then scan IS NOT case sensitive
                    if 'true, then scan IS case sensitive
        Returns:
           index of the character which follows the matching substring
             or (-1) if no match found
           Note: This is the wchar_t character index, NOT a byte index

  This method is very similar to the ’find()’ method above, but instead of returning the index to the beginning of the substring, returns the index of the character which FOLLOWS the substring.

- int32_t findr ( const gString& src, int32_t offset = -1, bool casesen = false ) const;
- int32_t findr ( const wchar_t *src, int32_t offset = -1, bool casesen = false ) const;
- int32_t findr ( const char *src, int32_t offset = -1, bool casesen = false ) const;
- int32_t findr ( const wchar_t& src, int32_t offset = -1, bool casesen = false ) const;

        Input  : src    : source data to be matched, one of the following:
                          -- pointer to a UTF-8 string
                          -- pointer to a wchar_t string
                          -- a gString object containing the source (by reference)
                          -- a single, wchar_t character (by reference)
                 offset : (optional, by default: index of null terminator minus one)
                          character index at which to begin search
                          -- if out-of-range, then same as if not specified
                 casesen: (optional, 'false' by default)
                          if 'false', then scan IS NOT case sensitive
                          if 'true, then scan IS case sensitive

        Returns: index of the first character (closest to head of data) of the
                 matching substring or (-1) if no match found
                 Note: This is the wchar_t character index, NOT a byte index

  Scan the data beginning at the specified offset and moving toward the head of the string (toward offset zero). Locate the matching substring and if found, return the index of the first match.

  Actual comparison is always performed against the ’wide’ character array using wcsncasecmp (or wcsncmp). Null terminator character IS NOT included in the comparison.

- int32_t findx ( wchar_t srcChar = L`' '`, int32_t offset=0 ) const;

        Input  :
           srcChar: (optional, L' ' by default) character to be skipped over
           offset : (optional, ZERO by default)
                    if specified, equals the character offset into the
                    character array at which to begin the scan.
        Returns:
           a) If successful, returns the index of first character which
              DOES NOT match specified character.
           b) If the scan finds no character which is different from the
              specified character, OR if 'offset' is out of range, OR if the
              specified character is the null character, the return value
              indexes the null terminator of the array.
           Note: This is the wchar_t character index, NOT a byte index

  Scan the text and locate the first character which DOES NOT match the specified character.

  This method is used primarily to scan past the end of a sequence of space `(' ')` characters (0x0020), but may be used to skip over any sequence of a single, repeated character. Note that the character specified must be a ‘wide’ (wchar_t) character.

  See also the ’scan’ method below which scans to the first non-whitespace character.

- int32_t scan ( int32_t offset=0 ) const ;

        Input  :
           offset : (optional, ZERO by default)
                    if specified, equals the character offset into the
                    character array at which to begin the scan.
        Returns:
           a) If successful, returns the index of first non-whitespace
              character
           b) If the scan finds no non-whitespace character OR if 'offset'
              is out of range, the return value indexes the null terminator
              of the array.
           Note: This is the wchar_t character index, NOT a byte index.

  Scans the text array and returns the index of the first non-whitespace character found.

  `` Whitespace characters are defined as:
  `0x0020` single-column ASCII space
  `0x3000` two-column CJK space
  `0x0A` linefeed character
  `0x0D` carriage-return character
  `0x09` horizontal-tab character
  `0x0B` vertical-tab character
  `0x0C` formfeed character

#### Examples

    gString str1( "Toys for Tots" ) ;
    gString str2( "The Tin Drum" ) ;

    // compare with UTF-8 string
    int result = str1.compare( "Toys for Tots" ) ;

    // compare with wchar_t string
    int result = str2.compare( L"The Tin Drum" ) ;

    // compare gString objects
    if ( str1 == str2 ) { /* do stuff */ }
    if ( str1 != str2 ) { /* do stuff */ }

    gString gs( L"Tiny Tim had a titillating tour of Times Square." ) ;

    // find first instance of substring "tim" (not case sensitive)
    int tIndex = gs.find( "tim" ) ;
    wcout << &gs.gstr()[tIndex] << endl ;
     - - -> Tim had a titillating tour of Times Square.

    // find the next instance of "tim"
    gString gsSub( "tim" ) ;      // search string in a gString object
    tIndex = gs.find( gsSub, tIndex + 1 ) ;
    wcout << &gs.gstr()[tIndex] << endl ;
     - - -> Times Square.

    // find first instance of substring "ti" (case sensitive)
    tIndex = gs.find( L"ti", 0, true ) ;
    wcout << &gs.gstr()[tIndex] << endl ;
     - - -> titillating tour of Times Square.

    // match the first three characters of the search string
    tIndex = gs.find( L"squirrel", 0, false, 3 ) ;
    wcout << &gs.gstr()[tIndex] << endl ;
     - - -> Square.

    // find first instance of L'R' (not case sensitive)
    tIndex = gs.find( L'R' ) ;
    wcout << &gs.gstr()[tIndex] << endl ;
     - - -> r of Times Square.

    // extract the filename from path/filename string
    gString gs( "/home/sam/SoftwareDesign/NcDialog/Dialog1/gString.hpp" ) ;
    if ( (tIndex = gs.findlast( L'/' )) >= 0 )
       wcout << &gs.gstr()[tIndex + 1] << endl ;
     - - -> gString.hpp

    // insert text after first instance of substring
    gString gs( "I think that a parrot would be an ideal pet." ) ;
    int pIndex = gs.after( L"would" ) ;
    gs.insert( " NOT", pIndex ) ;
     - - -> I think that a parrot would NOT be an ideal pet.

For more examples of using gString-class methods, please refer to Test #6 of the ’Dialogw’ test application.

### Extract Formatted Data

- int32_t gscanf ( const wchar_t* fmt, ... ) const ;
- int32_t gscanf ( const char* fmt, ... ) const ;

        Input  :
           fmt  : a format specification template in the style of swscanf()
                  or sscanf() and related C/C++ functions
                  Template may be either a const char* OR a const wchar_t*

           ...  : optional arguments
                  Each optional argument is a POINTER to (address of) the
                  variable to receive the formatted data.
                  - Important Note: There must be AT LEAST as many optional
                    arguments as the number of format specifiers defined in
                    the formatting template. Excess arguments will be
                    ignored; however, too few arguments will return an
                    error condition. (see below)

        Returns:
           number of items captured and converted
           returns 0 if:
             a) number of format specifications in 'fmt' > gsFormMAXARGS
             b) number of format specifications in 'fmt' > number of
                optional arguments (pointers to target variables) provided

  Scan the text data contained in the gString object and extract data according to the specified formatting template.
  (This is an implementation of the standard C-library ’swscanf’ function.)

  The formatting template may be either a `'const wchar_t*'` as in a call to `'swscanf'`, or a `'const char*'` as in a call to `'sscanf'`.

  The formatting template may contain between zero(0) and gsFormMAXARGS format specifiers.

  The optional arguments are pointers to the target variables which will receive the formatted data.

  As with `'swscanf'`, the number of optional arguments must be equal to or greater than the number of format specifiers:
  `(%d, %63s, %X %lld, %24lls, %[, etc.).`
  Excess arguments will be ignored; however, unlike the `'swscanf'` function, `'gscanf'` counts the number of format specifiers and optional arguments, and if there are too few arguments, the scan will be aborted to avoid an application crash due to memory-access violation. (You’re welcome :-)

- int32_t gscanf ( int32_t offset, const wchar_t* fmt, ... ) const ;
- int32_t gscanf ( int32_t offset, const char* fmt, ... ) const ;

        Input  :
           offset: wide-character offset at which to begin the scan
                   Important Note: This IS NOT a byte offset.
                   If offset < 0 || offset > length of data, offset will
                   be silently set to 0.

           fmt   : a format specification template in the style of swscanf()
                   or sscanf() and related C/C++ functions
                   Template may be either a const char* OR a const wchar_t*

           ...   : optional arguments
                   Each optional argument is a POINTER to (address of) the
                   variable to receive the formatted data.
                   - Important Note: There must be AT LEAST as many optional
                     arguments as the number of format specifiers defined in
                     the formatting template. Excess arguments will be
                     ignored; however, too few arguments will return an
                     error condition. (see below)

        Returns:
           number of items captured and converted
           returns 0 if:
             a) number of format specifications in 'fmt' > gsFormMAXARGS
             b) number of format specifications in 'fmt' > number of
                optional arguments (pointers to target variables) provided

  This is the same method as described above except that the scan of the data begins at the specified character offset.

  #### Examples

      int  sval1, sval2, sval3, sval4 ;
      int  ival ;
      long long int llval ;
      double dval ;
      char   str1[64], str2[16], str3[16], ch1 ;
      gString gs( "17 % 18 21 22 48A2B 720451 24.325 A country song "
                  "is three chords and the truth. - Willie Nelson" ) ;
      int32_t cnt =
         gs.gscanf( L"%d %% %d %d %d %X %lld %lf %63[^-] %c %16s %16s",
                    &sval1, &sval2, &sval3, &sval4, &ival, &llval,
                    &dval, str1, &ch1, str2, str3 ) ;

      gString gsOut( "items    : %d\n"
                     "numeric  : %d  %d  %d  %d  0x%04X  %lld  %4.6lf\n"
                     "text data: \"%s\" %c %s %s\n",
                     &cnt, &sval1, &sval2, &sval3, &sval4, &ival, &llval, &dval,
                     str1, &ch1, str2, str3 ) ;
      dp->WriteParagraph ( 1, 1, gsOut, dColor ) ;

      This yields:
      items    : 11
      numeric  : 17  18  21  22  0x48A2B  720451  24.325000
      text data: "A country song is three chords and the truth. " - Willie Nelson

      A working example may be found in the NcDialog API package,
      (Dialogw test application, Test #6).

       - - - - -

      To begin the scan from a particular offset into the text, the unneeded
      initial data may either be scanned into a throw-away buffer or the
      scan offset may be specified directly. For example, to discard the
      first sixteen(16) characters:

      wchar_t junk[gsALLOCMIN] ;
      gs = "Useless garbage: 17 21 34" ;

      gs.gscanf( L"%16C %d %d %d", junk, &sval1, &sval2, &sval3 ) ;
        _or_
      gs.gscanf ( 16, L"%d %d %d", &sval1, &sval2, &sval3 ) ;

  Programmer’s Note: It is good practice to specify a maximum length for all scanned strings in order to avoid overrun of the target buffer. `THIS: %64s %128lls %256S %32[a-z]` `NOT THIS: %s %lls %S %[a-z]`

### Statistical Info

- int32_t gString::gschars ( void ) const ;

        Input  :
           none
        Returns:
           number of characters in the string

  Returns the number of characters in the string including the null terminator.

- int32_t utfbytes ( void ) const ;

        Input  :
           none
        Returns:
           number of bytes in UTF-8 string

  Returns the number of bytes in the UTF-8-encoded string including the null terminator.

- int32_t gscols ( void ) const ;

       Input  :
          none
       Returns:
          number of columns needed to display the data

  Returns the number of columns required to display the string.

- const short* gscols ( short& charCount ) const ;

        Input  :
           charCount : (by reference, initial value ignored)
                       on return, contains number of characters in
                       the string including the null terminator.
        Returns:
           pointer to number of columns needed for display of each character

  Returns a pointer to an array of column counts, one for each character of the text data. Note that number of array elements equals number of characters (plus meta-characters, if any).

  #### Example

      This example is from the FileMangler utility. It trims the head of
      the provided path/filename string to fit within a dialog window.

      void FmConfig::ecoPathFit ( gString& gsPath, short colsAvail )
      {
         if ( (gsPath.gscols()) > colsAvail )
         {
            gString gst = gsPath ;
            int32_t width = gst.gscols(),
                    offset = ZERO,
                    charCount ;
            const short* colArray = gst.gscols( charCount ) ;

            while ( width > (colsAvail - 3) )
               width -= colArray[offset++] ;
            gsPath.compose( L"...%S", &gst.gstr()[offset] ) ;
         }
      }  //* End ecoPathFit() *

- bool isASCII ( void ) ;

        Input  :
           none
        Returns:
           'true' if data are pure, 7-bit ASCII, else 'false'

  Scan the data to determine whether it is pure, 7-bit ASCII.

### gString Miscellaneous

- void gString::clear ( void );

        Input  : none
        Returns: nothing

  Reset contents to an empty string i.e. `""`. The data will consist of a single, NULLCHAR character `(L'\0')`.
  The character and byte counts are set to 1 (one), and the column count is zero.

- int32_t wAlloc ( void ) const;
- int32_t uAlloc ( void ) const;

        Input  : none

        Returns: size of dynamic storage allocation in wchar_t words
                 OR
                 size of dynamic storage allocation in uint8_t (char) bytes

  Report data storage allocation for the gString object:
  Note that this the maximum UTF-32 (wchar_t) characters,
  (or UTF-8 byte) capacity, NOT the current number of
  characters or bytes stored.
  `wAlloc :` returns the storage allocation for
  `` UTF-32 (wchar_t) characters
  `uAlloc :` returns the storage allocation for UTF-8 bytes

- int32_t freeSpace ( void ) const;

        Input  : none

        Returns: available buffer space
                 Note: If zero(0) is returned, data may have been
                       truncated to fit.

  Reports the amount of free buffer space available, expressed as a count of UTF-32 (wchar_t) characters.

- int32_t reAlloc ( int32_t steps, bool clear = false );

        Input  :
           steps : number of steps to increase or decrease in buffer size.
                   Range: +/-999
                   If value out of range, will be set to upper/lower limit.
           clear : (optional, 'false' by default)
                   if 'false', if possible, retain the existing contents
                               of the buffer. (Note that if buffer size is
                               reduced, some data may be truncated.)
                   if 'true',  erase any existing text in the buffer
                               (same as 'clear' method, above)

        Returns: new buffer capacity expressed as the number of wchar_t characters

  Increase or decrease the size of storage buffer by the specified number of gsALLOCMIN increments.

  The buffer is sized in multiples of gsALLOCMIN in the range:
  `gsALLOCMIN <= size <= gsALLOCMAX`
  `1024 chars 1,024,000 chars`

- const char* Get_gString_Version ( void ) const ;

        Input  :
           none
        Returns:
           pointer to version string

  Return a pointer to gString class version number string.

- void gString::dbMsg ( gString& gsmsg ) const;

        Input  :
           gsmsg : (caller's object, by reference)
                   receives most recent debug message
        Returns:
           nothing

  FOR DEBUGGING ONLY! Application can retrieve most recent debug message.
  Note: This method is visible only if the DEBUG_GSTRING flag is set in gString.hpp.

- `void dumpGstring (` const wchar_t*& gstr, const char*& ustr,
  `` const short*& cwid, int32_t& gsw,
  `` int32_t& gsu, int32_t& bsch, int32_t& bsco,
  `` int32_t& utfb, bool& isas ) const;

        Input  :
           gstr   : array of wchar_t characters
           ustr   : array of UTF-8 bytes
           cwid   : array of column widths
           gsw    : size of gstr array
           gsu    : size of ustr array
           bsco   : number of display columns required for stored data
           bsch   : number of wchar_t characters stored (incl. nullchar)
           utfb   : number of UTF-8 bytes stored (incl.nullchar)
           isas   : set if stored data are pure ASCII data

        Returns: nothing

  FOR DEBUGGING ONLY! Get a snapshot of the private gString data members.
  Note: This method is visible only if the DEBUG_GSTRING flag is set in gString.hpp.

### gString Examples

The NcDialog API test application ’Dialogw’ contains extensive examples of gString usage, including working copies of the examples used in this chapter.
The other NcDialog API test applications also use gString in various ways.

Here, we show just a sample of some basic uses for the gString class.

1. Convert a UTF-8 (8-bit) character string to a wchar_t (32-bit) character string.

       const char* some_UTF-8_data = "I want to buy an hamburger." ;
       wchar_t some_wide_data[gsALLOCDFLT] ;

       gString gs( some_UTF-8_data ) ;
       gs.copy( some_wide_data, gsALLOCDFLT ) ;

2. Convert a wchar_t (32-bit) character string to a UTF-8 (8-bit) character string.

       const wchar_t* some_wide_data = L"I want to buy an hamburger." ;
       char some_UTF-8_data[gsALLOCDFLT] ;

       gString gs( some_wide_data ) ;
       gs.copy( some_UTF-8_data, gsALLOCDFLT ) ;

3. Concatenate strings.

       const char* Head = "Where" ;
       const wchar_t* Tail = L"is Carmen Sandiego?" ;
       gString gs( L" in the world " ) ;
       gs.insert( Head, ZERO ) ;
       gs.append( Tail ) ;
       wcout << gs << endl ;
        - - ->  Where in the world is Carmen Sandiego?

4. Create formatted string data.

       const char* utf8String = "We present" ;
       const wchar_t* wideString = L"for your enjoyment:" ;
       const char utf8Char = 'W' ;
       const wchar_t wideChar = L'C' ;
       short int ways = 100 ;
       double dish = 17.57 ;
       gString gs ;

       gs.compose( "%s %S %hd %cays to %Cook %Chicken,\n"
                   "and %.2lf side dishes and beverages!",
                   utf8String,
                   wideString,
                   &ways,
                   &utf8Char,
                   &wideChar, &wideChar,
                   &dish ) ;

       wcout << gs << endl ;
        - - ->  We present for your enjoyment: 100 Ways to Cook Chicken,
                and 17.57 side dishes and beverages!

   > Important Note: All parameters are pointers to the data: For strings (and pointers), the address is the name of the variable. For all other data types, including single characters, use the address-of `('&')` operator.

5. Count display columns to make data fit the window.

   This is a formatting method taken from the ’Dialogx’ test application. It breaks a text stream into lines which fit within the dianostic window. It’s not speedy (or particularly smart), but it demonstrates the use of ’gString’ to calculate the space needed to display text data and then formatting the data to fit the space.

       //*  FormatOutput   *
       //* Input  : gsOut     : semi-formatted source data
       //*          wpos      : start position for display
       //*          lineCount : maximum display lines before truncation
       //* Returns: nothing

       void dXClip::FormatOutput ( const gString& gsOut,
                                   winPos& wpos, int32_t lineCount )
       {
          int tWidth = (ddCOLS - 2),        // inside width of target window
              maxWidth = tWidth * lineCount,// max columns for message
              tLines = ZERO ;               // loop counter

          gString gsw( gsOut.gstr() ), gso ;
          if ( gsw.gscols() > maxWidth )
          { // truncate the string if necessary
             gsw.limitCols ( maxWidth - 3 ) ;
             gsw.append( L"..." ) ;
          }
          do
          {  // break the source into convenient widths
             gso = gsw ;
             gso.limitCols( tWidth ) ;
             gso.append( L'\n' ) ;
             gsw.shiftCols( -tWidth ) ;
             this->dpd->ClearLine ( wpos.ypos ) ; // clear target display line
             wpos = this->dpd->WriteParagraph ( wpos, gso,
                                                dxPtr->dColor, true ) ;
          }
          while ( ++tLines <= lineCount && gsw.gschars() > 1 ) ;

       }  //* End FormatOutput() *

   The example above is just a simple demonstration of using column widths. To see it in action, please refer to the ’Dialogw’ NcDialog API Test Application, test seven (7).

   For a more sophisticated text-parsing algorithm, see formatParagraph which parses text data by token rather than simply counting columns.

### gsmeter Test App

> GSMETER
> gsmeter Introduction
> gsmeter Options
> Building gsmeter

#### 'gsmeter' Introduction

The original design of the gString class was based upon a fixed buffer size of `PATH_MAX`, which is the maximum length of a file specification under the POSIX standard. This is is defined as s GNU compiler constant, (4096 bytes), which is greater-than-or-equal-to the number of bytes (or characters), depending on the character set used for filespecs.
This buffer size was chosen specifically to balance storage capacity with performance. The original gString design has performed far beyond expectations for over fifteen years, and it is expected to meet or exceed most daily needs of applications into the future.

In October of 2024, a beta-test branch of the gString class, `bString` was created. The design critera for this class were to retain the original functionality of the gString class with as few modifications as possible, while converting the static character buffers to dynamically-resized character and byte buffers.

This compares favorably with std::string and std::wstring which are cute in their own way and semi-functional; but seriously overweight. While it is not our intention to be fat-shaming the C++ language, std::string support for text data is functionally inconvenient, entirely too English-centric and practically-speaking, is often mis-used (or ignored completely) by developers due to its opaque implementation, which is based on a solid idea, but clearly, was designed by committee.

Because this new design touches every aspect of the original gString functionality, the `'gsmeter'` test utility was created to perform exhaustive regression testing, with a special focus on the algorithms for allocation and re-allocation of dynamic memory.

The beta branch has now been re-integrated into the mainline gString class, so the test application is now being included as part of the gString distribution. Have fun!

#### 'gsmeter' Command-line Options

While this application lacks professional polish, it does provide a simple menu structure and the usual `--help` and `--version` options.

    gsmeter: version:0.0.05  gString v:0.0.37 - (c) 2024-2025 The Software Samurai
    ------------------------------------------------------------------------------
    Test Suite for gString Class  Usage: gsmeter TEST [SUBTEST]
       C[a|b] --------- Constructors  :  S ------- Statistics
       I[a|b] --------- Initializers  :  O ------- Output group
       M[a|b|c|d]------ Modifiers     :  B[a|b] -- Buffer size
       A[a|b|c|d|e|f]-- Analyzers     :  R[a|b] -- Reallocation
       --help  --version              :  P ------- Playground

          Example Invocations:
             gsmeter              # No arguments, invokes the options menu
             gsmeter Ca           # Constructor Group, section 'a'
             gsmeter Ac           # Analyzer Group, section 'c'
             gsmeter --version    # Report version numbers, current locale
                                  # and copyright info

The tests are grouped according to functionality, and are sub-divided into smaller groups so that each test run will fit within one terminal window of 39 rows x 150 columns.

There are seven(7) test groups with eighteen(18) tests, plus a “Sandbox” for creating ad-hoc tests.

#### Test Groups

1. Constructors
   A: Constructors A, default, specify allocation, char*, wchar_t*, format specification B: Constructors B: integer-formatting constructors
2. Initializers
   A: Initializers A, and basic reporting methods: wAlloc(), uAlloc(), gstr(), ustr(), gschars(), uftbytes(), gscols(), isASCII(), operator=, loadChars(), formatInt() B: Initializers B: compose(format, ...), compose(binary extension)
3. Modifiers
   A: append(), limitChars(), limitCols(), insert(), erase() B: replace(), shiftChars(), shiftCols() C: rightJustify(), padCols(), strip(), textReverse() D: formatParagraph(), clear()
4. Analyzers
   A: operator==, operator!=, compare(gString&), compare() B: compcoll(), find() C: findlast(), findx(), scan() D: after() E: findr() F: gscanf()
5. Statistics
   Info Dump, Public Stats, Character Widths, Class Version Number
6. Output group
   "operator<<" for both UTF-32 (wide) and UTF-8 (narrow) streams
7. Reallocation tests
   A: Reallocation tests, Group A B: Reallocation tests, Group B
8. Buffer Size/Resize (attempted overflow) tests
   A: Constructors and Assignments Overflow tests B: Insert and Append Overflow tests

Reporting of test results is split between the terminal window and a file `(gsmdbg.txt)` created in the current working directory.

Note on Application Locale

`gsmeter` automatically enables the “locale” specified in the terminal environment. While the gString class is written to be locale-independent, some of the `gsmeter` tests rely upon the locale to function properly.
Specifically, the gString `compcoll` (compare-collated) method invokes the locale-aware C-language function,`'wcscoll'`. This function uses a dictonary-style comparison which is dependent on the language and locale involved. Please see compcoll method for details.

#### Building 'gsmeter'

`gsmeter` is a very simple application, so building it is also simple.

There are four(4) ways to invoke the `Makefile`:

gmake # compile the application module and link # to the existing gString library gmake buildlib # delete the existing gString.lib link library # and rebuild it gmake clean # Remove the object files, the gString library # and the executable gmake all # Execute the 'clean', 'buildlib' and # 'gmake' options

> > Important Note: Some tests include a snapshot of the gString object’s internal configuration. This report requires that a conditional-compile declaration be enabled: #define DEBUG_GSTRING (1) This declaration is located near the top of gString.hpp. This declaration should be enabled only for use by `gsmeter`, and should be disabled for all other applications. #define DEBUG_GSTRING (0)

## CsvView Demo App

`'CsvView' (csvv)` reads any Comma-Seperated-Values file and formats the data for viewing in the terminal window.

### Introduction to CsvView

#### What Is CSV?

Comma-Seperated-Values files are plain-text files commonly used for transferring tabular data between applications or accross the web. The format is very simple and supported by many applications such as LibreOffice, Excel(tm), as well as various email platforms and database applications.

While there is no formal specification for CSV data, several groups have worked toward a normalized format, most notably the World Wide Web Consortium (W3C).
https://www.w3.org/TR/tabular-data-primer/
https://www.w3.org/2013/csvw/wiki/Main_Page.html/

Additional information (and the opinions of various parties) are available:
Internet Engineering Administration, Research Task Force `(IRTF)`:
https://datatracker.ietf.org/doc/html/rfc4180
FileFormat.com:
https://docs.fileformat.com/spreadsheet/csv/
Wikipedia:
https://en.wikipedia.org/wiki/Comma-separated_values

For examples of CSV files, please see CSV Encoding, and the sample CSV files included with this distribution.

#### The CsvView Application

The `CsvView` application (csvv) reads any CSV-formatted file and reformats it for viewing, either directly in the terminal window or through the `'less'` utility. `CsvView` supports source files in any of the four(4) authorized encodings:
`UTF-8`
`UTF-8 with byte-order mark (BOM)`
`UTF-16LE (little-endian)`
`UTF-16BE (big-endian)`

It is important to note that the `'less'` can display some CSV files without the need for reformatting; however, `'less'` will often complain that the target file is a `"binary"` file, and cannot display the data as text, even though the file does not actually contain binary data.

For this reason, `CsvView` reformats the source data into pure UTF-8 encoding before display. This re-encoding also vertically aligns the fields to present the data in an orderly manner. `CsvView` can format the output in any of three(3) ways.

Horizontal Format: one record per line

    NAME              TITLE                PHONE        EMAIL
    Helena Handbasket Queen of the Castro  415-654-3210 Yaz-Queen@TwinPeaks.com

Vertical Format : one field per line

    NAME     Helena Handbasket
    TITLE    Queen of the Castro
    PHONE    415-654-3210
    EMAIL    Yaz-Queen@TwinPeaks.com

Quick Format : horizontal format, truncated to width of window

    ┌───────────────────────────────────────────────────────┐
    │NAME              TITLE                PHONE        EMA│
    │Helena Handbasket Queen of the Castro  415-654-3210 Yaz│
    └───────────────────────────────────────────────────────┘

Please see csv display option for selection of the display format.

`CsvView` may also be used to create files in CSV format using any of the encoding methods described above.
Please see csv create option for details.

### Invoking CsvView

This chapter lists the command-line options for invoking the `CsvView` (csvv). The `'help'` and `'version'` options override all other specified options.

The `CsvView` application is intentionally very simple — built without support for direct user-configuration of the `AnsiCmd` library. The only available terminal configuration option is for selection of the color attributes used for text output.
Please see Invoking - Terminal Setup for a detailed discussion of the `AnsiCmd` terminal setup options used for the `EarthPoints` and `AcEdit` applications,

#### Summary of Options

> OPTION | DESCRIPTION
> --- | ---
> csv filespec option | Specify the source CSV file
> csv display option | Specify the display format
> csv fgndattr option | Foreground color attribute
> csv bgndattr option | Background color attribute to a file
> csv language option | Specify user-interface language
> csv header option | Specify whether source file includes a header record
> csv saveas option | Save formatted display data
> csv stats option | Report source file stats
> csv dimensions option | Report dimensions of terminal window
> csv help option | Display all application options
> csv helpless option | Same as `'--help'` option except pipe through `'less'`
> csv version option | Reports CsvView version number and copyright info.
> `---` Development Options `---` | `------------------`
> csv create option | Create a CSV file
> csv capture option | Capture a range of records
> csv terminfo option | Report the current terminal configuration
> csv pause option | Pause before display of formatted data

Options may be specified in any order.

For each option that requires one or more arguments, the option name and its argument(s) may be separated by either `'='` or `' '` (space). Note that if the argument contains whitespace, then the entire argument sequence must be enclosed within single-quotes or double-quotes. This prevents the terminal’s shell program from “interpreting” (trashing) your argument formatting.

Multiple instances of an option will result in unpredictable results, so don’t do it.

    Examples:
        --filespec=Contacts.csv
        --filespec Contacts.csv
        --create=Sample.txt,utf8bom,crlf
        --create "Sample Records.txt, utf16le, crlf"

Note: As a convenience, the options may be uniquely specified in a truncated form. At least six (6) characters of the option must be specified. This consists of the two `'dash'` characters, plus the first four characters of the option name. Example: The “`--filespec`” option may be uniquely specified as “`--file`”.

#### Invocation Options

– –filespec Specify the source CSV file.

> Specify the file to be displayed.
> The source file may be specified as a filename in the current directory, as a relative path, or as an absolute path. Special characters such as `'.' '..' '~'` are recognized, and symbolic links in the path will be followed. The filename must include the `".csv"` filename extension.

> The file must be in Comma-Seperated-Values (CSV) format, and encoded as
> `UTF-8, UTF-8 with byte-order-mark, UTF-16LE or UTF-16BE`.
> If the file cannot be verified as containing valid CSV data, a warning will be displayed and the application will exit.
> Important Note: Because there is no formal standard for the CSV format, it is possible that a non-CSV file will be accepted for processing. If this happens, then as the saying goes: “Garbage in, garbage out.”

>        EXAMPLES:  csvv --filespec=Contacts.csv
>                   csvv --filespec='Company Employee Info.csv'
>                   csvv --filespec "Fred's Extended Family.csv"
>                   csvv --file=Contacts.csv
>        Although it is not recommended, CsvView will accept a source
>        filename WITHOUT the "--filespec" option:
>                   csvv Contacts.csv --display=v --stats

– –display Specify the display format.

> The `display` option specifies the type of formatting to be used for display of the CSV records. The options are:

> h — Horizontal (default) `` Display one record per line. `` The record fields are aligned vertically for ease of viewing. `` The data are displayed using the `'less'` utility to fascilitate `` both vertical and horizontal scrolling. v — Vertical `` Display one field per line. This is useful if the record `` is wider than the width of the terminal window. `` The data are displayed using the `'less'` utility to fascilitate `` both vertical and horizontal scrolling. q — Quick `` The Quick output format is the same as the Horizontal format except: `` a) The data are written directly into the terminal window, `` one page at a time. `` This is similar to viewing data using the `'cat'` utility. `` b) The data are truncated at the right edge of the terminal window `` to prevent the terminal from inserting automatic line breaks.

> Please see Output Formats for further information.

> `EXAMPLE: csvv --display=v`

– –fgndattr Set foreground color attribute.

> Specify the foregroud (text) attribute used for display of the data.
> By default, the text data are displayed using blue text.

> The available attributes are the eight(8) basic colors and their “intense” (bold) variants, or the terminal-default attribute.

>        BASIC    INTENSE
>        -----    -------
>        black    blacki
>        red      redi
>        green    greeni
>        brown    browni
>        blue     bluei
>        magenta  magentai
>        cyan     cyani
>        grey     greyi
>        dflt

>        EXAMPLES:  csvv --fgndattr=green
>                   csvv --fgndattr red
>                   csvv --fgndattr=redi

– –bgndattr Set background color attribute.

> Specify the backgroud attribute used for display of the data.
> By default, the background attribyte is the terminal default (dflt).

> The available attributes are the same as those listed for the foreground attributes above.
> Note: Avoid using the same attribute for both foreground and background.

> [** THE bgndattr OPTION IS CURRENTLY IGNORED **]

>        EXAMPLES:  csvv --bgndattr=magenta
>                   csvv --bgndattr brown
>                   csvv --bgndattr=bluei

– –language Specify the user interface language.

> Specify the language used by the application’s user interface.

> Options:
> `` `EN —` ENglish
> `` `ZH —` ZHongwen (中文) Simplified Chinese
> `` `tenv —` Terminal EnVironent (default)

> By default, the user interface language used is derived from the locale used by the system. If the system locale is one of the Zhōngwén variants, the Chinese interface will be used; otherwise, the English interface will be used.
> See Terminal Configuration for a discussion of locale.

> To override the automatic language selection, use the `'--language'` option to select the desired user-interface language.

> Note that the ’EN’ and ’ZH’ designators are the internationally accepted language designators.
> Please refer to Library Of Congress document: https://www.loc.gov/standards/iso639-2/
> or to the Wikipedia article which describes the `ISO 639` standard:
> https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes

>        EXAMPLES:  csvv --language=ZH
>                   csvv --lang en
>                   csvv --language tenv

> > Note: This application is designed to be as simple as possible, so we have implemented only our two(2) best languages. Other UI languages may be added in a later release.

– –header Specify whether source contains header record.

> Override the application’s determination of whether the source file contains a header record.
> A header record contains column headings for the remainder of the records.

> During the initial scan of the source file, the application tries to determine whether the first record of the file is a header record. The criteria for this test are:
> `1)` Is the first line of the file terminated by a newline?
> `2)` Does the record include at least one comma (’,’) delimeter?
> `3)` Do all fields of the record contain text data, (non-empty)?

> Clearly, the first record of a CSV file may meet all these criteria and still not be a header record—or may be a header record without meeting these criteria. If this happens, the program’s scan results may be overridden using the `'--header'` option to specify whether the file does, in fact include a header record.

> Note that if a CSV file does not contain a header record, then horizontal output formatting will simply have no column headings; however, for vertical output formatting, generic column headings will be used. Example:
> `Field # 1 : Helena Handbasket`
> `Field # 2 : Queen of the Castro`
> `Field # 3 : 415-654-3210`
> `Field # 4 : Yaz-Queen@TwinPeaks.com`

> `EXAMPLE: csvv --filespec='Contacts.csv' --header=y`

> `────────────────────`

> > Note that the MIME-type database for the system may optionally specify whether CSV files on the system include header records; however, this information is not just optional, it is unreliable and is not referenced by this application. In a corporate setting, CSV files that are routinely used to transfer company data may adhere to the specified MIME type; however, a CSV file created by a non-corporate application (e.g. an email application), or a file randomly downloaded from the web are not likely to conform to the system’s MIME-type database.

– –saveas Save reformatted display data.

> When specified, the `'--saveas'` option saves a copy of the displayed data to a file in the current working directory. Specify the filename only.

> The saved data will be plain text in the same format used to display the data in the terminal window.

> The data format is determined by the `'--display'` option described above, either `'Horizonal'` or `'Vertical'`.
> (For the “Quick” output format, the data are not saved.)

> `EXAMPLE: csvv --filespec='contacts.csv' --saveas='formatted_data.txt'`

– –help (or –h) Display command-line help.

> Command-line Help. Display a brief summary of command-line usage and options.
> (overrides everything on command line except `'--version'`)

>        EXAMPLES:  csvv --help
>                   csvv -h

– –helpless Display command-line help.

> Display command-line help. Same as the `'--help'` option above except that the help menu will be piped through the `'less'` utility.

>        EXAMPLES:  csvv --helpless
>                   csvv -hl

– –version Report CsvView version number.

> Display the CsvView version number and copyright information.
> (overrides everything else on the command line)
> The AnsiCmd-class and gString-class version numbers are also reported.

> `EXAMPLE: csvv --version`

– –create Create a CSV file from plain text.

> Create a Comma-Seperated-Values (CSV) file using a plain-text file as the source data.

> During development, this option was used to create various test files to exercise the functionality and general syntax checking of the application. The test files included in this distribution were all created from the plain-text file, `'csvsource.txt'` using the `--create` option. Study this file for more information.

> The `create` option takes two or three arguments:
> `1) source filename`
> `2) UTF encoding` (utf8, utf8bom, utf16le, or utf16be)
> `3) newline format (optional) lf` linefeed only, or
> `crlf` carriage-return/linefeed pairs

> The CSV file created through this option takes the name of the source file, but with the `".csv"` filename extension. Example:
> `csvsource.txt --> csvsource.csv`
> `csvsource --> csvsource.csv`

> Although the source file is technically a plain-text file, it could also be described as a pure UTF-8 encoded CSV file.

> #### Exception:

> The newline character, (either a linefeed `'\n'` or a carriage-return/linefeed pair `"\r\n"`) is a special character which signals the end of a record within a CSV file. However, it is fairly common to use newlines within a long, free-form field to indicate line breaks, so long as the field is enclosed within secondary-delimeter pairs.

> To test this functionality, a special two-character sequence within the source file: “\n” is recognized by the `'createCsvFile'` method as an embedded newline character. This allows for testing embedded newlines within a field.

> Please see CSV Encoding for additional information about newlines and commas embedded within a CSV record.

>        EXAMPLES:  csvv --create=source_data.txt,utf16le
>                   csvv --create="source data.txt,utf16be,crlf"
>                   csvv --create="source data.txt, utf8bom, crlf"

– –capture Capture a range of records.

> Extract a range of records from the source file, and if the records are UTF-16 encoded, convert them to UTF-8.

> Format the data for analysis, and write the formatted data to a file in the current working directory.
> The name of the target file is: `"captured_records.txt"`

> The `--capture` option takes three(s) parameters:
> `a)` the source filename,
> `b)` the index of the first record to be captured (>=0), and
> `c)` the index of the last record to be captured (>first record)
> Note that the header record (index 0) is always captured.

> During development, certain records in the source files may either be malformed or, gasp the application may have parsed the record incorrectly. This option may be used to isolate the suspected range of records and format them as both text and `ASCII` hex, which may then be used to visually analyze the data. See example output below.

> `EXAMPLE: csvv --capture="SourceRecords.csv,5,6"`

> #### Sample Output

> HEADER RECORD - index:00 ------------------------- N A M E , A G E , O C C U P A T I O N \n 4E 41 4D 45 2C 41 47 45 2C 4F 43 43 55 50 41 54 49 4F 4E 0A RECORD INDEX :05 ----------------- 成 吉 思 汗 , 9 6 2 , 马 语 者 , " 蒙 古 , 6210 5409 601D 6C57 2C 39 36 32 2C 9A6C 8BED 8005 2C 22 8499 53E4 2C 肯 特 山 脊 " \n 80AF 7279 5C71 810A 22 0A RECORD INDEX :06 ----------------- " B o n d , J a m e s " , 3 6 , w o m e n \n 22 42 6F 6E 64 2C 20 4A 61 6D 65 73 22 2C 33 36 2C 77 6F 6D 65 6E 0A

– –stats Report statistics for source file.

> Display information about the specified source file.
> This information includes basic information about the file itself, as well as information about the CSV data contained in the file.

> The following example illustrates the type of information reported.
> This test file shown here is included as part of the distribution package.

>     Source File Stats
>     ------------------------------------
>     Filename   : utf8bom_cr.csv            # Name of the source file
>     File type  : REG                       # File type (must be Regular)
>     File bytes : 388                       # Size of the file in bytes
>     Mod time   : 2024-02-15T19:09:30       # Timestamp (modification time)
>     Permissions: r:1 w:1                   # Read and Write permission flags
>     Encoding   : UTF-8bom Cr:yes Hdr:yes   # Type of character encoding
>                                            # Type of newline: Linefeed only,
>                                            #  or Carriage-return/Linefeed pairs
>                                            # Report whether file includes a
>                                            #  header record
>     Records    : 9        Fields : 4       # Number of records (not incl. header)
>                                            # Number of fields per record

>        EXAMPLE:  csvv --stats --filespec='utf8bom_cr.csv'

– –dimesions Report terminal window dimensions.

> Report the size of the terminal window expressed as the number of rows and columns.

> When deciding how to format the CSV data to fit within the terminal window, the window dimensions must first be calculated. This option simply reports the results of that calculation.

> The following example shows how the report is written to the display.
> The report preceeds the formatted output of the CSV file data.

>     ┌───────────────────────────────────────┐
>     │ Terminal Size: 39 rows x 154 columns  │
>     └───────────────────────────────────────┘
>     Press Any Key To Continue...

>        EXAMPLES:  csvv --dimensions
>                   csvv --dime --filespec=Contacts.csv

– –terminfo Report terminal configuration.

> Used during development, this option reports the current terminal window configuration data as reported by the `AnsiCmd` link library. Please see acGetTermInfo for further information about terminal configuration.

>     Terminal Configuration Flags
>     ---------------------------------------------
>     istrip : 7-bit input                 disabled
>     opost  : output flags                enabled
>     onlcr  : convert newlines to cr/lf   enabled
>     xtabs  : convert tabs to spaces      disabled
>     cread  : read terminal input         enabled
>     csize  : character width             8 bits
>     icanon : enable canonical input      disabled
>     echo   : echo character input        disabled
>     echonl : echo newlines               disabled
>     echoctl: echo control chars as (^x)  enabled
>     iexten : posix extensions            enabled

>        EXAMPLE:  csvv --terminfo

– –pause Pause before display of formatted data.

> This option is included primarily for use during development.
> When debugging output is enabled, it is written to the display during startup and during analysis of the source file. This option causes the program to wait for a keypress before the debugging information is overwritten by the formatted CSV records.

> `EXAMPLE: csvv --pause --filespec='Contacts.csv'`

### CSV Encoding

This chapter provides a practical, (but not official) description of Comma-Seperated-Values (CSV) formatting and example data for each of the recognized UTF encodings.

1. A CSV file consists of a list of `"records"`, one record per line of the file. Any reasonable number of records is supported.
   Technical Note: This application uses 16-bit indices, so the practical record limit is 32,768 data records.
2. Each record consists of a series of `"fields"` seperated by the `ASCII` comma: `',' (2C hex)`.
   1. Each record must have the same number of fields.
   2. Any reasonable number of fields is allowed.
   3. A field may contain any reasonable number of characters, (including zero characters).
   4. A field may contain any text character except commas and newline characters, (but see note about secondary delimeters, below).
   5. The first field of a record does not have a leading comma.
   6. The last field of a record does not have a trailing comma.
3. Each line is terminated by a newline. For purposes of this discussion, a `"newline"` is either a single linefeed character: `'\n'` or a carriage-return/linefeed pair: `"\r\n"`.

   In UTF-8 encoded data the newline is represented as:
   `0A or 0D0A hex`
   `\n or \r\n`

   In UTF-16LE (little-endian) encoded data the newline is represented as:
   `0A00 or 0D000A00 hex`
   `\n\0 or \r\0\n\0`

   In UTF-16BE (big-endian) encoded data the newline is represented as:
   `000A or 000D000A hex`
   `\0\n or \0\r\0\n`

4. Secondary Field Delimeters:
   The double-quotation character: `'"' (22 hex)` may be used in conjunction with the basic comma delimeter to create pairs of secondary field delimeters. This is useful (and necessary) if the field contains either commas or newlines (as defined above). An example of a record using a secondary-delimeter pair for the second field of the three-field record is given:
   `Hello!,"When, where\nand why",vape?` `48656C6C6F212C225768656E2C2077686572652C0A616E6420776879222C766170653F0A`
   `H e l l o ! , " W h e n , w h e r e ,\n a n d w h y " , v a p e ?\n`
   `└── ┴┴ ┴┴ ──┘`
   `opening embedded embedded closing`
   `delimeter comma newline delimeter`

   The secondary delimeters enclose the data of the field: `,".....",` and have the effect of dereferencing those special characters, which are then interpreted as plain text within the field.

#### A Note On Creating CSV Files With Secondary Delimeters

The CsvView application includes the functionality to create CSV files from a plain-text source file. (see csv create option) The CSV file is created using the desired UTF encoding and newline format.

Commas and newlines within a CSV file are interpreted as field-delimeter and end-of-record, respectively. However, these characters may be interpreted as ordinary text IF they are enclosed within secondary delimeters as described above.

Within the source file used to create CSV output, a comma embedded within secondary delimeters is automatically identified during conversion; however, because the newline character is a “special” character (i.e. a control character) within a plain-text file, it must be handled as a special case.

The design decision was made that within a source file used to generate CSV files, embedded newlines are designated using a sequence of two ordinary `ASCII` characters:
`backstroke: '\' plus a lower case n: 'n'`
During creation of the CSV file, this sequence is converted to a newline character as defined above.

Comment lines may be used within the source file and will be ignored by the conversion algorithm. Comments are identified by using the hash character (’#’) as the first character of the line. When the hash character is encountered, the entire source line will be discarded.

Technical Note: Secondary delimeters must not be used in the first record of the source file (header record). This is because when scanning the first record of a CSV file, the type of encoding has not yet been determined.

Technical Note: It is possible that some designers of CSV files will attempt to be “creative” by using a character other than the double-quote character to create secondary-delimeter pairs. Some examples would be the astrisk `'*'` or the semicolon `';'`. CsvView does not support this kind of “creativity”, but if you often encounter such constructs, the `'convertDoubleQuotes'` and `'dqDelimeterCount'` methods could be generalized to accomodate such constructs.

### Build CsvView from Source

#### Tools

The `CsvView` demonstration application and the `AnsiCmd` library upon which it is built, are written in C++ and are built with the GNU C++ compiler and linker. No additional link libraries or third-party tools are needed.

GCC (G++) version 7 and above with support for C++17 (gnu++17) or greater.

#### Compiling

The make file, `'Makefile'` includes several options for building the application.

Examples: gmake all — Execute all other options in sequence gmake clean — Delete the executable and object files gmake refreshlib — Copy the necessary files from parent directory gmake — Build out-of-date source files and re-link

#### Build Options

The `AnsiCmd` library has two(2) global directives which affect conditional compilation of the library.
`1) DEBUG_ANSICMD` Enable or disable debugging methods and data.
`2) INCLUDE_API` Include the high-level `API` methods and data.

Both of these conditional-compile directives should be set to zero (’0’) when building the `AnsiCmd` library (`gmake buildlib`).
While neither directive affects the functionality of the `CsvView` application, disabling them will reduce the size of the executable by approximately 600 Kbytes.
Please see Build Options for the `AnsiCmd` library for more information about conditional compilation.

1. DEBUG_CSVV – Global control of debugging code for the application. Various condition-compilation directives for debugging are defined for individual methods, and when the `DEBUG_CSVV` directive is set to zero (’0’), all of the following directives will also be disabled.
   1. DEBUG_PF – Defined in the `'SrcScan'` method and used to control code for parsing the fields of a record.
   2. DEBUG_RR – Defined in the `'readRecord'` method, this directive controls debugging output for the rather complex task of reading a single record from a CSV-formatted file.
   3. DEBUG_isUTF16 – As the name implies, this directive is defined in the `'isUTF16'` method which scans the first record of the source file to determine whether the file is encoded as UTF-16 data.
   4. DEBUG_B2W – Defined in the `'convert2UTF16'` method, this directive reports intermediate information for conversion from UTF-8 to UTF-16 data.
   5. DEBUG_CNL – Defined in the `'convertNewlines'` method, this directive reports on the process of converting linefeed characters to carriage-return/linefeed pairs.
   6. DEBUG_DNL – Defined in the `'deflateNewlines'` method which complements the `'convertNewlines'` method by converting carriage-return/linefeed pairs to linefeed characters.
   7. DEBUG_isUTF8b – Defined in the `'isUTF8bom'` method, this directive reports the intermediate steps in determining whether the source CSV file contains a UTF-8 byte-order mark (BOM).
   8. DEBUG_CDQ – Defined in the `'convertDoubleQuotes'` method, this directive reports the intermediate steps in processing double-quotation-mark characters which are used as secondary delimeters within a field.
      Please see Secondary Field Delimeters for more information on secondary delimeters.
   9. DEBUG_GCLA – Defined in the `'GetCommandLineArgs'` method, this directive enables reporting on parsing of the application’s command line arguments.
   10. DEBUG_VP – Defined in the `'DisplayData'` method, this directive inserts visible characters (’-’) instead of whitespace for padding fields to their full width.

#### Testing the Build

To test the build, invoke with a request for the CsvView version number. You should get something similar to the following:

./csvv --version CsvView (csvv) v:0.0.06 Copyright(c) 2024-2026 The Software Samurai ======================================================================= AnsiCmd Link Library v:0.0.07 (gString v:0.0.37) ----------------------------------------------------------------------- License GPLv3+: GNU GPL version 3 <http://gnu.org/licenses/gpl.html> This is free software: you are free to modify and/or redistribute it under the terms set out in the license. There is NO WARRANTY, to the extent permitted by law.

If you have forgotten to disable the `AnsiCmd` library debugging code, and/or the `AnsiCmd API-level` code (see above), a warning message will be appended to the above output.

## AcEdit Demo App

### Introduction to AcEdit

Documentation for the `'AcEdit'` demo application is under construction.

The `AcEdit` application is designed as a platform for testing the high-level functionality of the `AnsiCmd library`, and for demonstrating various approaches to building applications based on the `AnsiCmd` library.
For details, see AnsiCmd Link Library at the top of this document.

`AcEdit` is a console application, meaning that it runs within a terminal window.

`AcEdit` is not designed to be a full-featured text editor, although subsequent releases may approach full functionality.

#### AcEdit Features

1. `AcEdit` is invoked like any command-line utility, although the data are not displayed as `TTY` output. Instead, `AcEdit` is a windowed application, visually similar to an application built on the `"ncurses"` library, but vastly more simple in design and execution than an `ncurses` application.
   Please visit the author’s website for wide variety of applications which are built on the `ncurses` library.

   Please see Invoking AcEdit for a discussion of all command-line options.

2. Configuration of `AcEdit` is performed by reading the `ace.cfg` configuration file on startup.
   Please see AcEdit Configuration for more information.
3. Multiple files may be edited simultaneously, so copy and paste among the files via a “local” (application-specific) clipboard is straightforward.

   Access to the system clipboard is enabled by default, so data may be seamlessly transferred between `AcEdit` and other active applications.
   See AnsiCmd Clipboard Access for a discussion of the system clipboard interface.

4. `AcEdit` is designed as a multi-language application. Two languages are initially supported: English and Chinese (simplified). All LTR (left-to-right) character sets are supported.

   Support for RTL languages is too complex for this demonstration app; sorry about that. Please see the author’s `NcDialog API` which includes full support for both LTR and RTL languages.

#### Building the Application

The application is based on the author’s `AnsiCmd` link library. The library is fully self-contained and the build requires only the GNU compiler and its standard dynamic-load libraries.
(The compiler version must support the `C++17` functionality which became available in GCC v:7.
See Build AcEdit from Source for details.

A local clipboard is built into the library; however, access to the system clipboard requires the `wl-clipboard` package which is available for downlad on most distribution sites.

### Invoking AcEdit

This chapter lists the command-line options for invoking the `AcEdit` (ace). The `'help'` and `'version'` options override all other specified options.

For a detailed discussion of the `AnsiCmd` terminal setup options used for applications based on the `AnsiCmd` link library.
please see Invoking - Terminal Setup.

#### Summary of Options

> OPTION | DESCRIPTION
> --- | ---
> ace color option | application color attributes
> ace language option | user interface language
> ace dimensions option | application height/width
> ace help option | Display all application options
> ace helpless option | Same as `'--help'` option except pipe through `'less'`
> ace version option | Reports AcEdit version number and copyright info.
> `---` Development Options `---` | `------------------`
> ace test option | Sandbox (testing only)

All parameters are optional, and may be specified in any order.

For each option that requires one or more arguments, the option name and its argument(s) may be separated by either `'='` or `' '` (space).
Note that if the argument contains whitespace, then the entire argument sequence must be enclosed within single-quotes or double-quotes.
This prevents the terminal’s shell program from “interpreting” your argument formatting.

Parsing of command line options requires at least the first six(6) characters of the option token.
For instance, the `"--language"` token is fully identified by the first six characters: `--lang"`.

Avoid specifying the same option multiple times. Multiple instances of an option may cause unpredictable results.

#### Invocation Options

> Specify file(s) to be edited:

1. Any parameter that does not begin with a dash, ‘–’ character) is interpreted as a filename specification.
   1. Specify the filename only, which will be interpreted as a file located in the current working directory (CWD).
      Example: `ace strip_cr.pl`
   2. Specify a path relative to the CWD.
      Example: `ace "../../Perl Utilities/strip_cr.pl"`
   3. Specify a full filespec.
      Example: `ace "/home/sam/Documents/Perl Utilities/strip_cr.pl"`
2. Environment variable substitutions and special filespec characters are supported.
   `Example: ace ~/Videos/DVD_List.txt`
   `ace '${HOME}/Videos/Blu-ray/Videos With Subtitles.txt'`
   `ace ./Subtitles.txt`
3. Symbolic links are followed. Example: `ace WkExer.lnk`
   with the link referencing `~/Documents/Weekly_Exercise.txt`.
4. Note that the names of files edited in previous sessions will have been stored in the configuration file.
   If the file was open for editing when the application was closed, it will automatically be re-opened on application startup.
5. If a filename specified on the command line duplicates a filename saved in the configuration file, the duplicate name will be discarded.
6. Only “regular” text files may be edited using `AcEdit`. For example: Bash scripts, Perl, C, C++, HTML, XML, etc.
   Binary files and complex files such as LibreOffice documents will be rejected for edit.

– –color=BORDER_FG:BORDER_BG[,TEXT_FG:TEXT_BG[,HILITE_FG:HILITE_BG] Application color attributes.

> 1. Border attributes must be specified.
> 2. Text-field and cursor-row attributes are optional
> 3. Application’s default value is indicated by zeros for both foreground and background values:
>    `Example: --color=f00:f00,f10:f04`

> Note that selecting a color scheme should normally be done in the configuration file. See AcEdit Configuration.

> Command line specification of color attributes mirrors the syntax of the config file; and while this makes for efficient coding, it is certainly not user friendly. The option sequence is as follows:

>     --color=Border_FG:Border_BG, Text_FG:Text_BG, Hilite_FG:Hilite_BG
>        │     │         │          │       │        │         │
>        │     │         │          │       │        │         │
>        │     │         │          │       │        │         └ cursor row background
>        │     │         │          │       │        └ cursor row foreground
>        │     │         │          │       └ text field background
>        │     │         │          └ text field foreground
>        │     │         └ border background
>        │     └ border foreground
>        └ option name

> The color options correspond to the terminal color registers for 4-bit palette (16 colors), 8-bit palette (256 colors) and 24-bit palette (RGB).

> Each specified attribute consists of a single character (case insensitive), followed by an integer value.
> Foreground/Background pairs are seperated by a colon `':'`.
> Color pairs are seperated by a comma `','` (and optional whitespace).

>        Palette:  Character:  Value Range:
>        --------  ----------  ------------
>        4-bit       f         00 - 15
>        8-bit       e         16 - 231
>        24-bit      r         00 - 252

>        EXAMPLES:  ace --color="f12:f03"
>                   ace --color="f00:e38, e16:e21"
>                   ace --color="f12:f03, r108:r216, r108:r252"

> Please refer to the color chart in the configuration file, or
> see AcEdit Configuration for additional information.

– –language=[en | zh | te] User Interface Language.

> Specify the user interface language for the application.

> `AcEdit` is designed specifically for multi-language support. The menus, dialogs and most informational messages are provided in each supported language. An example would be the “Help About” dialog.

> > ┌────────────────────────────────────────────────────────────────┐ │ AcEdit (ace): Copyright (c) 2023-2026 v:0.0.05 │ │ The Software Samurai │ │ http://www.SoftwareSam.us/ │ │ │ │ This application is based upon the author's AnsiCmd library │ │ which implements the ANSI escape sequences available within a │ │ Linux terminal window. It is not intended as a full-featured │ │ text editor; but rather is a testing platform for the AnsiCmd │ │ library and the ACWin and ACDlg classes within the library. │ │ AnsiCmd v:0.0.07 WaylandCB v:0.0.06 │ │ gString v:0.0.37 wl-clipboard v:2.2.1 │ │ OK │ └────────────────────────────────────────────────────────────────┘
> > ┌─────────────────────────────────────────────────────────┐ │ AcEdit (ace): Copyright (c) 2023-2026 v:0.0.05 │ │ The Software Samurai (软件武士) │ │ http://www.SoftwareSam.us/ │ │ │ │ 该应用程序基于同一作者的 AnsiCmd 库。该库实现了 │ │ Linux 终端窗口内可用的 ANSI 转义序列。它并非一个 │ │ 全功能的文本编辑器；而是一个 AnsiCmd 功能的测试平台。 │ │ AnsiCmd v:0.0.07 WaylandCB v:0.0.06 │ │ gString v:0.0.37 wl-clipboard v:2.2.1 │ │ .好的 │ └─────────────────────────────────────────────────────────┘

> The current release supports two languages:
> `1) English`
> `2) Zhōngwén, 中文` (Chinese, simplified)
> By default, the application uses the language specified in the terminal environment if that language is supported. If the language specified in the environment is unsupported, English will be the fall-back language.

> Hooks for additional languages are provided, so additional languages may be added as desired.

>        EXAMPLES:  ace --language=zh     // Zhōngwén interface language
>                   ace --language=en     // English interface language
>                   ace --language=te     // Use language specified in
>                                         // terminal environment
>                   ace                   // language automatically taken
>                                         // from terminal environment

> Technical Note: The command-line code for taking the language from the terminal environment is `"te"`. This is technically the code for Telugu, a Dravidian language of south-eastern India. If an enterprising programmer from Telangana builds an application that supports Telugu, then we will be happy to assist in making modifications to our code.
> తెలుగు ఒక అందమైన లిఖిత భాష.

– –dimensions Report dimensions of terminal window.

> Report the terminal window dimensions (rows and columns), then exit.

> This option can be used when updating the configuration file to specify the application dimensions to be used on startup.

The “Sandbox” is the traditional name for a section of the application code which can be used for testing new functionality without disturbing the functional code.

The AcEdit application accesses code within the Sandbox using the `--test` command-line option. To invoke a specific test, provide the test number: `ace --test=[0|1|2|3]`. These tests numbers are reserved for ad-hoc tests.

Depending on build options, the Sandbox may also contain several pre-constructed test routines for use during regression testing.
For a list of available tests, invoke without specifying a test number: `ace --test`

Example: Development Test Menu 00, 01, 02. 03 - Temporary Tests 11 - Test updateFocus/updateText methods 12 - Timestamp Formatting 13 - Terminal Configuration 14 - skField Text Formatting Options 15 - Report locale settings 99 - This Menu Press any key to exit...
– –help (or –h) Display command-line help.

> Command-line Help. Display a brief summary of command-line usage and options.
> (overrides everything on command line except `'--version'`)

>        EXAMPLES:  ace --help
>                   ace -h

– –helpless (or −hl) Display command-line help.

> Display command-line help. Same as the `'--help'` option above except that the help menu will be piped through the `'less'` utility.

>        EXAMPLES:  ace --helpless
>                   ace -hl

– –version Report AcEdit version number.

> Display the `AcEdit` version number and copyright information.
> (overrides everything else on the command line)
> The AnsiCmd-class and gString-class version numbers are optionally reported by appending the letter `'V'` (verbose) to the command.

> EXAMPLE: ace --version AcEdit (ace) v:0.0.05 (c) 2023-2026 The Software Samurai ================================================================================ License GPLv3+: GNU GPL version 3 <http://gnu.org/licenses/gpl.html> This is free software: you are free to modify and/or redistribute it under the terms set out in the license. There is NO WARRANTY, to the extent permitted by law. EXAMPLE: ace --versionv AcEdit (ace) v:0.0.05 (c) 2023-2026 The Software Samurai ================================================================================ AnsiCmd Link Library v:0.0.07 (gString v:0.0.37) -------------------------------------------------------------------------------- License GPLv3+: GNU GPL version 3 <http://gnu.org/licenses/gpl.html> This is free software: you are free to modify and/or redistribute it under the terms set out in the license. There is NO WARRANTY, to the extent permitted by law.

### AcEdit Dialogs

#### TEMP - EXPERIMENTAL

Documentation for the `'AcEdit'` demo application is under construction.

#### User Interface Dialogs

CZONE - AcEdit User Interface Dialogs

#### Crash Recovery

All applications, even you humble author’s applications, will occasionally experience an uncontrolled shutdown, either through a system error or (gasp!), due to programmer error. This is primarily due to the developer underestimating the absolute stupidity of the user.

When an application crashes for whatever reason, it is possible that it will leave behind some potentially recoverable data. The `AcEdit` application is no exception.

On the next startup following an uncontrolled exit, `AcEdit` scans for orphaned temporary files and if found compares them with the associated source files and asks the user how to handle the recovered data.

The following example demonstrates the dialog window used to obtain the user’s decision. In this case, an uncontrolled exit was simulated by manually creating a temporary backup file associated with the file under edit, namely:
`Welcome_To_AcEdit.txt`
The backup file is a “hidden” file located in the same directory as the file under edit, and takes it name from the source file:
`.#Welcome_To_AcEdit.txt#`
This naming convention is similar to that used by other text editors, and is useful in recovering data abandoned in an application crash.

The dialog reports the names of the source and recovered files, as well as the last modification timestamp and file size for each file.
In this example, the recovered file is about three minutes newer than the source file and is a different size. This indicates that the recovered file may contain useful data. The available options are shown.
First, select one of the four Radiobuttons and then press the `CONTINUE` Pushbutton; or none of the options matches your needs, select the `EXIT` Pushbutton to abandon the recovered file without modification.

1. Compare the two files.
   Invoke the `'diff'` utility to format the contents of the files for side-by-side display. The data are displayed using the `'less'` utility. (Press ’q’ key to close `'less'` and return to the dialog.)
2. Save the recovered file as "Recovered_nn.txt".
   Rename the recovered file. The original source file is not modified.
   Because multiple files may have been orphaned by the previous application crash, to prevent accidental overwrite of another file, a serialized filename format is used where the `"nn"` is replaced by a two-digit serial number: `Recovered_01.txt, Recovered_02.txt,` etc. The renamed file can then be moved, renamed or opened for editing if desired.
3. Replace the source file with the recovered file.
   If it is determined that the recovered data are more complete than the source file, then the original source file will be renamed as a backup file, and the recovered file will be renamed as the source file.
   `Welcome_To_AcEdit.txt --> Welcome_To_AcEdit.txt~`
   `.#Welcome_To_AcEdit.txt# --> Welcome_To_AcEdit.txt`
   No data are lost. Note that the appended tilde character (`'~'`) is recognized by Linux system as indicating a “backup” file.

   The recovered file will then be opened as if it were the original source file. The old source file remains in the current directory and can be saved or discarded, as desired.

4. Discard the recovered temporary file.
   If it is determined that the data in the recovered file are of no practical value, use this option to delete the recovered file.

After the desired operation has been performed, a status message will be displayed, and then the dialog will wait for the next keystroke before closing.

┌────────────┤ Recover Data From Abnormal Shutdown ├───────────┐ │ │ │ Source File : Welcome_To_AcEdit.txt │ │ Last Modified: 18 Oct 2025 17:12:33 Size: 628 bytes │ │ Recovered File : .#Welcome_To_AcEdit.txt# │ │ Last Modified: 18 Oct 2025 17:15:22 Size: 681 bytes │ │ ─────────── ─────────── ─────────── ─────────── ─────────── │ │ [♦] Compare the two files. │ │ [ ] Save the recovered file as “Recovered_nn.txt” │ │ [ ] Replace the source file with the recovered file. │ │ [ ] Discard the recovered temporary file. │ │ │ │ CONTINUE EXIT │ │ │ └──────────────────────────────────────────────────────────────┘

You can test this functionality without actually needing to cause a crash simply by: 1)closing the application, 2)copying any file that was open for edit using the filename format described above, and then 3)reopening the application:
`./ace MyApp.cpp`
`Close the application`
`cp --preserve=all 'MyApp.cpp' '.#MyApp.cpp#'`
`./ace`
On startup, the backup file will be recognized, and the recovery dialog will be automatically invoked as described above.

#### FileMan - File Management Class

While the `AcEdit` application is designed as a test and demonstration app for the `AnsiCmd` library, and specifically for the `ACWin and ACDlg` classes, it reaches a few centimeters into the realm of an actually useful console application.

File management within the application is done through an array of `FileMan` records, one for each file under edit.
While a large number of files can simultaneously be open for edit, the number of files which are currently visible is limited by the number of visible edit fields.
Full-window mode: The “active” FileMan record references the file displayed in that field.
Dual-window mode: The “active” FileMan record references the file in the field that has the input focus, and the “inactive” FileMan record references the file displayed in the field which is visible, but does not have the input focus.
Other open (or recently closed) files are reference by other members of the FileMan array. Please see AcEdit Menu System for information on navigating among the files which are open for edit.

#### FileMan Class Data Members

1. tnFName tnf: Source file stats data.
   The data include owner of the file, file type, timestamps, access flags and other data which identify the file within the filesystem.
2. char srcSpec — Source fileSpec:
   Filespec of source file. The file may currently be under edit, OR may have recently been under edit.
3. char wrkSpec — Working copy fileSpec
   Filespec for working copy of source file. This is a “hidden” file located in the same directory as the source file. It is an intermediate buffer between the text being edited and the source file. It is used for auto-save operations and miscellaneous updates; thus protecting the source file from possible corruption due to system problems or !gasp!, program error.
4. fldIndex tindx — TextEdit Index
   Index of the TextEdit control in which file data are currently displayed.
   (Initialized only for “active” records.)
5. fldIndex lindx — Line number Index
   Index of the LineNumber control associated with `'teindx'`.
   (Initialized only for “active” records.)
6. char* scr — Scratch buffer
   for tracking miscellaneous data during file edit.
   This is a pointer to dynamic allocation.
   1. [NOT YET DEFINED]
   2. [NOT YET DEFINED]
   3. [NOT YET DEFINED]
7. int32_t scrCnt — Source Count
   Number of bytes allocated for the `'scr'` buffer.
8. int vtop — Vertical Top row:
   This is the (1-based) line number of top visible data row in TextEdit control.
   1. If the source file was referenced in config file, then this value is initialized from data in the config file.
   2. Afterwards, it tracks the line number of the data row displayed at the top of the field and when updating the LineNum field.
   3. When file is closed (or application is closed) this value is stored in the config file record for the file.
9. int voff — Vertical Offset: Vertical offset from `'vtop'` to cursor line.
   This value is used to indicate the cursor position when updating the gutter field.
   1. If the source file was referenced in config file, then this value is initialized from data in the config file.
   2. Afterwards, it tracks the offset from the top display row to the row containing the cursor.
   3. When file is closed (or application is closed) this value is stored in the config file record for the file.
10. int hoff — Horizontal Offset:
    Character (not column) offset from first character of cursor row to IP (Insertion Point).
    This value is used to indicate the cursor position when updating the gutter field.
11. int sindx — Source Index:
    Index of FileMan record from which the live FileMan data were retrieved.
    When the data are copied from one record to another, the index of the source record is stored in target record so that it can be copied back later, either when the file is closed by the user, or when the application exits.
    (Initialized only for “active” records.)
12. bool open:
    Set if source file is currently open or is to be opened on startup.
    Note that “open” in this case does not mean that the source file is literally open. It means that the data of the file are currently (or about to be) under edit. The source file is opened periodically, and only long enough to save updates and then is immediately closed to ensure data integrity.
13. bool mods:
    Set if TextEdit field data are newer than working copy of the file (’wrkSpec’). This indicates that a save to target file is pending.
14. bool wmods:
    Set if working copy of file (`'wrkSpec'`) is newer than the source file (`'srcSpec'`). This indicates that a save to source is pending.
15. bool active:
    Set when the data of the FileMan record is actively being used during file edit (dynamically updated in response to user interaction).
16. int64_t extime — External access Time:
    Timestamp when file was most recently updated by the application.
    Used on startup to determine whether file has been modified by another application.

### AcEdit Configuration

#### Introduction

The `AcEdit` application startup sequence is built around a configuration file, `ace.cfg` by default. This file provides definitions for initialization of application dimensions, position, color attributes, shortcut keycodes, a list of previously open files and other setup information.

The configuration algorithm is not yet fully implemented. For the current release (0.0.05), the configuration file is read on startup, but is not updated on exit.

#### TEMP - EXPERIMENTAL

Documentation for the `'AcEdit'` demo application is under construction.

### Build AcEdit from Source

#### TEMP - EXPERIMENTAL

Documentation for the `'AcEdit'` demo application is under construction.

## TFMTest Demo App

`'TFMTest' (tfmtest)` is a simple test and demo application supporting the TFMan (Temporary File Management) class.

### The TFMTest Application

`TFMTest (tfmtest)` demonstrates the use of the `TFMan` class, which encapsulates creation and management of any temporary files required by an application.
The next chapter, TFMan Class describes the class itself.

- `TFMTest` is a stand-alone utility designed for stress-testing the methods of the `TFMan class`.
- This application does not use the AnsiCmd library. Output is written directly to `stdout`.
- Each of the public methods of the TFMan class is exercised by this application.
- Text analysis and formatting within the application is done through the author’s gString class.
  See gString Text Tool for more information.
- Support for C++17 (g++ v:8 and higher) is required.
  Please see Building TFMTest below for details on building the application.

Invoking TFMTest

`TFMTest ('tfmtest')` requires one option, either `--basic` or `--full`. Other options are optional :-).

- `--basic`
  Perform basic tests of the temporary-file system. This ensures that the application and the `TFMan` class are functioning and communicating with the system as expected.
- `--full`
  First, the sequence of basic tests is performed, and then additional tests are performed to ensure that all public methods of the `TFMan` class are functional and that the C-standard library functions are interacting with the system as expected.
- `--verbose`
  Output verbose diagnostics for each non-trivial test.
  Significant redundancy is built into these tests to ensure that the system is not lying to us. Verbose output simply reports the information generated by this redundancy, for example, the timestamps of the files which are created.
- `--redirect`
  The application writes directly to `stdout` by default; however, the output may be rediected (piped) to the `'less'` utility so that the data may be scrolled for easy viewing.

  This redirection is not actually necessary because the full, verbose report only requires approximately 25 lines, and should fit comfortably in a typical terminal window. The pipe mechanism is used here to fulfill a student request for a simple example of how pipes work. Enjoy, Sarah!

- `--help` (or `-h`)
  List the available command-line options, (this list).
- `--version`
  Report the application version number and copyright notice.
  The report also includes the version numbers of the `TFMan` class and the `gString` class.

Building TFMTest

    Development Tools:
    ------------------
       g++ (GCC) 14.3.1 20251022 (C++17)
       Fedora Linux v:42
       GNOME Terminal v:3.54.5 (GNOME 47)

1. Open a terminal window.
   The `TFMTest` application source is located in a subdirectory of the `AnsiCmd` library distribution archive. Download the archive, open a terminal window and navigate to the directory containing the archive.
   Example:
   `cd ~/sam/Documents/Software`
   Unpack the archive:
   `tar -xjvf ansicmd-x.x.xx.tar.bz2`
2. Navigate to the directory containing the TFMTest source.
   `cd AnsiCmd/TFMTest`
3. The directory should contain two files:
   `TFMTest.cpp // Application source code.`
   `Makefile // Build the TFMTest application`
   `ls -l`
   Additional files will be copied from the parent directory during the build sequence.
4. Be sure that your compiler version is 8.0 or greater (or Clang v:5). `g++ --version`
   `g++ (GCC) 14.3.1 20251022 (Red Hat 14.3.1-4)`
5. Build the `'tfmtest'` application.
   `gmake all`
   Three files will be copied from the parent directory:
   `TFMan.hpp`
   `gString.cpp`
   `gString.hpp`

   The `TFMTest and gString` modules will be compiled and then linked to create the `'tfmtest'` executable.

   The build should be clean with no errors and no warnings. If there are errors, then the most likely cause would be that the compiler cannot find a necessary header file or library. Check your LIB_PATH and other environment variables.

6. Once you have a clean build, invoke the application with a request for version number.
   `./tfmtest --version`
   1. If the application successfully reports the version number and copyright notice, then the application has been built correctly.
   2. If the application does not run, then verify that all necessary libraries are installed on your system. Run the ’ldd’ command to list the necessary libraries. The needed libraries will look something like the following. These are all standard libraries which should be installed on your system by default.

          [TFMan]$ ldd tfmtest
             linux-vdso.so.1 (0x00007f9ca33f5000)
             libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f9ca3000000)
             libm.so.6 => /lib64/libm.so.6 (0x00007f9ca32ef000)
             libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f9ca32c0000)
             libc.so.6 => /lib64/libc.so.6 (0x00007f9ca2e0d000)
             /lib64/ld-linux-x86-64.so.2 (0x00007f9ca33f7000)

### TFMan Class

The `TFMan` (Temporary File Management) class is desigined to fascilitate creation, deletion and general management of temporary files used within an application.

Temporary files created by the system are defined as uniquely named files created within the system’s shared temporary-file directory. Standard library functions are available for creating these files, but the author’s experience in the classroom setting has shown that application management of these files can be haphazard (to put it politely). The `TFMan class` was created to inject a bit of organization into this chaos.

System Interface

The system interface functions of the C++ standard library used by the TFMan class require C++17 support. Be sure that your compiler version is 8.0 or greater (or Clang v:5).

These functions are available in C++17 (released Jan. 2018):
`const char* fs::temp_directory_path ( void ) ;|{@*
@verb{| const char* fs::temp_directory_path ( std::error_code& ec ) ;`

These functions return the filespec of a directory suitable for temporary files. The path is guaranteed to exist and to be a directory. The overload that takes error_code& argument returns an empty path on error.

On POSIX systems, the path may be specified in an environment variable: `TMPDIR, TMP, TEMP, TEMPDIR,` and, if none of them are specified, the path `"/tmp"` is returned by the system call.

Please visit: `<http://en.cppreference.com>` for more information on the library functions.

In the author’s FileMangler application, which was developed well before C++17 was released, we implemented a literal interpretaton of the above description. Now that the development community has had time to upgrade their compilers, (gcc v:8 and above) we are able to use the library function to obtain the temp-directory path.

Note that the TFMan class does not accept the system’s assurances that the target exists and is a directory. That information, including user’s read/write access, is independently verified.

Requesting a unique hack-resistant filename for a temporary file

The library function:
`char * mkdtemp (char *TEMPLATE);`
is used to create a subdirectory within the system temp-file directory. This function returns the uniquely-named directory in which all other application temporary files will be located.
This makes cleanup of temporary file during application exit as simple as calling the TFMan destructor.

1. The ’mkdtemp’ function returns a random sequence of characters for the filename: Example: `"sakJhr"`
2. A constant prefix may be attached to the provided character sequence to enable easy identification of the subdirectory during application development. Example: `"ANSICMD_sakJhr"`.
3. An alternate prefix string may be specified using the `'prefix'` parameter. Example prefix: `"SAM"` would yield the subdirectory name: `"SAMsakJhr".`

The library function used to create the individual temp files is:
`int mkstemp (char *TEMPLATE);`

Note that both `mkdtemp` and `mkstemp` are `"atomic"`, that is, file creation by one process may not be interrupted by another process.

Technical Note: It is assumed that only non-special filename characters will be used on the temp-file-path. "Special characters" are those which may be interpreted by the shell or other system functionality as requiring special handling.

    List of Special Characters:
      '\'  '"'  ''' '?'  ':'  ';'  '&'  '>'  '<'  '|'  '*'  '`'  '$',
      '#'  '+'  '=' '%'  '!'  '~'  '{'  '}'  '@'  '('  ')'  '['  ']',  ' '

These special character should not be used in filenames. The algorithm for escaping these characters is slow and probably not worth the complexity in this context.
Please see notes in the author’s FileMangler application. FMgr-class on using `'rmdir'` and `'unlink'` on filenames which contain `"special"` characters.

Within the application’s temp-file subdirectory, temporary files take the form: "TF_xxxxxx" where "TF_" is the specified prefix and the "xxxxxx" sequence is replaced by the unique system-provided sequence.

#### Public Methods of the TFMan Class

`TFMan` is a very simple class with the following public methods.

- TFMan ( void );

        Input  : none
        Returns: implicitly returns pointer to object

  Default constructor.
  Create a uniquely named temp-file subdirectory within the system’s temp-file directory. (Prefix for temp-file subdirectory name is set to default value: "TFMAN_".)

  Example tree structure: `/tmp/TFMAN_sakJhr`

- TFMan ( const char* prefix );

        Input  :
           prefix : pointer to a prefix for temp-file subdirectory name.
                    -- Valid filename characters only
                    -- Maximum of 16 bytes including null terminator
        Returns: implicitly returns pointer to object

  Initialization constructor.
  Create a uniquely named temp-file subdirectory within the system’s temp-file directory using the provided prefix string for the subdirectory name.

  Example:
  `instance: TFMan* tfm = new TFMan( "MYAPP" );`
  `yields: /tmp/MYAPPsakJhr`

- ~TFMan ( void );

        Input  : none
        Returns: nothing

  Destructor.
  Delete all temporary files located within the subdirectory created by the TFMan constructor, then delete the subdirectory itself.

  The destructor is invoked in different ways, depending upon whether the TFMan object was created in `'stack'` (automatic) memory or from `'heap'` memory.

  If the TFMan object is created on the `'stack'`, then the destructor is called implicitly when the object goes out-of-scope.

  int doStuff ( void ) ; int main ( int argc, char* argv[], char* argenv[] ) { tfm = new TFMan ( "SAM_" ) ; doStuff () ; if ( tfm != NULL ) delete tfm ; } int doStuff ( void ) { TFMan tfm ( "SAM_" ) ; int status = 0 ; . . . return status ; // (the object goes out-of-scope here) }
  ── ── ── ── ── ── ──

  If the TFMan object is created in `'heap'` memory (dynamic allocation), then the object should be deleted explicity when it is no longer needed.

  int doStuff ( void ) ; static TFMan *tfm = NULL ; int main ( int argc, char* argv[], char* argenv[] ) { tfm = new TFMan ( "SAM_" ) ; doStuff () ; if ( tfm != NULL ) delete tfm ; }

  Teacher’s Rant: Note that the application’s heap memory is automatically returned to the system when the application exits; HOWEVER, it is sloppy programming, indeed to simply abandon objects on the heap. Objects on the heap should always be deleted explicity before exiting the application.

- bool createTempFile ( gString& tmpPath );

        Input  :
           tmpPath : (by reference) gString object to receive filespec
        Returns:
           'true'  if file successfully created:
                   (file exists, and contains no data)
           'false' if system call failed

  Create a uniquely-named temporary file.
  The filename takes the form: `"TF_xxxxxx"` where `xxxxxx` is the six-character token which uniquely identifies the file created by the system.

  Example: If the TFMan constructor has created the application subdirectory: /tmp/TFMAN_rQabnE then the filespec of the temporary file would be of the form: /tmp/TFMAN_rQabnE/TF_saNAar

  The full filespec is then returned to caller in `'tmpPath'`. The application can then open the file in the usual way and write data to the (empty) file.

  ofstream ofs ( tmpPath.ustr(), ofstream::out | ofstream::app ) ; if ( (ofs.is_open()) ) { ofs << "Write some data to the temp file." << endl ; ofs.close() ; }

  Notice that the gString object’s UTF-8 (byte-oriented) text is used for the system call. Note also that because the file has been created by the call, the file may be opened either for “append”, or for “trunc” output.
  Please see gString Public Methods for a discussion of the string data stored in the gString class.

  Please see above for a description of how the system creates uniquely-named temporary files, or refer to the C standard library documentation for the `'mkstemp'` function.

- bool deleteTempFile ( const gString& tmpPath );

        Input  :
           tmpPath : (by reference) filespec of file to be deleted
        Returns:
           'true'  if target file successfully deleted
           'false' if library call failed (invalid filespec)

  Delete a previously created temporary file.

  `deleteTempFile` will delete the specified file ONLY if the file resides within the temporary subdirectory created by the `TFMan` constructor.

- bool clearTempFiles ( void );

        Input  : none
        Returns:
           'true'  if all target files successfully deleted
           'false' if unable to delete one or more target files

  Delete all files in the application’s temp-file container subdirectory.
  Only files created within the subdirectory created by the TFMan-class constructor are affected. The application-specific subdirectory created by the TFMan constructor IS NOT deleted by this method.

- const char* getTempPath ( void );

        Input  : none
        Returns: pointer to const buffer containing filespec

  Returns a pointer to the filespec of temp-file subdirectory created by the TFMan constructor. This is a read-only pointer!

  This method may be used during application development to locate the application’s temp files.

- bool isActive ( void );

        Input  : none
        Returns:
           'true'  if temp-file manager initialized and functional
           'false' if initialization failed

  Report the active/inactive status of the TFMan object.
  Although it is unlikely that the constructor will fail to create the target subdirectory, if the system call fails, the constructor has no way to report the error. This method may be used to verify that the TFMan temp-file manager is active and functional.

      Example:
        gString gsFilespec ;
        TFMan* tfm = new TFMan( "MyApp" ) ;
        if ( (tfm->isActive()) )
        {
           tfm->createTempFile ( gsFilespec ) ;
           . . .
           tfm->deleteTempFile ( gsFilespec ) ;
        }
        delete tfm ;

- const char* tfmVersion ( void );

        Input  : none
        Returns: pointer to constant string of the form: "M.m.ss"
                 indicating the major/minor/step versions

  Report the TFMan-class version number.

      Example:
        TFMan* tfm = new TFMan( "SAM_" ) ;
        cout < "TFMan class version: " << (tfm->tfmVersion()) << endl ;
        . . .
        delete tfm ;

      Output:
        TFMan class version: 0.0.02

## Technical Support

Please Note: All trademarks and service marks mentioned in this document are the entirely-too-proprietary property of their respective owners, and this author makes no representation of affiliation with or ownership of any of the damned things.

### Contact

AnsiCmd-class library, test applications, source code and associated Texinfo documentation were written and are maintained by: Mahlon R. Smith, The Software Samurai Beijing University of Technology on the web at: www.SoftwareSam.us For bugs, suggestions, periodic updates, or possible praise, please post a message to the author via website. The author wishes to thank everyone for their intelligent, kind and thoughtful responses. (ranters I can live without)

### By the Same Author

- NcDialog Application Programming Interface (API) library.
  The NcDialog API forms the basis for most of our other software projects. It provides the application developer with the tools to create dialog-based console applications, without the need to learn anything about the complexities of the underlying ‘ncurses’ C-language library.

  Console applications have always been the most efficient and easily-implemented of computer programs. What they lacked was a friendly and visually-pleasing user interface.

  With the NcDialog API, console applications can now be used and understood by experts and novice users alike.

- FileMangler (fmg), is a compact, fast and flexible tool for handling all your file management needs.

  FileMangler performs all basic file management tasks, as well as performing scheduled and ad-hoc file backup and synchronization activities.

  FileMangler runs in a console window, and thus provides access to many system tools not available to a GUI application. FileMangler also provides full support for accessing the local Trashcan.

  FileMangler is based on the NcDialog API, and thus will run in almost any GNU/Linux or UNIX terminal environment.

- Console Trashcan (ctrash) is a simple, console-based (command-line) utility for managing the contents of your local Trashcan. Send items to the trash, restore items from the trash, report the trashcan contents, and empty the trash. ’ctrash’ is designed as a safer, and more flexible alternative to the ’rm’ and ’rmdir’ commands.
- Infodoc, post-processing and CSS style for HTML documents created by the Texinfo (makeinfo) utility. If you write documentation using the Texinfo/makeinfo documentation engine, AND if you care at all about what your documentation looks like, then you really do need the ‘infodoc-styles.css‘ definition file and the ‘idpp’ HTML post-processor.

  The HTML version of this document was formatted using ‘idpp’ and is displayed using the ‘infodoc-styles.css‘ definition file. Many more examples are available on the author’s website.

- gString text internationalization tool.
  gString implements a C++ class that may be integraged into any application for smooth and painless text formatting, and for converting between UTF-8 and ‘wchar_t’ (wide) character encoding.

  The gString class is lightweight, consisting of one C++ source module and one header file. The gString class may be directly integrated into an application, or may be built as a link library.
  The gString class is also embedded within the NcDialog API library (see above).

- Taggit (taggit) is a demonstration program written for students, or for anyone who wishes to create a console application with a multilingual user interface.

  Conceptually, Taggit is an audio-file tag editor (metadata editor), and is album oriented rather than file oriented so that all audio files in an album may be edited simultaneously.

  Taggit is not intended as a full-featured tag editor; for instance, Taggit does not access online databases of audio tag information. Taggit fully supports tag editing for audio formats: MP3, M4A, OGG/Vorbis and WMA.

  The OGG/Vorbis I specification is supported for all text tags in `'.ogg'` and `'.oga'` audio files.

  For MP3 audio files, all tag frames of the ID3v2.3 standard are supported, along with some features of ID3v2.4, such as support for UTF-8 text encoding which enables writing text tags in any language.

  Taggit is implemented in four(4) user interface languages: Español (Spanish), Zhōngwén (中文) (Chinese, simplified), Tiếng Việt (Vietnamese) and English (U.S.). Additional user interface languages (both LTR and RTL) may be added with minimum effort.

- Source Profiler (srcprof) is a source code analysis tool for determining the ‘maintainability’ of source code modules.

  ‘srcprof’ can be used to profile source code for high-level languages such as C, C++ and Java, as well as various assembly languages and scripting languages such as Python, Perl and Ruby. For a complete list of currently-supported source languages, please see the Source Profiler documentation.

  ’srcprof’ can be used both as a productivity-measurement tool and as a tool for testing source code quality based on an evaluation of its ‘maintainability’.

  Source Profiler is a console-based utility, which runs as either a pure, command-line utility, OR as a dialog application based on the NcDialog API.

- WaylandCB, clipboard access for console applications.
  Access to the system clipboard under the Wayland communications protocol, leveraging Sergey Bugaev’s "wl-clipboard" application suite.

  WaylandCB is a simple C++ class definition which provides console applications with seemless access to the system clipboard.

- Exercalc (ecalc) is a utility for tracking daily exercise activity.
  Specify the type of exercise, walk/bike/run/cardio/free weights, etc. and either the elapsed time, distance travelled, or energy expended (KCal or METs). Exercalc then calculates the efficiency and progress over time. Archive the data, retrieve and analyze the data in various ways including tables, comparisons and bar charts.

  The application is specifically designed to be a student exercise in creating applications which incorporate a multi-language user interface. Exercalc is implemented in four(4) user interface languages: Español (Spanish), Zhōngwén (中文) (Chinese, simplified), Tiếng Việt (Vietnamese) and English (U.S.). Additional user interface languages (both LTR and RTL) may be added with minimum effort.

- DVD Repair (dvdrep) is a utility for exploring the contents of a damaged DVD video disc and rescuing as much of the data as possible.

  ‘dvdrep’ can be used to rescue data from any non-encrypted DVD video source disc that is formatted using the Universal Disc Format (UDF) filesystem (as all commercially produced DVD movies are).

  ‘dvdrep’ takes a layered approach to the analysis of the source disc. A detailed log file is maintained for each step of the process in case manual intervention is needed at a later step.

  DVD Repair is based on the NcDialog API, and thus will run in almost any GNU/Linux or UNIX terminal environment.

- crcPlus (crcplus) is a reference model and demonstration program for implementating CRC (Cyclic Redundancy Check) data error detection. crcPlus provides a reliable reference algorithm for verifying the function of other CRC generators and decoders as well as providing the tools to build a fully customizable hash table (lookup table) for creating your own high-speed CRC generator.
- Various other Linux utilities designed as academic exercises are also available for student use. For example: interprocess communication pipes, FIFOs, sockets, shared memory blocks, multi-threading, the ’Sleeping Barber’ problem and so on.
  These cannot be considered as production-worthy, but they demonstrate the concepts in simple terms.

## Copyright Notice

The AnsiCmd library and source code are released under the GNU General Public License (GPL 3+), and the user documentation (this document) is released under the GNU Free Documentation License (FDL 1.3+):
Copyright © 2022-2026 Mahlon R. Smith, The Software Samurai This manual describes version 0.0.07 of the AnsiCmd library. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".

### GNU General Public License

Version 3, 29 June 2007
Copyright © 2007 Free Software Foundation, Inc. https://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

#### Preamble

The GNU General Public License is a free, copyleft license for software and other kinds of works.

The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program—to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.

To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.

For the developers’ and authors’ protection, the GPL clearly explains that there is no warranty for this free software. For both users’ and authors’ sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.

Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users’ freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.

Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.

The precise terms and conditions for copying, distribution and modification follow.

#### TERMS AND CONDITIONS

0. Definitions.

   “This License” refers to version 3 of the GNU General Public License.

   “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.

   “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.

   To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.

   A “covered work” means either the unmodified Program or a work based on the Program.

   To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.

   To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.

   An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.

1. Source Code.

   The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.

   A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.

   The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.

   The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work’s System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.

   The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.

   The Corresponding Source for a work in source code form is that same work.

2. Basic Permissions.

   All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.

   You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.

   Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.

3. Protecting Users’ Legal Rights From Anti-Circumvention Law.

   No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.

   When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work’s users, your or third parties’ legal rights to forbid circumvention of technological measures.

4. Conveying Verbatim Copies.

   You may convey verbatim copies of the Program’s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.

   You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.

5. Conveying Modified Source Versions.

   You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:

   1. The work must carry prominent notices stating that you modified it, and giving a relevant date.
   2. The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
   3. You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
   4. If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.

   A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation’s users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.

6. Conveying Non-Source Forms.

   You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:

   1. Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
   2. Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
   3. Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
   4. Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
   5. Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.

   A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.

   A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.

   “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.

   If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).

   The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.

   Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.

7. Additional Terms.

   “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.

   When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.

   Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:

   1. Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
   2. Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
   3. Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
   4. Limiting the use for publicity purposes of names of licensors or authors of the material; or
   5. Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
   6. Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.

   All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.

   If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.

   Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.

8. Termination.

   You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).

   However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.

   Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.

   Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.

9. Acceptance Not Required for Having Copies.

   You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.

10. Automatic Licensing of Downstream Recipients.

    Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.

    An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party’s predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.

    You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.

11. Patents.

    A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor’s “contributor version”.

    A contributor’s “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.

    Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor’s essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.

    In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.

    If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient’s use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.

    If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.

    A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.

    Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.

12. No Surrender of Others’ Freedom.

    If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.

13. Use with the GNU Affero General Public License.

    Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.

14. Revised Versions of this License.

    The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

    Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.

    If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Program.

    Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.

15. Disclaimer of Warranty.

    THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

16. Limitation of Liability.

    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

17. Interpretation of Sections 15 and 16.

    If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.

#### END OF TERMS AND CONDITIONS

#### How to Apply These Terms to Your New Programs

If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.

one line to give the program's name and a brief idea of what it does. Copyright (C) year name of author This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.

Also add information on how to contact you by electronic and paper mail.

If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:

program Copyright (C) year name of author This program comes with ABSOLUTELY NO WARRANTY; for details type ‘`show w`’. This is free software, and you are welcome to redistribute it under certain conditions; type ‘`show c`’ for details.

The hypothetical commands ‘`show w`’ and ‘`show c`’ should show the appropriate parts of the General Public License. Of course, your program’s commands might be different; for a GUI interface, you would use an “about box”.

You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see https://www.gnu.org/licenses/.

The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read https://www.gnu.org/licenses/why-not-lgpl.html.

### GNU Free Documentation License

Version 1.3, 3 November 2008
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. https://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

0. PREAMBLE

   The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

   This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

   We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

   This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

   A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

   A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

   The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

   The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

   A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.

   Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

   The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.

   The “publisher” means any person or entity that distributes copies of the Document to the public.

   A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.

   The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

2. VERBATIM COPYING

   You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

   You may also lend copies, under the same conditions stated above, and you may publicly display copies.

3. COPYING IN QUANTITY

   If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

   If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

   If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

   It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

4. MODIFICATIONS

   You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

   1. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
   2. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
   3. State on the Title page the name of the publisher of the Modified Version, as the publisher.
   4. Preserve all the copyright notices of the Document.
   5. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
   6. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
   7. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license notice.
   8. Include an unaltered copy of this License.
   9. Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
   10. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History” section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
   11. For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
   12. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
   13. Delete any section Entitled “Endorsements”. Such a section may not be included in the Modified Version.
   14. Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section.
   15. Preserve any Warranty Disclaimers.

   If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.

   You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

   You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

   The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

5. COMBINING DOCUMENTS

   You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

   The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

   In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”

6. COLLECTIONS OF DOCUMENTS

   You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

   You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

7. AGGREGATION WITH INDEPENDENT WORKS

   A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

   If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

8. TRANSLATION

   Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

   If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

9. TERMINATION

   You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.

   However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.

   Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.

   Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.

10. FUTURE REVISIONS OF THIS LICENSE

    The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See https://www.gnu.org/licenses/.

    Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.

11. RELICENSING

    “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.

    “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.

    “Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.

    An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.

    The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.

#### ADDENDUM: How to use this License for your documents

To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:

Copyright (C) year your name. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''.

If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with…Texts.” line with this:

with the Invariant Sections being list their titles, with the Front-Cover Texts being list, and with the Back-Cover Texts being list.

If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.

If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.

## Index

Jump to: | 0 1 ~ A B C D E F G H I K L M N O P Q R S T U V W Z

| Index Entry | Section
0
| 01.0.00 Introduction | Introduction
| 02.0.00 Invoking | Invoking
| 02.1.00 Invoking - Terminal Setup | Invoking - Terminal Setup
| 02.2.00 Invoking - AnsiCmd Tests | Invoking - AnsiCmd Tests
| 02.3.00 Invoking - EarthPoints | Invoking - EarthPoints
| 03.0.00 AnsiCmd Library | AnsiCmd Library
| 03.1.00 Introductory Notes | Introductory Notes
| 03.2.00 ANSI Escape Sequences | ANSI Escape Sequences
| 03.3.00 Terminal Configuration | Terminal Configuration
| 03.4.00 AnsiCmd Class Methods | AnsiCmd Class Methods
| 03.4.01 Table of Public Methods | Table of Public Methods
| 03.4.02 Configuration Methods | Configuration Methods
| 03.4.03 Color Attributes | Color Attributes
| 03.4.04 Text Modifiers | Text Modifiers
| 03.4.05 Cursor Positioning | Cursor Positioning
| 03.4.06 Input Methods | Input Methods
| 03.4.07 Output Methods | Output Methods
| 03.4.08 Text Erase | Text Erase
| 03.4.09 Misc Methods | Misc Methods
| 03.4.10 API Methods | API Methods
| 03.4.11 Coding Example | Coding Example
| 03.4.11 Development Support | Development Support
| 04.0.00 ACWin Class | ACWin Class
| 04.1.00 ACWin Public Methods | ACWin Public Methods
| 04.2.00 skForm Class | skForm Class
| 04.2.01 User Interaction | User Interaction
| 04.2.02 skForm Public Methods | skForm Public Methods
| 04.2.03 skForm Data Members | skForm Data Members
| 04.2.04 skField Public Methods | skField Public Methods
| 04.2.05 skField Data Members | skField Data Members
| 04.2.06 UI Control Types | UI Control Types
| 04.2.07 skForm Initialization | skForm Initialization
| 04.3.00 Dialog sub-Windows | Dialog sub-Windows
| 05.0.00 | Development and Testing
| 06.0.00 Building from Source | Building from Source
| 07 gString Text Tool | gString Text Tool
| 07.01 Introduction to gString | Introduction to gString
| 07.02 gString Public Methods | gString Public Methods
| 07.03 gString Instantiation | gString Instantiation
| 07.04 Assignment Operators | Assignment Operators
| 07.05 Formatted Assignments | Formatted Assignments
| 07.06 Integer Formatting | Integer Formatting
| 07.07 Data Access | Data Access
| 07.08 Copying Data | Copying Data
| 07.09 Modifying Existing Data | Modifying Existing Data
| 07.10 Comparisons | Comparisons
| 07.11 Extract Formatted Data | Extract Formatted Data
| 07.12 Statistical Info | Statistical Info
| 07.13 gString Miscellaneous | gString Miscellaneous
| 07.14 gsmeter Test App | gsmeter Test App
| 07.14 gString Examples | gString Examples
| 08.0.00 CsvView Demo App | CsvView Demo App
| 08.01 Introduction to CsvView | Introduction to CsvView
| 08.02 Invoking CsvView | Invoking CsvView
| 08.03 CSV Encoding | CSV Encoding
| 08.04 Build CsvView from Source | Build CsvView from Source
| 09.0.00 AcEdit Demo App | AcEdit Demo App
| 09.01 Introduction to AcEdit | Introduction to AcEdit
| 09.02 Invoking AcEdit | Invoking AcEdit
| 09.03 AcEdit Menu System | AcEdit Menu System
| 09.05 AcEdit Configuration | AcEdit Configuration
| 09.05 AcEdit Dialogs | AcEdit Dialogs
| 09.06 Build AcEdit from Source | Build AcEdit from Source
1
| 10.0.00 TFMTest Demo App | TFMTest Demo App
| 10.01 The TFMTest Application | The TFMTest Application
| 10.02 TFMan Class | TFMan Class
| 11.0.00 Technical Support | Technical Support
| 12.0.00 Copyright Notice | Copyright Notice
| 12.1.00 GNU General Public License | GNU General Public License
| 12.2.00 GNU Free Documentation License | GNU Free Documentation License
A
| A option | Invoking - Terminal Setup
| acaExpand class | API Methods
| acAttr, enum | API Methods
| acBeep | Misc Methods
| acBlockingInput | Configuration Methods
| acBoxClear | API Methods
| acBoxDraw | API Methods
| acBoxErase | API Methods
| acBufferedInput | Configuration Methods
| acCaptureBreakSignal | Configuration Methods
| acCaptureQuitSignal | Configuration Methods
| acCaptureSignals | Configuration Methods
| acCaptureSuspendSignal | Configuration Methods
| acClearArea | API Methods
| acClearScreen | API Methods
| acClipboardByteCnt | API Methods
| acClipboardCharCnt | API Methods
| acClipboardDisable | API Methods
| acClipboardEnable | API Methods
| acClipboardGetText | API Methods
| acClipboardSetText | API Methods
| acClipboardTest | API Methods
| acComposeAttributes | API Methods
| acCreateTempfile | API Methods
| acCreateTemppath | API Methods
| acDeleteTempfile | API Methods
| acDeleteTemppath | API Methods
| ACDlg class | Dialog sub-Windows
| acDrawBox | API Methods
| acDrawLine | API Methods
| ace color option | Invoking AcEdit
| ace dimensions option | Invoking AcEdit
| ace help option | Invoking AcEdit
| ace helpless option | Invoking AcEdit
| ace language option | Invoking AcEdit
| ace test option | Invoking AcEdit
| ace version option | Invoking AcEdit
| AcEdit invoking | Invoking AcEdit
| acEraseArea | Text Erase
| acEraseBox | API Methods
| acFlushIn | Input Methods
| acFlushOut | Output Methods
| acFlushStreams | Output Methods
| acFormatParagraph | API Methods
| acFullReset | Text Modifiers
| acGetAttributes | API Methods
| acGetCursor | Cursor Positioning
| acGetEchoOption | Configuration Methods
| acGetLocale | Configuration Methods
| acGetTermDimensions | Configuration Methods
| acGetTermInfo | Configuration Methods
| acGetTermSize | Configuration Methods
| acPause | Input Methods
| acRead | Input Methods
| acReleaseSignals | Configuration Methods
| acReset | Color Attributes
| acResetMods | Text Modifiers
| acRestoreTermInfo | Configuration Methods
| acSet8bitBg | Color Attributes
| acSet8bitFg | Color Attributes
| acSetAixBg | Color Attributes
| acSetAixFg | Color Attributes
| acSetAttributes | API Methods
| acSetBg | Color Attributes
| acSetCursor | Cursor Positioning
| acSetCursorStyle | Cursor Positioning
| acSetEchoOption | Configuration Methods
| acSetFg | Color Attributes
| acSetFgBg | Color Attributes
| acSetFont | Misc Methods
| acSetGreyscaleBg | Color Attributes
| acSetGreyscaleFg | Color Attributes
| acSetIdeogram | Misc Methods
| acSetLocale | Configuration Methods
| acSetMod | Text Modifiers
| acSetRgbBg | Color Attributes
| acSetRgbFg | Color Attributes
| acSetStreamWidth | Configuration Methods
| acSetWebBg | Color Attributes
| acSetWebFg | Color Attributes
| acShellOut | API Methods
| acVersion | Misc Methods
| acWait | Input Methods
| ACWin constructor | ACWin Public Methods
| ACWin derived class | ACWin Class
| ACWin destructor | ACWin Public Methods
| acWrite | Output Methods
| AC_Box Class | API Methods
| aeSeq enumerated type | ANSI Escape Sequences
| AIX extensions | Color Attributes
| Aixterm, IBM | Color Attributes
| AlertEnable | ACWin Public Methods
| Alt keys | Terminal Configuration
| ALT-key combo | Invoking - AnsiCmd Tests
| ANSI escape sequence | ANSI Escape Sequences
| AnsiCmd constructor | Configuration Methods
| AnsiCmd destructor | Configuration Methods
| ansiTest | Development Support
| ansiTest_Menu | Development and Testing
| api methods | API Methods
| application options | Invoking - EarthPoints
| ASCII codes | Terminal Configuration
| ascii test | Invoking - AnsiCmd Tests
| assignment, skField | skField Public Methods
| assignment, skForm | skForm Public Methods
| attributes, color | Color Attributes
B
| B option | Invoking - Terminal Setup
| BiDi text | Modifying Existing Data
| blink timeout | Invoking - Terminal Setup
| blink timeout | Cursor Positioning
| break signal | Terminal Configuration
| breaksignalReceived | Configuration Methods
| breaksignalReceived | Configuration Methods
| buffered input | Configuration Methods
| buffering, input | Terminal Configuration
| build CsvView | Build CsvView from Source
| build options | Building from Source
C
| C option | Invoking - Terminal Setup
| callback example | Dialog sub-Windows
| callback function | ACWin Public Methods
| callback, dialog | Dialog sub-Windows
| chrono | Misc Methods
| class, acaExpand | API Methods
| class, ACDlg | Dialog sub-Windows
| class, ACWin | ACWin Class
| class, AnsiCmd | AnsiCmd Class Methods
| class, skField | skField Public Methods
| class, skForm | skForm Class
| class, TermConfig | Terminal Configuration
| class, TermSet | Terminal Configuration
| ClearField | ACWin Public Methods
| ClearRow | ACWin Public Methods
| ClearWin | ACWin Public Methods
| clipboard directive | Building from Source
| clipboard, copy/paste | API Methods
| CloseWindow | ACWin Public Methods
| coa option | Invoking - EarthPoints
| cob option | Invoking - EarthPoints
| code example | Coding Example
| codepoint, Unicode | ACWin Public Methods
| color attributes | Color Attributes
| color option | Invoking - EarthPoints
| color test | Invoking - AnsiCmd Tests
| colorConfig | skField Public Methods
| colors, custom | skField Public Methods
| command-line options | Invoking
| compilation, conditional | Development and Testing
| compile from source | Building from Source
| conditional compilation | Development and Testing
| configuration, terminal | Terminal Configuration
| configuraton | Configuration Methods
| contact info | Technical Support
| control codes | Terminal Configuration
| control types | UI Control Types
| Control_C | Terminal Configuration
| Control_Z | Configuration Methods
| convert option | Invoking - EarthPoints
| copy to cb | API Methods
| csv bgndattr option | Invoking CsvView
| csv capture option | Invoking CsvView
| csv create option | Invoking CsvView
| csv dimensions option | Invoking CsvView
| csv display option | Invoking CsvView
| csv encoding | CSV Encoding
| csv fgndattr option | Invoking CsvView
| csv filespec option | Invoking CsvView
| csv header option | Invoking CsvView
| csv help option | Invoking CsvView
| csv helpless option | Invoking CsvView
| csv language option | Invoking CsvView
| csv pause option | Invoking CsvView
| csv saveas option | Invoking CsvView
| csv stats option | Invoking CsvView
| csv terminfo option | Invoking CsvView
| csv version option | Invoking CsvView
| csvview build | Build CsvView from Source
| CsvView invoking | Invoking CsvView
| CTRL-key combo | Invoking - AnsiCmd Tests
| cursor offsets | Cursor Positioning
| cursor position | Cursor Positioning
| custom colors | skField Public Methods
| cut to cb | API Methods
D
| database, GPS | Invoking - EarthPoints
| delimeters, secondary | CSV Encoding
| derived class, ACWin | ACWin Class
| dialog callback | Dialog sub-Windows
| Dialog method | ACWin Public Methods
| Dialog method | Dialog sub-Windows
| dialog test | Invoking - AnsiCmd Tests
| Dialog_GetField | ACWin Public Methods
| Dialog_GetItem | ACWin Public Methods
| Dialog_GetItem | ACWin Public Methods
| Dialog_GetState | ACWin Public Methods
| Dialog_GetStateXOR | ACWin Public Methods
| Dialog_GetText | ACWin Public Methods
| Dialog_Hilite | ACWin Public Methods
| Dialog_Refresh | ACWin Public Methods
| Dialog_Scroll | ACWin Public Methods
| Dialog_SetAttr | ACWin Public Methods
| Dialog_SetFocus | ACWin Public Methods
| Dialog_SetReadOnly | ACWin Public Methods
| Dialog_SetText | ACWin Public Methods
| Dialog_Write | ACWin Public Methods
| directive, clipboard | Building from Source
| documentation, installing | Building from Source
| DrawBox | ACWin Public Methods
| DrawLine | ACWin Public Methods
| dump option | Invoking - EarthPoints
| dumpConfig2Log | ACWin Public Methods
| dumpField2Log | ACWin Public Methods
| dumpFifo2Log | ACWin Public Methods
| dumpFifoRecord2Log | ACWin Public Methods
| dumpMrp2Log | ACWin Public Methods
| dynamic alloc. gString | gString Instantiation
E
| echo options | Terminal Configuration
| EditForm | ACWin Public Methods
| EnableFootnotes | ACWin Public Methods
| encoding, csv | CSV Encoding
| enum acAttr | API Methods
| enum FldType | UI Control Types
| enum FloType | ACWin Public Methods
| erase, text | Text Erase
| erasure test | Invoking - AnsiCmd Tests
| EstablishCallback | ACWin Public Methods
| example, coding | Coding Example
F
| field types | UI Control Types
| FIFO, input stream | ACWin Public Methods
| file option | Invoking - EarthPoints
| FileMan class | AcEdit Dialogs
| fiUnits enumerated type | Integer Formatting
| Fnn-key combo | Invoking - AnsiCmd Tests
| Focus2NextField | ACWin Public Methods
| Focus2PrevField | ACWin Public Methods
| font test | Invoking - AnsiCmd Tests
| Footnote | ACWin Public Methods
| formatInt field overflow | Integer Formatting
| FormatParagraph | ACWin Public Methods
| formula option | Invoking - EarthPoints
G
| getConfig | Development Support
| GetCursorPos | ACWin Public Methods
| getDataMembers | Development Support
| GetFieldData | ACWin Public Methods
| GetFieldIP | ACWin Public Methods
| GetFieldItem | ACWin Public Methods
| GetFieldState | ACWin Public Methods
| GetFieldText | ACWin Public Methods
| GetFifo | ACWin Public Methods
| GetForm | ACWin Public Methods
| getHilite | skField Public Methods
| GetInputFocus | ACWin Public Methods
| getItem | skField Public Methods
| GetWinAttributes | ACWin Public Methods
| GetWinConfig | ACWin Public Methods
| GPS database | Invoking - EarthPoints
| gsettings, blink | Invoking - Terminal Setup
| gString | Introduction
| gString memory alloc. | gString Instantiation
| gString methods | gString Public Methods
| gString text conversion | gString Text Tool
| GUI keys | Terminal Configuration
H
| help option | Invoking - EarthPoints
| helpless option | Invoking - EarthPoints
| HideWin | ACWin Public Methods
| HilightFieldText | ACWin Public Methods
| hotkeys, direct | skField Data Members
| hotkeys, set | ACWin Public Methods
I
| i/o streams | Terminal Configuration
| IBM Aixterm | Color Attributes
| ideograph test | Invoking - AnsiCmd Tests
| info database | Building from Source
| input buffering | Terminal Configuration
| input methods | Input Methods
| input stream FIFO | ACWin Public Methods
| input, buffered | Configuration Methods
| InsertKey | ACWin Public Methods
| invoking | Invoking
| invoking AcEdit | Invoking AcEdit
| invoking CsvView | Invoking CsvView
| invoking TFMTest | The TFMTest Application
| invoking, EarthPoints | Invoking - EarthPoints
| invoking, term setup | Invoking - Terminal Setup
| invoking, test options | Invoking - AnsiCmd Tests
| isCommandKey | API Methods
| isInsertMode | ACWin Public Methods
| isPrint | ACWin Public Methods
| isSpecialKey | API Methods
K
| KeycodePush | ACWin Public Methods
L
| L option | Invoking - Terminal Setup
| labelConfig | skField Public Methods
| LaunchDefaultApp | ACWin Public Methods
| less utility | Introduction to CsvView
| list of methods | Table of Public Methods
| locale name | Terminal Configuration
| locale, set | Integer Formatting
| locale, specify | Invoking - Terminal Setup
M
| memory, alloc. gString | gString Instantiation
| menu item | skField Public Methods
| method list | Table of Public Methods
| methods, gString | gString Public Methods
| misc methods | Misc Methods
| modifiers, text | Text Modifiers
| MoveWin | ACWin Public Methods
| multi-threading | ANSI Escape Sequences
N
| nanosleep | Misc Methods
| nsleep | Misc Methods
O
| offsets, cursor | Cursor Positioning
| OpenWindow | ACWin Public Methods
| option, A | Invoking - Terminal Setup
| option, ace color | Invoking AcEdit
| option, ace dimensions | Invoking AcEdit
| option, ace help | Invoking AcEdit
| option, ace helpless | Invoking AcEdit
| option, ace language | Invoking AcEdit
| option, ace test | Invoking AcEdit
| option, ace version | Invoking AcEdit
| option, B | Invoking - Terminal Setup
| option, C | Invoking - Terminal Setup
| option, coa | Invoking - EarthPoints
| option, cob | Invoking - EarthPoints
| option, color | Invoking - EarthPoints
| option, convert | Invoking - EarthPoints
| option, csv bgndattr | Invoking CsvView
| option, csv capture | Invoking CsvView
| option, csv create | Invoking CsvView
| option, csv dimensions | Invoking CsvView
| option, csv display | Invoking CsvView
| option, csv fgndattr | Invoking CsvView
| option, csv filespec | Invoking CsvView
| option, csv header | Invoking CsvView
| option, csv help | Invoking CsvView
| option, csv helpless | Invoking CsvView
| option, csv language | Invoking CsvView
| option, csv pause | Invoking CsvView
| option, csv saveas | Invoking CsvView
| option, csv stats | Invoking CsvView
| option, csv terminfo | Invoking CsvView
| option, csv version | Invoking CsvView
| option, dump | Invoking - EarthPoints
| option, file | Invoking - EarthPoints
| option, formula | Invoking - EarthPoints
| option, help | Invoking - EarthPoints
| option, helpless | Invoking - EarthPoints
| option, L | Invoking - Terminal Setup
| option, P | Invoking - Terminal Setup
| option, Q | Invoking - Terminal Setup
| option, S | Invoking - Terminal Setup
| option, verbose | Invoking - EarthPoints
| option, version | Invoking - EarthPoints
| option, W | Invoking - Terminal Setup
| option, window | Invoking - EarthPoints
| option, Z | Invoking - Terminal Setup
| options, application | Invoking - EarthPoints
| options, echo | Terminal Configuration
| options, setup | Invoking - Terminal Setup
| options, testing | Invoking - AnsiCmd Tests
| outlineConfig | skField Public Methods
| output formats | Introduction to CsvView
| output methods | Output Methods
P
| P option | Invoking - Terminal Setup
| ParagraphSize | ACWin Public Methods
| paste from cb | API Methods
| positioning test | Invoking - AnsiCmd Tests
Q
| Q option | Invoking - Terminal Setup
| QuickDialog | ACWin Public Methods
| QuickDialog | Dialog sub-Windows
| quitsignalReceived | Configuration Methods
R
| ram memory, gString | gString Instantiation
| ReformatFieldText | ACWin Public Methods
| RefreshField | ACWin Public Methods
| RefreshWin | ACWin Public Methods
| RTL text | Modifying Existing Data
S
| S option | Invoking - Terminal Setup
| sandbox test | Invoking - AnsiCmd Tests
| Screenshot | ACWin Public Methods
| ScrollFieldText | ACWin Public Methods
| secondary delimeters | CSV Encoding
| set locale | Integer Formatting
| SetBorderAttr | ACWin Public Methods
| SetCursorPos | ACWin Public Methods
| SetFieldAttr | ACWin Public Methods
| SetFieldData | ACWin Public Methods
| SetFieldFlow | ACWin Public Methods
| SetFieldHidden | ACWin Public Methods
| SetFieldHotkey | ACWin Public Methods
| SetFieldIP | ACWin Public Methods
| SetFieldLabel | ACWin Public Methods
| SetFieldOutline | ACWin Public Methods
| SetFieldState | ACWin Public Methods
| SetFieldText | ACWin Public Methods
| SetHilightMod | ACWin Public Methods
| setHiliteMod | skField Public Methods
| SetInputFocus | ACWin Public Methods
| SetReadOnly | ACWin Public Methods
| SetTextAttr | ACWin Public Methods
| SetTitle | ACWin Public Methods
| setup options | Invoking - Terminal Setup
| ShellOut | ACWin Public Methods
| ShiftFieldText | ACWin Public Methods
| Sidebar | ACWin Public Methods
| skField class | skField Public Methods
| skField constructor | skField Public Methods
| skField operator= | skField Public Methods
| skForm class | skForm Class
| skForm constructor | skForm Public Methods
| skForm operator= | skForm Public Methods
| sleep_for | Misc Methods
| soft-echo options | Terminal Configuration
| source code | Building from Source
| special keys | Terminal Configuration
| streams, i/o | Terminal Configuration
| support methods | Development Support
| support, technical | Technical Support
| suspendsignalReceived | Configuration Methods
| swscanf emulation | Extract Formatted Data
T
| technical support | Technical Support
| temporary files | API Methods
| temporary files | The TFMTest Application
| temporary files | TFMan Class
| TermConfig class | Terminal Configuration
| terminal configuration | Terminal Configuration
| terminal test | Invoking - AnsiCmd Tests
| TermSet class | Terminal Configuration
| test methods | Development and Testing
| test the build | Building from Source
| test, ascii | Invoking - AnsiCmd Tests
| test, color | Invoking - AnsiCmd Tests
| test, dialog | Invoking - AnsiCmd Tests
| test, erasure | Invoking - AnsiCmd Tests
| test, font | Invoking - AnsiCmd Tests
| test, ideograph | Invoking - AnsiCmd Tests
| test, positioning | Invoking - AnsiCmd Tests
| test, sandbox | Invoking - AnsiCmd Tests
| test, terminal | Invoking - AnsiCmd Tests
| test, window | Invoking - AnsiCmd Tests
| testing options | Invoking - AnsiCmd Tests
| Test_4Bit | Development and Testing
| Test_8bitColor | Development and Testing
| Test_acaExpand | Development and Testing
| Test_acaExpandSwap | Development and Testing
| Test_AixFgBg | Development and Testing
| Test_AltFonts | Development and Testing
| Test_AsciiCodes | Development and Testing
| Test_Bg | Development and Testing
| Test_Box | Development and Testing
| Test_Clipboard_API | Development and Testing
| Test_Clipboard_Win | Development and Testing
| Test_Cookie | Development and Testing
| Test_CursorPos | Development and Testing
| Test_Dialog | Development and Testing
| Test_Erasures | Development and Testing
| Test_Fifo | Development and Testing
| Test_Form | Development and Testing
| Test_Greyscale | Development and Testing
| Test_Hilite | Development and Testing
| Test_Ideogram | Development and Testing
| Test_LaunchExt | Development and Testing
| Test_Line | Development and Testing
| Test_Menu | Development and Testing
| Test_ModFlags | Development and Testing
| Test_NonBlock | Development and Testing
| Test_OutputStream | Development and Testing
| Test_RawInput | Development and Testing
| Test_RGB | Development and Testing
| Test_Sandbox | Development and Testing
| Test_SoftEcho | Development and Testing
| Test_TermFlags | Development and Testing
| Test_Tfman | Development and Testing
| Test_UnbufferedInput | Development and Testing
| Test_WinDefault | Development and Testing
| Test_Window | Development and Testing
| Test_Wrap | Development and Testing
| Test_Write | Development and Testing
| text conversion, gString | gString Text Tool
| text erase | Text Erase
| text modifiers | Text Modifiers
| TFMan | Introduction
| TFMTest app | The TFMTest Application
| timeout, blink | Cursor Positioning
| timeout, blinking | Invoking - Terminal Setup
| tseReport | Development Support
| ttyWrite | Output Methods
U
| Unicode codepoint | ACWin Public Methods
| user interface controls | UI Control Types
V
| verbose option | Invoking - EarthPoints
| version option | Invoking - EarthPoints
W
| W option | Invoking - Terminal Setup
| WaylandCB | Introduction
| web-safe indices | API Methods
| window option | Invoking - EarthPoints
| window test | Invoking - AnsiCmd Tests
| WinInfo | ACWin Public Methods
| Write | ACWin Public Methods
Z
| Z option | Invoking - Terminal Setup
~
| ~skField | skField Public Methods