Next:   [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 GetInputFocus ( 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 SetInputFocus ( short fldIndex );
      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 fIndx, const gString& srcTxt, bool refresh = true );
  • bool SetFieldText ( short fIndx, const wchar_t* srcTxt, bool refresh = true );
  • bool SetFieldText ( short fIndx, 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 fIndx, gString& txtBuf ) const;
  • int GetFieldText ( short fIndx, wchar_t* txtBuf, int maxChars ) const;
  • int GetFieldText ( short fIndx, 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 fIndx, 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 fIndx, 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 SetFieldIP ( short fIndx, short newIp, 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 fIndx );
      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 fIndx, 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 fIndx, 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 fIndx, const gString& srcTxt, acAttr txtAttr = acaUSEDFLT,
                     short newIp = ZERO, bool refresh = true );
  • bool SetFieldData ( short fIndx, const wchar_t* srcTxt, acAttr txtAttr = acaUSEDFLT,
                     short newIp = ZERO, bool refresh = true );
  • bool SetFieldData ( short fIndx, const char* srcTxt, acAttr txtAttr = acaUSEDFLT,
                     short newIp = 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 fIndx );
      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 fIndx, 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.




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 Menu System

TEMP - EXPERIMENTAL

Documentation for the 'AcEdit' demo application is under construction.




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.





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 EntrySection

0
01.0.00 IntroductionIntroduction
02.0.00 InvokingInvoking
02.1.00 Invoking - Terminal SetupInvoking - Terminal Setup
02.2.00 Invoking - AnsiCmd TestsInvoking - AnsiCmd Tests
02.3.00 Invoking - EarthPointsInvoking - EarthPoints
03.0.00 AnsiCmd LibraryAnsiCmd Library
03.1.00 Introductory NotesIntroductory Notes
03.2.00 ANSI Escape SequencesANSI Escape Sequences
03.3.00 Terminal ConfigurationTerminal Configuration
03.4.00 AnsiCmd Class MethodsAnsiCmd Class Methods
03.4.01 Table of Public MethodsTable of Public Methods
03.4.02 Configuration MethodsConfiguration Methods
03.4.03 Color AttributesColor Attributes
03.4.04 Text ModifiersText Modifiers
03.4.05 Cursor PositioningCursor Positioning
03.4.06 Input MethodsInput Methods
03.4.07 Output MethodsOutput Methods
03.4.08 Text EraseText Erase
03.4.09 Misc MethodsMisc Methods
03.4.10 API MethodsAPI Methods
03.4.11 Coding ExampleCoding Example
03.4.11 Development SupportDevelopment Support
04.0.00 ACWin ClassACWin Class
04.1.00 ACWin Public MethodsACWin Public Methods
04.2.00 skForm ClassskForm Class
04.2.01 User InteractionUser Interaction
04.2.02 skForm Public MethodsskForm Public Methods
04.2.03 skForm Data MembersskForm Data Members
04.2.04 skField Public MethodsskField Public Methods
04.2.05 skField Data MembersskField Data Members
04.2.06 UI Control TypesUI Control Types
04.2.07 skForm InitializationskForm Initialization
04.3.00 Dialog sub-WindowsDialog sub-Windows
05.0.00Development and Testing
06.0.00 Building from SourceBuilding from Source
07 gString Text ToolgString Text Tool
07.01 Introduction to gStringIntroduction to gString
07.02 gString Public MethodsgString Public Methods
07.03 gString InstantiationgString Instantiation
07.04 Assignment OperatorsAssignment Operators
07.05 Formatted AssignmentsFormatted Assignments
07.06 Integer FormattingInteger Formatting
07.07 Data AccessData Access
07.08 Copying DataCopying Data
07.09 Modifying Existing DataModifying Existing Data
07.10 ComparisonsComparisons
07.11 Extract Formatted DataExtract Formatted Data
07.12 Statistical InfoStatistical Info
07.13 gString MiscellaneousgString Miscellaneous
07.14 gsmeter Test Appgsmeter Test App
07.14 gString ExamplesgString Examples
08.0.00 CsvView Demo AppCsvView Demo App
08.01 Introduction to CsvViewIntroduction to CsvView
08.02 Invoking CsvViewInvoking CsvView
08.03 CSV EncodingCSV Encoding
08.04 Build CsvView from SourceBuild CsvView from Source
09.0.00 AcEdit Demo AppAcEdit Demo App
09.01 Introduction to AcEditIntroduction to AcEdit
09.02 Invoking AcEditInvoking AcEdit
09.03 AcEdit Menu SystemAcEdit Menu System
09.05 AcEdit ConfigurationAcEdit Configuration
09.05 AcEdit DialogsAcEdit Dialogs
09.06 Build AcEdit from SourceBuild AcEdit from Source

1
10.0.00 TFMTest Demo AppTFMTest Demo App
10.01 The TFMTest ApplicationThe TFMTest Application
10.02 TFMan ClassTFMan Class
11.0.00 Technical SupportTechnical Support
12.0.00 Copyright NoticeCopyright Notice
12.1.00 GNU General Public LicenseGNU General Public License
12.2.00 GNU Free Documentation LicenseGNU Free Documentation License

A
A optionInvoking - Terminal Setup
acaExpand classAPI Methods
acAttr, enumAPI Methods
acBeepMisc Methods
acBlockingInputConfiguration Methods
acBoxClearAPI Methods
acBoxDrawAPI Methods
acBoxEraseAPI Methods
acBufferedInputConfiguration Methods
acCaptureBreakSignalConfiguration Methods
acCaptureQuitSignalConfiguration Methods
acCaptureSignalsConfiguration Methods
acCaptureSuspendSignalConfiguration Methods
acClearAreaAPI Methods
acClearScreenAPI Methods
acClipboardByteCntAPI Methods
acClipboardCharCntAPI Methods
acClipboardDisableAPI Methods
acClipboardEnableAPI Methods
acClipboardGetTextAPI Methods
acClipboardSetTextAPI Methods
acClipboardTestAPI Methods
acComposeAttributesAPI Methods
acCreateTempfileAPI Methods
acCreateTemppathAPI Methods
acDeleteTempfileAPI Methods
acDeleteTemppathAPI Methods
ACDlg classDialog sub-Windows
acDrawBoxAPI Methods
acDrawLineAPI Methods
ace color optionInvoking AcEdit
ace dimensions optionInvoking AcEdit
ace help optionInvoking AcEdit
ace helpless optionInvoking AcEdit
ace language optionInvoking AcEdit
ace test optionInvoking AcEdit
ace version optionInvoking AcEdit
AcEdit invokingInvoking AcEdit
acEraseAreaText Erase
acEraseBoxAPI Methods
acFlushInInput Methods
acFlushOutOutput Methods
acFlushStreamsOutput Methods
acFormatParagraphAPI Methods
acFullResetText Modifiers
acGetAttributesAPI Methods
acGetCursorCursor Positioning
acGetEchoOptionConfiguration Methods
acGetLocaleConfiguration Methods
acGetTermDimensionsConfiguration Methods
acGetTermInfoConfiguration Methods
acGetTermSizeConfiguration Methods
acPauseInput Methods
acReadInput Methods
acReleaseSignalsConfiguration Methods
acResetColor Attributes
acResetModsText Modifiers
acRestoreTermInfoConfiguration Methods
acSet8bitBgColor Attributes
acSet8bitFgColor Attributes
acSetAixBgColor Attributes
acSetAixFgColor Attributes
acSetAttributesAPI Methods
acSetBgColor Attributes
acSetCursorCursor Positioning
acSetCursorStyleCursor Positioning
acSetEchoOptionConfiguration Methods
acSetFgColor Attributes
acSetFgBgColor Attributes
acSetFontMisc Methods
acSetGreyscaleBgColor Attributes
acSetGreyscaleFgColor Attributes
acSetIdeogramMisc Methods
acSetLocaleConfiguration Methods
acSetModText Modifiers
acSetRgbBgColor Attributes
acSetRgbFgColor Attributes
acSetStreamWidthConfiguration Methods
acSetWebBgColor Attributes
acSetWebFgColor Attributes
acShellOutAPI Methods
acVersionMisc Methods
acWaitInput Methods
ACWin constructorACWin Public Methods
ACWin derived classACWin Class
ACWin destructorACWin Public Methods
acWriteOutput Methods
AC_Box ClassAPI Methods
aeSeq enumerated typeANSI Escape Sequences
AIX extensionsColor Attributes
Aixterm, IBMColor Attributes
AlertEnableACWin Public Methods
Alt keysTerminal Configuration
ALT-key comboInvoking - AnsiCmd Tests
ANSI escape sequenceANSI Escape Sequences
AnsiCmd constructorConfiguration Methods
AnsiCmd destructorConfiguration Methods
ansiTestDevelopment Support
ansiTest_MenuDevelopment and Testing
api methodsAPI Methods
application optionsInvoking - EarthPoints
ASCII codesTerminal Configuration
ascii testInvoking - AnsiCmd Tests
assignment, skFieldskField Public Methods
assignment, skFormskForm Public Methods
attributes, colorColor Attributes

B
B optionInvoking - Terminal Setup
BiDi textModifying Existing Data
blink timeoutInvoking - Terminal Setup
blink timeoutCursor Positioning
break signalTerminal Configuration
breaksignalReceivedConfiguration Methods
breaksignalReceivedConfiguration Methods
buffered inputConfiguration Methods
buffering, inputTerminal Configuration
build CsvViewBuild CsvView from Source
build optionsBuilding from Source

C
C optionInvoking - Terminal Setup
callback exampleDialog sub-Windows
callback functionACWin Public Methods
callback, dialogDialog sub-Windows
chronoMisc Methods
class, acaExpandAPI Methods
class, ACDlgDialog sub-Windows
class, ACWinACWin Class
class, AnsiCmdAnsiCmd Class Methods
class, skFieldskField Public Methods
class, skFormskForm Class
class, TermConfigTerminal Configuration
class, TermSetTerminal Configuration
ClearFieldACWin Public Methods
ClearRowACWin Public Methods
ClearWinACWin Public Methods
clipboard directiveBuilding from Source
clipboard, copy/pasteAPI Methods
CloseWindowACWin Public Methods
coa optionInvoking - EarthPoints
cob optionInvoking - EarthPoints
code exampleCoding Example
codepoint, UnicodeACWin Public Methods
color attributesColor Attributes
color optionInvoking - EarthPoints
color testInvoking - AnsiCmd Tests
colorConfigskField Public Methods
colors, customskField Public Methods
command-line optionsInvoking
compilation, conditionalDevelopment and Testing
compile from sourceBuilding from Source
conditional compilationDevelopment and Testing
configuration, terminalTerminal Configuration
configuratonConfiguration Methods
contact infoTechnical Support
control codesTerminal Configuration
control typesUI Control Types
Control_CTerminal Configuration
Control_ZConfiguration Methods
convert optionInvoking - EarthPoints
copy to cbAPI Methods
csv bgndattr optionInvoking CsvView
csv capture optionInvoking CsvView
csv create optionInvoking CsvView
csv dimensions optionInvoking CsvView
csv display optionInvoking CsvView
csv encodingCSV Encoding
csv fgndattr optionInvoking CsvView
csv filespec optionInvoking CsvView
csv header optionInvoking CsvView
csv help optionInvoking CsvView
csv helpless optionInvoking CsvView
csv language optionInvoking CsvView
csv pause optionInvoking CsvView
csv saveas optionInvoking CsvView
csv stats optionInvoking CsvView
csv terminfo optionInvoking CsvView
csv version optionInvoking CsvView
csvview buildBuild CsvView from Source
CsvView invokingInvoking CsvView
CTRL-key comboInvoking - AnsiCmd Tests
cursor offsetsCursor Positioning
cursor positionCursor Positioning
custom colorsskField Public Methods
cut to cbAPI Methods

D
database, GPSInvoking - EarthPoints
delimeters, secondaryCSV Encoding
derived class, ACWinACWin Class
dialog callbackDialog sub-Windows
Dialog methodACWin Public Methods
Dialog methodDialog sub-Windows
dialog testInvoking - AnsiCmd Tests
Dialog_GetFieldACWin Public Methods
Dialog_GetItemACWin Public Methods
Dialog_GetItemACWin Public Methods
Dialog_GetStateACWin Public Methods
Dialog_GetStateXORACWin Public Methods
Dialog_GetTextACWin Public Methods
Dialog_HiliteACWin Public Methods
Dialog_RefreshACWin Public Methods
Dialog_ScrollACWin Public Methods
Dialog_SetAttrACWin Public Methods
Dialog_SetFocusACWin Public Methods
Dialog_SetReadOnlyACWin Public Methods
Dialog_SetTextACWin Public Methods
Dialog_WriteACWin Public Methods
directive, clipboardBuilding from Source
documentation, installingBuilding from Source
DrawBoxACWin Public Methods
DrawLineACWin Public Methods
dump optionInvoking - EarthPoints
dumpConfig2LogACWin Public Methods
dumpField2LogACWin Public Methods
dumpFifo2LogACWin Public Methods
dumpFifoRecord2LogACWin Public Methods
dumpMrp2LogACWin Public Methods
dynamic alloc. gStringgString Instantiation

E
echo optionsTerminal Configuration
EditFormACWin Public Methods
EnableFootnotesACWin Public Methods
encoding, csvCSV Encoding
enum acAttrAPI Methods
enum FldTypeUI Control Types
enum FloTypeACWin Public Methods
erase, textText Erase
erasure testInvoking - AnsiCmd Tests
EstablishCallbackACWin Public Methods
example, codingCoding Example

F
field typesUI Control Types
FIFO, input streamACWin Public Methods
file optionInvoking - EarthPoints
FileMan classAcEdit Dialogs
fiUnits enumerated typeInteger Formatting
Fnn-key comboInvoking - AnsiCmd Tests
Focus2NextFieldACWin Public Methods
Focus2PrevFieldACWin Public Methods
font testInvoking - AnsiCmd Tests
FootnoteACWin Public Methods
formatInt field overflowInteger Formatting
FormatParagraphACWin Public Methods
formula optionInvoking - EarthPoints

G
getConfigDevelopment Support
GetCursorPosACWin Public Methods
getDataMembersDevelopment Support
GetFieldDataACWin Public Methods
GetFieldIPACWin Public Methods
GetFieldItemACWin Public Methods
GetFieldStateACWin Public Methods
GetFieldTextACWin Public Methods
GetFifoACWin Public Methods
GetFormACWin Public Methods
getHiliteskField Public Methods
GetInputFocusACWin Public Methods
getItemskField Public Methods
GetWinAttributesACWin Public Methods
GetWinConfigACWin Public Methods
GPS databaseInvoking - EarthPoints
gsettings, blinkInvoking - Terminal Setup
gStringIntroduction
gString memory alloc.gString Instantiation
gString methodsgString Public Methods
gString text conversiongString Text Tool
GUI keysTerminal Configuration

H
help optionInvoking - EarthPoints
helpless optionInvoking - EarthPoints
HideWinACWin Public Methods
HilightFieldTextACWin Public Methods
hotkeys, directskField Data Members
hotkeys, setACWin Public Methods

I
i/o streamsTerminal Configuration
IBM AixtermColor Attributes
ideograph testInvoking - AnsiCmd Tests
info databaseBuilding from Source
input bufferingTerminal Configuration
input methodsInput Methods
input stream FIFOACWin Public Methods
input, bufferedConfiguration Methods
InsertKeyACWin Public Methods
invokingInvoking
invoking AcEditInvoking AcEdit
invoking CsvViewInvoking CsvView
invoking TFMTestThe TFMTest Application
invoking, EarthPointsInvoking - EarthPoints
invoking, term setupInvoking - Terminal Setup
invoking, test optionsInvoking - AnsiCmd Tests
isCommandKeyAPI Methods
isInsertModeACWin Public Methods
isPrintACWin Public Methods
isSpecialKeyAPI Methods

K
KeycodePushACWin Public Methods

L
L optionInvoking - Terminal Setup
labelConfigskField Public Methods
LaunchDefaultAppACWin Public Methods
less utilityIntroduction to CsvView
list of methodsTable of Public Methods
locale nameTerminal Configuration
locale, setInteger Formatting
locale, specifyInvoking - Terminal Setup

M
memory, alloc. gStringgString Instantiation
menu itemskField Public Methods
method listTable of Public Methods
methods, gStringgString Public Methods
misc methodsMisc Methods
modifiers, textText Modifiers
MoveWinACWin Public Methods
multi-threadingANSI Escape Sequences

N
nanosleepMisc Methods
nsleepMisc Methods

O
offsets, cursorCursor Positioning
OpenWindowACWin Public Methods
option, AInvoking - Terminal Setup
option, ace colorInvoking AcEdit
option, ace dimensionsInvoking AcEdit
option, ace helpInvoking AcEdit
option, ace helplessInvoking AcEdit
option, ace languageInvoking AcEdit
option, ace testInvoking AcEdit
option, ace versionInvoking AcEdit
option, BInvoking - Terminal Setup
option, CInvoking - Terminal Setup
option, coaInvoking - EarthPoints
option, cobInvoking - EarthPoints
option, colorInvoking - EarthPoints
option, convertInvoking - EarthPoints
option, csv bgndattrInvoking CsvView
option, csv captureInvoking CsvView
option, csv createInvoking CsvView
option, csv dimensionsInvoking CsvView
option, csv displayInvoking CsvView
option, csv fgndattrInvoking CsvView
option, csv filespecInvoking CsvView
option, csv headerInvoking CsvView
option, csv helpInvoking CsvView
option, csv helplessInvoking CsvView
option, csv languageInvoking CsvView
option, csv pauseInvoking CsvView
option, csv saveasInvoking CsvView
option, csv statsInvoking CsvView
option, csv terminfoInvoking CsvView
option, csv versionInvoking CsvView
option, dumpInvoking - EarthPoints
option, fileInvoking - EarthPoints
option, formulaInvoking - EarthPoints
option, helpInvoking - EarthPoints
option, helplessInvoking - EarthPoints
option, LInvoking - Terminal Setup
option, PInvoking - Terminal Setup
option, QInvoking - Terminal Setup
option, SInvoking - Terminal Setup
option, verboseInvoking - EarthPoints
option, versionInvoking - EarthPoints
option, WInvoking - Terminal Setup
option, windowInvoking - EarthPoints
option, ZInvoking - Terminal Setup
options, applicationInvoking - EarthPoints
options, echoTerminal Configuration
options, setupInvoking - Terminal Setup
options, testingInvoking - AnsiCmd Tests
outlineConfigskField Public Methods
output formatsIntroduction to CsvView
output methodsOutput Methods

P
P optionInvoking - Terminal Setup
ParagraphSizeACWin Public Methods
paste from cbAPI Methods
positioning testInvoking - AnsiCmd Tests

Q
Q optionInvoking - Terminal Setup
QuickDialogACWin Public Methods
QuickDialogDialog sub-Windows
quitsignalReceivedConfiguration Methods

R
ram memory, gStringgString Instantiation
ReformatFieldTextACWin Public Methods
RefreshFieldACWin Public Methods
RefreshWinACWin Public Methods
RTL textModifying Existing Data

S
S optionInvoking - Terminal Setup
sandbox testInvoking - AnsiCmd Tests
ScreenshotACWin Public Methods
ScrollFieldTextACWin Public Methods
secondary delimetersCSV Encoding
set localeInteger Formatting
SetBorderAttrACWin Public Methods
SetCursorPosACWin Public Methods
SetFieldAttrACWin Public Methods
SetFieldDataACWin Public Methods
SetFieldFlowACWin Public Methods
SetFieldHiddenACWin Public Methods
SetFieldHotkeyACWin Public Methods
SetFieldIPACWin Public Methods
SetFieldLabelACWin Public Methods
SetFieldOutlineACWin Public Methods
SetFieldStateACWin Public Methods
SetFieldTextACWin Public Methods
SetHilightModACWin Public Methods
setHiliteModskField Public Methods
SetInputFocusACWin Public Methods
SetReadOnlyACWin Public Methods
SetTextAttrACWin Public Methods
SetTitleACWin Public Methods
setup optionsInvoking - Terminal Setup
ShellOutACWin Public Methods
ShiftFieldTextACWin Public Methods
SidebarACWin Public Methods
skField classskField Public Methods
skField constructorskField Public Methods
skField operator=skField Public Methods
skForm classskForm Class
skForm constructorskForm Public Methods
skForm operator=skForm Public Methods
sleep_forMisc Methods
soft-echo optionsTerminal Configuration
source codeBuilding from Source
special keysTerminal Configuration
streams, i/oTerminal Configuration
support methodsDevelopment Support
support, technicalTechnical Support
suspendsignalReceivedConfiguration Methods
swscanf emulationExtract Formatted Data

T
technical supportTechnical Support
temporary filesAPI Methods
temporary filesThe TFMTest Application
temporary filesTFMan Class
TermConfig classTerminal Configuration
terminal configurationTerminal Configuration
terminal testInvoking - AnsiCmd Tests
TermSet classTerminal Configuration
test methodsDevelopment and Testing
test the buildBuilding from Source
test, asciiInvoking - AnsiCmd Tests
test, colorInvoking - AnsiCmd Tests
test, dialogInvoking - AnsiCmd Tests
test, erasureInvoking - AnsiCmd Tests
test, fontInvoking - AnsiCmd Tests
test, ideographInvoking - AnsiCmd Tests
test, positioningInvoking - AnsiCmd Tests
test, sandboxInvoking - AnsiCmd Tests
test, terminalInvoking - AnsiCmd Tests
test, windowInvoking - AnsiCmd Tests
testing optionsInvoking - AnsiCmd Tests
Test_4BitDevelopment and Testing
Test_8bitColorDevelopment and Testing
Test_acaExpandDevelopment and Testing
Test_acaExpandSwapDevelopment and Testing
Test_AixFgBgDevelopment and Testing
Test_AltFontsDevelopment and Testing
Test_AsciiCodesDevelopment and Testing
Test_BgDevelopment and Testing
Test_BoxDevelopment and Testing
Test_Clipboard_APIDevelopment and Testing
Test_Clipboard_WinDevelopment and Testing
Test_CookieDevelopment and Testing
Test_CursorPosDevelopment and Testing
Test_DialogDevelopment and Testing
Test_ErasuresDevelopment and Testing
Test_FifoDevelopment and Testing
Test_FormDevelopment and Testing
Test_GreyscaleDevelopment and Testing
Test_HiliteDevelopment and Testing
Test_IdeogramDevelopment and Testing
Test_LaunchExtDevelopment and Testing
Test_LineDevelopment and Testing
Test_MenuDevelopment and Testing
Test_ModFlagsDevelopment and Testing
Test_NonBlockDevelopment and Testing
Test_OutputStreamDevelopment and Testing
Test_RawInputDevelopment and Testing
Test_RGBDevelopment and Testing
Test_SandboxDevelopment and Testing
Test_SoftEchoDevelopment and Testing
Test_TermFlagsDevelopment and Testing
Test_TfmanDevelopment and Testing
Test_UnbufferedInputDevelopment and Testing
Test_WinDefaultDevelopment and Testing
Test_WindowDevelopment and Testing
Test_WrapDevelopment and Testing
Test_WriteDevelopment and Testing
text conversion, gStringgString Text Tool
text eraseText Erase
text modifiersText Modifiers
TFManIntroduction
TFMTest appThe TFMTest Application
timeout, blinkCursor Positioning
timeout, blinkingInvoking - Terminal Setup
tseReportDevelopment Support
ttyWriteOutput Methods

U
Unicode codepointACWin Public Methods
user interface controlsUI Control Types

V
verbose optionInvoking - EarthPoints
version optionInvoking - EarthPoints

W
W optionInvoking - Terminal Setup
WaylandCBIntroduction
web-safe indicesAPI Methods
window optionInvoking - EarthPoints
window testInvoking - AnsiCmd Tests
WinInfoACWin Public Methods
WriteACWin Public Methods

Z
Z optionInvoking - Terminal Setup

~
~skFieldskField Public Methods