7526 CFR Sample Library of Utility Functions
--------------------------------------------

Introduction
------------
This library of utility Custom Function Routine functions provides various
useful, pre-written routines which help to speed development of CFRs for the
7526 Data Collection Terminal.

Included are:

- Routines to extract data from validation files by finding a specific record
  offset or a numbered record
- A binary validation file search routine which greatly speeds the checking of
  a record in a validation file of fixed length, sorted records.
- A version of sprintf() which is written specifically for use on the
  data collection terminal
- Higher level print functions for 7526's equipped with printer-capable
  processor boards.
- Format the time and date into strings
- Get the current time, represented as seconds since January 1, 1900 at
  mid-night.
- Control input from sensor ports and/or keypad, forcing numeric input to
  valid forms, handling scanner errors, and allowing cursor control within the
  input field.
- Write a character a number of times to the display

Source code is available for educational purposes, for creation of derivative
functions, and for fixing of any defects which may exist in the code.

Function Reference
------------------

BinaryValidation
----------------
Description:  This function performs a validation of the presence or absence of
  a match between a string and the records of a validation file, using a binary
  searching method.  The binary search can yield a much faster search time when
  the validation file has many records.

  For example, while the 7526 has built-in binary file searching, programs like
  Data Collector and DCC/2 do not inform the terminal that the files are sorted
  (even though they most often actually are) so it uses a sequential search.
  For a 3,000 record employee badge file (each record about 10 characters), the
  search can take about 3 seconds.  With this binary search, the elapsed time
  is less than 0.5 seconds (its so fast, it is hard to measure).

  Records must be of fixed length, and must be sorted into ascending order.
  An example of a properly formated validation file is:

   123456789
   222222222
   987654321

  If the file is not found on the terminal, the function will return
  FILE_NOT_FOUND.  Otherwise, it will return VAL_PASSED or VAL_FAILED,
  depending on the seach type which was requested and the results of the
  search.

C Format:

  int BinaryValidation(
   (
    char * ValFilename,        // The validation file name

    char type,                 // The validation type desired, either
                               // INCL_SKIP_IF_FAIL or
                               // EXCL_SKIP_IF_FAIL.

    char * data                // The string to compare against.
   );

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  int far main (int funct,char far *params)
   {
    USHORT xfrcnt;                   // Vio transfer count
    char filename[13];
    char badge_read[40];

    ...

    strcpy(filename, "BADGES.VAL");

    type = INCL_SKIP_IF_FAIL;

    // get data passed from transaction program
   ReadUserVariable(0, badge_read);

   // Try to do binary validation.  If file is
   // not found, resort to trying the regular
   // Validation routine, which will try to
   // do a host-based validation.
   rc = BinaryValidation(filename, type, badge_read);

   if (rc == FILE_NOT_FOUND)
    {
     // try regular support
     // (returns E_OK or E_DATA_NOT_FOUND,
     // which in the case of inclusive validation
     // are the same as VAL_PASSED and VAL_FAILED
     // as returned by the BinaryValidation routine.
     rc = Validation(filename, badge_read);
    } /* endif */

   // handle results...
   switch(rc)
    {
     case VAL_PASSED:
     case E_OK:
       // more...
       break;
     case VAL_FAILED:
     case E_DATA_NOT_FOUND:
       // more...
      break;
     case E_HOST_DOWN:
       // more...
      break;
     case FILE_NOT_FOUND:
       // more...
      break;
    }

   ...
  }

format_date
-----------
Description: This function reads the current date from the DCT's real-time
  clock and formats the data into strings which are ready for presentation or
  printing.  You can specify AMERican or EUROpean format and the character you
  want as the months-days-years delimiters.

  You must provide the addresses of two data areas:

  - A buffer of at least 9 characters in length for the time string with
    delimiters between the date elements
  - A buffer of at least 7 characters in length for a compact string with
    no element delimiters

C Format:

  void format_date
   (
    char * formatted_date, // A pointer to a results work area which your
                           // program must provide for the formatted date
                           // with delimiters in place -- minimum size 12 bytes

    char * no_delim_date,  // A pointer to a results work area which your
                           // program must provide for the formatted date
                           // with no delimiters used -- minimum size 9 bytes

    char form,             // The form of the date string; defines are
                           // EURO (DD.MM.YY) or AMER (MM/DD/YY)

    char date_delimiter    // The character you want used between date
                           // elements
   );

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"


  int far main (int funct,char far *params)
   {
    char date_str[9], short_date[7];  // data return areas

    ...

    // get the current date for printing
    format_date(date_str, short_date, EURO, '.');

    ...
   }

format_time
-----------
Description: This function reads the current time from the DCT's real-time
  clock and formats the data into strings which are ready for presentation or
  printing.  You can specify 12 or 24-hour time and the character you
  want as the hours-minutes-seconds delimiters.

  You must provide the addresses of two data areas:

  - A buffer of at least 12 characters in length for the time string with
    delimiters between the time elements
  - A buffer of at least 9 characters in length for a compact string with
    no element delimiters


C Format:

  void format_time
   (
    char * formatted_time, // A pointer to a results work area which your
                           // program must provide for the formatted time with
                           // delimiters in place -- minimum size 12 bytes

    char * no_delim_time,  // A pointer to a results work area which your
                           // program must provide for the formatted time with
                           // no delimiters used -- minimum size 9 bytes

    int form,              // The form of the time string; defines are
                           // HHMMSS_24 and HHMMSS_12

    char time_delimiter    // The character you want used between time elements
   );


Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  int far main (int funct,char far *params)
   {
    char time_str[12], short_time[9];  // data return areas

    ...


    // get the current time for printing
    format_time(time_str, short_time, HHMMSS_24, ':');

    ...
   }


GetRecord
---------
Description: This function returns a pointer to any numbered record within
  an on-board terminal validation file. The pointer is to the beginning of the
  record number prefix text.

  Records may be fixed or variable length.  The record number is a zero-padded,
  ascending prefix at the beginning of each record.  Each record in a 7526
  validation file is delimited by a record separator character (character 30d;
  1E hex).  The record prefix may be from 1 to 5 characters in length.  The
  records must be sorted into ascending order, but need not be consecutive.

  An example of a properly formated validation file is:

    00001 This is record 1
    00100 This is record 100
    11000 This is record 11000

  Because the records are sorted, this function can perform a binary search for
  the desired record, resulting in very fast access to any record in a large
  file.

  If the record cannot be found in the file, or the file cannot be found,
  a NULL is returned for the pointer.

C Format:

  char * GetRecord
   (
    char *        val_file_name,           // Validation file name

    unsigned int  record_number,           // Desired record number

    UCHAR         digits                   // Number of digits in zero-padded
                                           // prefix string.
   );

Example:

  #include "cfrutl26.h"
  #include "CFRAPI26.h"

  #define PREFIX    5          // 5 digit prefixes used here
  #define MAX_WIDTH 80
  #define RS        "\x1E"     // Record separator string

  int far main (int funct, char far *params)
   {
    USHORT       xfrcnt;                   // Vio transfer count
    char         filename[13];
    char       * help_ptr;
    unsigned int help_rec;
    int          LenRS;                    // length to first RS
                                           // character.
    char         temp[MAX_WIDTH+1];

    ...

    strcpy(filename, "HELP.VAL");

    help_rec = 155;  // Get record prefixed with 00155

    // get line from val file and show the part after the
    // record prefix.
    help_ptr = GetRecord(filename, help_rec, PREFIX);

    if (help_ptr == NULL)
     {
      char temp[35];
      strcpy(temp,"Could not find record #");
      itoa((int)msg_start + ctr, &temp[24], 10);
      VioWrtCharStr(temp, strlen(temp), 0,0, &xfrcnt, 0);
     }

    // Make a null-terminated string of the record's data
    // handle 'blank lines' in HELP.VAL which have no
    // characters but the terminator after the prefix.
   if (help_ptr[PREFIX] != 0x1E)
    {
     strncpy(temp,&help_ptr[PREFIX+1], MAX_WIDTH );
     // truncate at RS
     lenRS = strcspn(temp, RS);
     if ( lenRS != 0 )
       temp[lenRS] = '\0';
    }
   else
    {
     strcpy(temp," ");
    }

   VioWrtCharStr(temp, strlen(temp), 0, 0, &xfrcnt, NO_CURSOR_MOVE);

   ...
  }

get_seconds
-----------
Description: This function reads the current time and date from the DCT's
  real-time clock and converts it to an unsigned long integer representing the
  number of seconds which have elapsed since Janary 1, 1900 at midnight.
  This is useful for determining a point in time at which an event started
  or the current point in time for comparison to a starting time so that
  elapsed time can be calculated (i.e. for time-outs, durations, etc.).

C Format:

  unsigned long get_seconds(void);

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  int far main (int funct,char far *params)
   {
    unsigned long start_time;

    ...

    // get the starting time of the procedure
    start_time = get_seconds();

    // perform some function (e.g. watch for keypad data,
    // just sit and do nothing, show a message) for
    // 5 seconds
    do
     {
      // do something
      ...
     }
    while (get_seconds() - start_time <= 5);

    ...
   }


GetValRecord
------------
Description: This function returns a pointer to any absolute record within an
  on-board terminal validation file.  The function works by starting at the
  beginning of the file and counting records until it find the one requested.
  The first record in the file is considered absolute record zero.

  Records may be fixed or variable length.  Each record in a 7526 valiation
  file is delimited by a record separator character (character 30d; 1E hex).
  An example of a properly formated validation file is:

    This is record 0
    This is record 1
    This is record 2

  If the record cannot be found in the file, or the file cannot be found,
  a NULL is returned for the pointer.

C Format:

  char * GetValRecord
   (
    char *        val_file_name,            // Validation file name

    unsigned int  record_number             // Desired record number
   );

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  #define MAX_WIDTH 80

  int far main (int funct,char far *params)
   {
    USHORT       xfrcnt;                   // Vio transfer count
    char         filename[13];
    char       * help_ptr;
    unsigned int help_rec;
    char         temp[MAX_WIDTH+1];

    ...

    strcpy(filename, "HELP.VAL");

    help_rec = 155;  // Get record 155 (the 156th record
                     // from the beginning of the file

    // get line from val file and show the part after the
    // record prefix.
    help_ptr = GetValRecord(filename, help_rec);

    if (help_ptr == NULL)
     {
      char temp[35];

      strcpy(temp,"Could not find record #");
      itoa((int)msg_start + ctr, &temp[24], 10);
      VioWrtCharStr(temp, strlen(temp), 0,0, &.xfrcnt, 0);
     }

    // Make a null-terminated string of the record's data
    // by turning RS into NULL, if found before hitting
    // NULL put in by strncpy.
    strncpy(temp,help_ptr, MAX_WIDTH );

    // truncate at RS
    lenRS = strcspn(temp, RS);
    if ( lenRS != 0 )
      temp[lenRS] = '\0';

    VioWrtCharStr(help_ptr, strlen(help_ptr), 0, 0,
                  &.xfrcnt, NO_CURSOR_MOVE);
    ...
   }


GetValRecordFast
----------------
Description: This function returns a pointer to any absolute record within an
  on-board terminal validation file.  The function works by starting at the
  beginning of the file and counting records until it find the one requested.
  The first record in the file is considered absolute record zero.

  The function learns the location of each offset of 100 records on the first
  invocation of the function which searches to or past those locations.  On
  subsequent invocations, it already knows a short-cut to within 100 records
  of the final record.  This can save substantial time (as much as 1-2 seconds
  on large files) after the function gets warmed up.

  The validation file must be limited to under 1,099 records.

  The list of learned locations is only valid for the last file name used in
  the call.  If the next invocation requests another file name, the search must
  be done without benefit of learned locations.  Thus, if you alternate very
  frequently between files searched, the Fast function may be of little value.

  A side effect of the function is that the first character of the first record
  is changed to a '%' character.  This serves as a flag to the function that
  the validation file has not been reloaded since it learned the locations of
  the 100-record offsets.

  Records may be fixed or variable length.  Each record in a 7526 valiation
  file is delimited by a record separator character (character 30d; 1E hex).

  An example of a properly formated validation file is:

    This is record 0
    This is record 1
    This is record 2

  If the record cannot be found in the file, or the file cannot be found,
  a NULL is returned for the pointer.

C Format:

  char * GetValRecordFast
   (
    char *        val_file_name,           // Validation file name

    unsigned int  record_number            // Desired record number
   );

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  #define MAX_WIDTH 80

  int far main (int funct,char far *params)
   {
    USHORT       xfrcnt;                   // Vio transfer count
    char         filename[13];
    char       * help_ptr;
    unsigned int help_rec;
    char         temp[MAX_WIDTH+1];

    ...

    strcpy(filename, "HELP.VAL");

    help_rec = 155;  // Get record 155 (the 156th record
                     // from the beginning of the file

    // get line from val file and show the part after the
    // record prefix.
    help_ptr = GetValRecordFast(filename, help_rec);

    if (help_ptr == NULL)
     {
      char temp[35];

      strcpy(temp,"Could not find record #");
      itoa((int)msg_start + ctr, &temp[24], 10);
      VioWrtCharStr(temp, strlen(temp), 0,0, &.xfrcnt, 0);
     }

    // Make a null-terminated string of the record's data
    // by turning RS into NULL, if found before hitting
    // NULL put in by strncpy.
    strncpy(temp,help_ptr, MAX_WIDTH );

    // truncate at RS
   lenRS = strcspn(temp, RS);

   if (lenRS != 0)
     temp[lenRS] = '\0';

   VioWrtCharStr(help_ptr, strlen(help_ptr), 0, 0,
                 &.xfrcnt, NO_CURSOR_MOVE);
   ...
  }

pop_up_wnd
----------
Description: This routine saves the current screen contents and clears the
  screen so that a pop-up window may be displayed.  Another call to the routine
  will restore the display to its original content.  The entire screen is
  cleared, and an indication of the screen size (model) is returned.

C Format:

  unsigned char pop_up_wnd
   (
    char operation_code  // Either CLEAR to clear the window, or REFRESH
                         // to refresh the display with the orignal data.
   );

  Returns ONE_LINE_DISPLAY if 7526 model 100 with 1x16 display, or
  TWO_LINE_DISPLAY if 7526 model 200 with 2x40 display.

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  int far main (int funct,char far *params)
   {
    // key.code is an int for evaluating control key reads
    // key.chr.mapped gives the key character as mapped by any file a downloaded
    // key.chr.base gives the native, unchanging key character
    union
     {
      struct
       {
        char base;
        char mapped;
       }
      chr;
      unsigned short code;
     }
    key;

    ...

     // Clear a window, show an error message, wait for
     // a key to be pressed, and restore screen
    pop_up_wnd(CLEAR);

    VioWrtCharStr("Invalid numeric input",  11, 0 ,0 , &xfrcnt, NO_CURSOR_MOVE);
    VioWrtCharStr("Press any key to continue",  15, 1 ,0 , &xfrcnt, NO_CURSOR_MOVE);

    while (KbdReadAscii(&key.code) == E_NO_DATA)
      IdleManager(5);

    pop_up_wnd(RESTORE);

    ...
   }

print
-----
Description: This routine prints a string on a line printer, checking for
  return codes which may indicate a problem with the printing action.

  If given a length of 0, it treats the data to be printed as a null-terminated
  string and uses strlen to find size.  Otherwise, provide the length of the
  data to printer (e.g. if it has embedded nulls or you do not want to printer
  the entire string).

  Specify prt_buffer_size as DEFAULT_PRT (100 bytes) unless you have set a new
  buffer location and size.  The routine will break up longer strings into
  chunks which will fit into the current printer buffer, as defined to the
  routine in the buffer size passed to it.

  If prt_mode is set to 1 (STOP_ON_ERROR), the 7526 will prompt for user
  intervention when an error is encountered.  Use 2 (IGNORE_ERROR) to allow the
  terminal to ignore printer errors.

C Format:

  void print
   (
    char * prt,           // The string to be printed

    int length,           // Length of the string, or 0 if the string
                          // is null-terminated so that strlen may be
                          // used by the print function.

    int prt_buf_size,     // The current printer buffer size (DEFAULT_BUF if
                          // PrtSetBuffer has not been used to increase it.

    char prt_mode         // 1 (STOP_ON_ERROR) to have the 7526 not proceed
                          // until printer error is cleared, or 2 (IGNORE_ERROR)
                          // to ignore such errors.
   );

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  int far main (int funct,char far *params)
   {

    ...

    // print null-terminated string, correct printer errors
    print("Badge number", 0, DEF_BUFFER, 1);

    ...
   }

print_char
----------
Description: This routine prints a single character on a line printer,
  checking for return codes which may indicate a problem with the printing
  action.

  If prt_mode is set to 1 (STOP_ON_ERROR), the 7526 will prompt for user
  intervention when an error is encountered.  Use 2 (IGNORE_ERROR) to allow
  the terminal to ignore printer errors.

C Format:

  void print_char
   (
    char prt,             // The character to be printed

    char prt_mode         // 1 (STOP_ON_ERROR) to have the 7526 not proceed
                          // until printer error is cleared, or 2 (IGNORE_ERROR)
                          // to ignore such errors.
   );

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  int far main (int funct,char far *params)
   {

    ...

    // print null-terminated string, correct printer errors
    print_char('%', 1);

    ...
   }

read_auto
---------
Description: The read_auto function obtains keypad and/or sensor port input in
  the form desired, and shows it in the designated position on the screen.  It
  will control the method of data input, its maximum length, and numeric
  features such as signed/non-signed, integer or floating point.

  Data read is returned in key_in_num variable provided by the user. This
  buffer must be large enough to hold the length (plus 1) specified in the
  call.

  When keypad input is enabled, the following keys may be used when the
  function has control:

    Function                  Keys Used
    --------                  ---------
    Accept data               Left tab (shift-7), Right tab (shift-8), Enter,
                                or OK (Fill) keys.
    Cursor Left               Shift-4
    Cursor Right              Shift-5
    Backward Rub-out          Shift-6

                              Note: This key rubs-out the data immediately to
                                    the left of the cursor, and moves all text
                                    past the cursor along with it to the left.
    Clear                     Ends the input in a non-completed state and
                              returns CLEAR_KEY.

C Format:

  int read_auto
   (
    int length,     // Length of the input field; defines maximum keypad
                    // input length and the length of the underscored
                    // input field.  Maximum value is 39, assuming column
                    // 0 is used (see below).

    UCHAR row,      // Starting position of the input field.  (0,0) is the
    UCHAR col,      // upper left corner of the display.  The starting column
                    // plus the length (see above) must total 39 or less
                    // on a 40-character display, or 15 or less for a 7526-100.

    char inputs_allowed, // The input methods allowed in the field.  Defined
                         // input modes are:
                         //
                         //   AI_ONLY         Only bar code and magnetic
                         //                     sensor inputs are allowed
                         //   AI_OR_KEYBD     Sensor or full keypad input is
                         //                     allowed
                         //   KEYBD_ONLY      Only full keypad input is allowed
                         //   NUM_KEYBD_ONLY  Only numeric keys forming a valid
                         //                     number are allowed
                         //   AI_OR_NUMKEYBD  Only sensor input (any data) or
                         //                     valid numeric keys
                         //   DATE_AMER       Date in form DD-MM-YYYY
                         //   DATE_EURO       Date in form MM-DD-YYYY
                         //   TIME_STD        24 hour time in form HH:MM:SS

    char * prefill, // String of characters to prefill the input field.
                    // Use empty string for no prefill.  Time and date
                    // format will be filled with input template as a default.

    int time_limit, //  Number of seconds allowed of inactivity before timeout.
                    // Values are 1-65535, or 0 for no timeout enforced.

    char edit,      // Use defines YES and NO to allow editing of the prefilled
                    // data;  NO means prefilled data is cleared as soon as a
                    // data key is pressed.

    char field_signed,   // Use YES or NO defines to tell if the negative
                         // (change sign) key should be allowed.

    int field_precision, // -1 for no decimal point allowed, any other value
                         // allows decimal point to be input.

    char * key_in_num,   // String buffer for function to place obtained from
                         // sensors or keypad
   );

  Return values are:

   CLEAR_KEY if Clear key is pressed
   LEFT_TAB, RIGHT_TAB, OK_KEY (Fill key), or ENTER_KEY if one of those keys
     are pressed to accept the keyed input
   AI_READ if bar code or mag scanned
   TIME_OUT if time limit expired

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  #define BUFFER_SIZE  40

  int far main (int funct,char far *params)
   {
    char buffer[BUFFER_SIZE];
    int  rc;
    char prefill[10];

    ...

    strcpy( prefill, " 1.50");

    // read an signed, real number from the numeric keypad, allowing
    // up to 30 seconds for input.  Show the 10 position input field
    // at row 1, column 20, with a prefilled value.
    // Loop while operator presses Clear key
    do
     {
      rc =  read_auto(10, 1, 20, NUM_KEYBD_ONLY, prefill, 30,  YES, YES,
                      1, buffer);
      switch (rc)
       {
        case TIME_OUT:
          return(ABORT);
          break;
        case CLEAR_KEY:
          // re-do the read with no prefill
          strcpy(prefill, "");
          break;
       }
     }
    while( rc == CLEAR_KEY );

    // return data in UV 1
    WriteUserVariable(buffer, 1);

    ...
   }

sprintf_752x / sprintf_752xf
----------------------------
Description: sprintf_752x performs print string formating like the regular C
  library sprintf function provides, but without the PC-specific usage of
  stdout.  All aspects of the function work as printf/sprintf work, except the
  following:

  - The length of the target buffer area must be provided (to prevent buffer
    overruns.
  - The output may be automatically displayed at the requested row and column
    of the 752x display.  0,0 is the upper left corner of the display.  Use -1,
    -1 for non-display usage (e.g. for formating a transaction or printer
    string).
  - The F and N addressing convention prefixes are not supported.  The h prefix
    (short 'size') is not supported (USHORTS will work with the 'u' type).
  - The e, E, g, and G types will be converted to f type.
  - The n and p types are not supported.
  - The # flag is not supported for any type.

  The sprintf_752xf named version of the routine has the floating point support
  included.  This adds several kilobytes of storage requirements over the basic
  sprintf_752x version.  However, if you need floating point numbers formated
  in a CFR, you should use the floating point version for all calls to avoid
  redundant code being included in the file.

C Format:

  int sprintf_752x
   (
    char * buffer,         // A pointer to a results work area which your
                           // program must provide

    int buf_size,          // The size (in characters) of the buffer provided
                           // (see above)

    int row,               // The row and column where you want the resulting
    int col,               // string shown on the screen.  If you do not want
                           // the string shown, then specify row = -1 (the
                           // column value may be anything).

    char far * format_str, // The output format string specification.  Refer
                           // to the IBM C/2 1.10 Language Reference under
                           // "printf" for details.

    ...                    // The variable number of numeric values, characters,
                           // and/or string pointers in the order referenced
                           // in the format string.
   );

  Return values are:
  - OVERFLOW if the resulting string will not fit within the buffer provided
  - BAD_WIDTH if a width specified is more than 2 digits long
  - BAD_PREC if a precision specified is more than 2 digits long
  - BAD_FORMAT_PHRASE if a "%" character is found with no valid trailing
      type specifier.
  - E_OK if no error occured.

  In the event of an error, the formatted string obtained up to the point of
  the error is available.  Also, if optional automatic display was selected,
  the following strings will be appended to the display to show the error
  result:

  - *** shows that the formatted result exceeded the length of the supplied
        buffer
  - *1* shows that a bad width was specified for a field
  - *2* shows that a bad precision value was specified
  - *3* shows that an unknown format identifier was used

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  #define BUFFER_SIZE  100

  int far main (int funct,char far *params)
   {
           char buffer[BUFFER_SIZE];
    static int  number = 27;
    static char string[] = "Hello World";

    ...

    // format a string and show at upper left corner of the display.  In this
    // example, will show "String = Hello World, Decimal = 27, Hex = 1B"
    sprintf_752x(buffer, BUFFER_SIZE, 0, 0,
                 "String = %s, Decimal = %d, Hex = %X",
                 string, number, number);

    ...
   }


VioWrtNChar
-----------
Description: This function writes a given character a specified number of
  times, begining at a specified location on the display.

C Format:

  void VioWrtNChar
   (
    unsigned char row,            // Row for characters to be shown (0 is top)

    unsigned char col,            // Starting column  (0 is left edge)

    unsigned char Char,           // The character to be replicated

    unsigned short count,         // The # of times to replicate the character

    unsigned short * xfrcnt,      // The # of characters successfully written

    unsigned char cursor_movement // CURSOR_MOVE or NO_CURSOR_MOVE
   );

Example:

  #include "cfrutl26.h"
  #include "cfrapi26.h"

  int far main (int funct,char far *params)
   {
    unsigned short xfrcnt;

    ...

    // Draw a line of asterisks across the screen
    VioWrtNChar(0, 0, '*', 40, &xfrcnt, NO_CURSOR_MOVE);

    ...
   }