------------------------------- Page    i -------------------------------

                              C Quickscreen

                              User's Guide

------------------------------- Page   ii -------------------------------

                            TABLE OF CONTENTS


1.    Introduction  . . . . . . . . . . . . . . . . . . . . . . . . .   1

2.    Full Screen I/O . . . . . . . . . . . . . . . . . . . . . . . .   1

3.    A Simple Example  . . . . . . . . . . . . . . . . . . . . . . .   1

4.    How to Run Quickscreen  . . . . . . . . . . . . . . . . . . . .   3

5.    Where to Put Quickscreen Constructs . . . . . . . . . . . . . .   4

6.    The At Construct  . . . . . . . . . . . . . . . . . . . . . . .   5

7.    The Panel Construct . . . . . . . . . . . . . . . . . . . . . .   5

7.1      Commands . . . . . . . . . . . . . . . . . . . . . . . . . .   6
7.2      Constant Text  . . . . . . . . . . . . . . . . . . . . . . .   7
7.3      Embedded Fields  . . . . . . . . . . . . . . . . . . . . . .   7
7.4      Embedded Ats . . . . . . . . . . . . . . . . . . . . . . . .   9
7.5      Which Key Was Pressed and Where Was the Cursor?  . . . . . .  11
7.6      Which Fields Were Changed and Where Were those Fields? . . .  13

8.    The Erase Input Construct . . . . . . . . . . . . . . . . . . .  15

9.    The Copyscreen Construct  . . . . . . . . . . . . . . . . . . .  15

10.   How to Debug Quickscreen Programs . . . . . . . . . . . . . . .  16

11.   Advanced, Hard, Obscure, and Rarely Used Features . . . . . . .  17

11.1     Advanced Panel Commands  . . . . . . . . . . . . . . . . . .  17
11.2     Trimming Blanks and Double Characters  . . . . . . . . . . .  18
11.3     Waiting and Sleeping . . . . . . . . . . . . . . . . . . . .  19
11.4     C Source Within a Panel  . . . . . . . . . . . . . . . . . .  20
11.5     PA1 - PA2 Problems . . . . . . . . . . . . . . . . . . . . .  20
11.6     Who Has the Tube?  . . . . . . . . . . . . . . . . . . . . .  21

12.   References  . . . . . . . . . . . . . . . . . . . . . . . . . .  21

Appendix A.    Converting Old Quickscreen Programs  . . . . . . . . .  22

Appendix B.    Exact Definitions of the At Construct and the Embedded
               At . . . . . . . . . . . . . . . . . . . . . . . . . .  23

Appendix C.    Quickscreen Runtime Routines . . . . . . . . . . . . .  24

------------------------------- Page  iii -------------------------------

                                                            Last Page  25




                             TABLE OF TABLES


Table 1.    Table of Types  . . . . . . . . . . . . . . . . . . . . .   8

Table 2.    Table of Key Pressed Values . . . . . . . . . . . . . . .  11

-------------------------------- Page  1 --------------------------------

1.    INTRODUCTION

Quickscreen is an extension to C for  doing full-screen I/O to 3270  type
terminals.  It consists of a preprocessor and a set of  runtime routines.
The preprocessor  translates quickscreen  constructs within  a C  program
into C function  calls.  For  many applications, the  description of  the
screen in the program is  very close to its  appearance on the  terminal.
The present version used  their work as  a foundation.  Appendix A  lists
the few  items in  old quickscreen  programs which  need to  be  changed.
Appendix B contains definitions of exactly what the at construct  and the
embedded at do.  Appendix C contains definitions of the quickscreen  run-
time routines.




2.    FULL SCREEN I/O

Terminals are commonly used in  one of two  modes: line-by-line or  full-
screen.  In line-by-line mode the programmer displays one line at  a time
on the screen.  The terminal user may enter only one line of  information
at a time.  This mode  of terminal I/O is suitable for many  applications
and is fully supported by UTS.

Full screen mode permits the programmer to display a whole screen of data
at one time and allows  the terminal user to enter data at more than  one
place on  the screen.   This  increased flexibility  is very  useful  for
interactive techniques such as  menu selection, form filling, text  edit-
ing, and board games.




3.    A SIMPLE EXAMPLE

The following example will introduce the "at" and "panel" constructs  and
give you an  idea of  how they look.   When this program  is run it  will
erase the screen and ask the user to enter their name and age.  If  their
name was not "joe"  it will ring the  terminal bell and display an  error
message.  If the age is  over 99, it will erase  the screen and say  "You
are very old!".

        main()
        {
                int age;

-------------------------------- Page  2 --------------------------------

                char name[20], sage[5];

                name[0] = '\0';
                sage[0] = '\0';

                at 101;
                panel {
                Hello there.
                Please type your name: #INC,name,15#
                         and your age: #II ,sage, 4#
                }

                age = atoi(sage);
                if (strcmp(name,"joe") != 0) {
                        at 501;
                        panel(noerase,bell,cursor = 2480) {
                        Sorry #ON,name#, but you are not joe.
                        #@2401#ERROR!! ERROR!!
                        }
                } else if (age > 99) {
                        at 101;
                        panel(cursor = 2480) {
                        You are very old and wise!
                        }
                }
        }

The first statement puts a null byte into the char arrays name and  sage.
This  will  insure  that  these  fields  will  appear  blank  when  first
displayed.  The first word on the next  line is "at".  Qs will  recognize
this line as an "at" quickscreen construct.  This construct says that the
information in the next screen should begin at row 1 column 1.

The next  line starts  with "panel"  and is  the beginning  of a  "panel"
quickscreen construct.  The line "Hello  there." is inside the panel  and
will appear on the first line of the screen.   On line 2 will be  "Please
type your name: ".  The next character is a sharp '#' which has a special
meaning to qs.   It marks  the beginning (and  the end)  of an  "embedded
field".  The  "INC"  means  that  this field  is  an Input  field  to  be
displayed at Normal intensity and that the Cursor should be placed  here.
The field will come right after "name: ".  Characters typed in this field
will be placed in the variable name.  A maximum of 15 characters will  be
read.

-------------------------------- Page  3 --------------------------------

The next line is very  similar.  A maximum of 4  chars will be read  into
the variable sage.  The"II" means Input Invisible.  The characters  typed
will not appear on the screen.  This can be used to protect vital  infor-
mation like ages and passwords.

After the user enters their name and age  and presses the ENTER key,  the
program will continue to the next statement.  The variables name and sage
will contain the data entered.

The characters in sage are converted into the integer age with atoi.

If the name is not "joe", another panel construct will be executed.  This
one is more complicated.   Following the word  "panel" is a list of  com-
mands that control  how the  screen will be  displayed.  "noerase"  means
that the previous screen will not be erased.  The "Hello  there." and the
other lines will remain.  The terminal bell will be rung (beeped) and the
cursor will  be placed  at row  24 column  80.  If the  name entered  was
"david",

        Sorry david, but you are not joe.

would be displayed at row 5 column 1.  "ON" means that this is an  Output
field displayed at Normal intensity.  There is no length parameter  after
"name" so the string length (strlen) of "name" is used.  This many  char-
acters from the "name" array will be displayed.  The next  thing enclosed
in #'s,

        #@2401#

is an "embedded at".  It will cause "ERROR!! ERROR!!" to be placed at row
24 column 1.




4.    HOW TO RUN QUICKSCREEN

Quickscreen is invoked by  the "qs" command.   Qs examines its  arguments
for names ending in ".q".  These are files which contain quickscreen con-
structs intermingled with C code.  Qs translates these constructs into  C
function calls and puts the output in a file with  the same name but with
a suffix of ".c".

-------------------------------- Page  4 --------------------------------

If qs finds no errors, it will call the  C compiler with almost the  same
arguments.  There are two differences:

  *  All ".q" suffixes will be changed to ".c".

  *  The argument "-lq" will be added at the end.

The  runtime   routines  that   quickscreen   uses  are   in   the   file
"/usr/lib/libq.a".  The "-lq" argument will be passed along to the loader
which will include this file.  If you use the "-c" option to suppress the
loading, you will need to  use "-lq" when you call the loader later.   If
you forget it, the loader will complain that several names beginning with
"qs" are undefined.

If there are no compilation errors the ".c"  files created by qs will  be
removed.

The "-q" option on qs will run the preprocessor to create the ".c"  files
but not call the C compiler.

The command "mqs" does the same thing as "qs" but makes correcting errors
very easy.  If there  are errors either in the  ".q" file or in the  ".c"
file it will ned the ".q" file with  the error messages placed after  the
line to which they refer.  For details do a "man  mqs".  If mqs prints an
error referring to the .c file, it means that there is an error within  a
panel construct {#7} that the  preprocessor could not catch.  It is  most
likely caused by an  illegal expression within  an embedded field.   Make
the correction in the ".q" file not the ".c" file.




5.    WHERE TO PUT QUICKSCREEN CONSTRUCTS

Quickscreen constructs can be intermingled  with lines of  C code in  any
order.  All constructs  begin with  one of the  keywords, "at",  "panel",
"erase", or "copyscreen" which must be the first word on the line.  Files
containing quickscreen constructs should have names that end with ".q".

-------------------------------- Page  5 --------------------------------

6.    THE AT CONSTRUCT

The at construct controls where the  information on the next screen  will
begin.  It should be put right before a panel construct.  The syntax is:

        at  expr  ;

Expr is an arbitrary  C expression which  evaluates to a  row and  column
position.  This position is an integer that is calculated by  multiplying
the row  by 100  and adding  the column.   Rows range  from 1  to 24  and
columns from 1 to 80.

        at 1040;
        panel {
        Hello there.
        }

The 'H' will be placed at row 10 column 40.

        pos = 56;
        at(pos+200);

This will yield "at row 2 column 56".

Embedded ats {#7.4} can be used instead of the at construct.  See  appen-
dix B for an exact definition of what the at construct does.




7.    THE PANEL CONSTRUCT

The panel construct acts like an I/O statement by displaying text on  the
screen, waiting for a user action, and then returning the user's response
to the program.  The general syntax is:

        panel ( command list ) {
        text lines
        }

Commands should be separated by  commas.  If there  are no commands,  the
enclosing parentheses may  be omitted.   If there are  no text lines  the
braces may be replaced by a  semicolon.  /* Comments */ can be placed  to
the right of the panel  construct.  Text lines can contain 3 items:  con-
stant text {#7.2}, embedded fields  {#7.3}, and embedded ats {#7.4}.   If
the command list or a  text line is very long it can be continued to  the
next line by ending it  with a \.  Tabs at  the beginning of a text  line

-------------------------------- Page  6 --------------------------------

are translated into 8 blanks.   The indentation of text lines within  the
panel has no effect on their display.

        panel {
        Dear Pat,            /* July 3, 1980 */
           Thank you.
        }


        panel {              /* July 3, 1980 */
                Dear Pat,
                   Thank you.
        }

These two panels are equivalent.  The first has a nice rectangular clean-
ness about it and the second is more consistent with C coding standards.


7.1      COMMANDS

Three things need to be known when displaying any screen:

 a.  Should the old screen be erased or should  the new data be added  to
     the old?

 b.  Should the terminal bell be rung?

 c.  Should the keys be locked? (forcing the user to press the RESET  key
     before continuing).

The default actions are to erase the screen,  not ring the bell, and  not
lock the keys.  If  you don't want these  defaults you should use one  of
the commands  "noerase", "bell",  or  "lock".  There  are  also  commands
"erase", "nobell", and "nolock" which  can be used for purposes of  clar-
ity.

If you wish a command  to be conditional you can  use the forms "erase  =
expr", "bell = expr", and "lock = expr".  In the following panel:

        panel(erase = ntries < 4,bell,nolock) {
          ...
        }

the screen will be erased only if ntries is  less than 4.  The bell  will
be rung and the keys will not be locked.

-------------------------------- Page  7 --------------------------------

The command "cursor = expr" will cause the cursor to be placed at the row
and column position given by the expression {#6}.  If this command is not
given then the cursor  is placed at  the beginning of  an embedded  field
{#7.3} that specified the  cursor.  What if  there was no cursor  command
and no embedded field {#7.3} that specified  the cursor (not a good  pro-
gramming practice)?  If the  screen was not  erased then the cursor  will
remain where it was.  If the screen was erased it will be placed at loca-
tion 101.

See {#11} for some special purpose tricky commands.


7.2      CONSTANT TEXT

Within text lines,  embedded fields  and embedded ats  are surrounded  by
#'s.  Everything else (including  blanks) is constant  text.  It will  be
displayed at normal intensity exactly as shown.

        at 204;
        panel {
          Dear Mary,
             How are you?
        I am fine.
        }

The 'D' will be  put at 204.  The  rest of the  panel is positioned  with
reference to it.  The 'H' will be at 307 and the 'I' at 402.  The rest of
the screen will be blank.  If you want to display a '#' or want  constant
text at  high intensity,  use a  string constant  as the  variable in  an
embedded field.


7.3      EMBEDDED FIELDS

Embedded fields are used within  text lines for the  input and output  of
program variables.  The syntax consists of 3 expressions inside of #'s:

        # type, variable, length #

Type describes the characteristics of  the field.  It determines  whether
the field is to be  used for input or output, the intensity of the  field
(normal,  high,  or  invisible),  the  type  of  variable  (character  or
integer), and whether or not the cursor should be put there.  Valid types
include the symbols and values in the following table:

-------------------------------- Page  8 --------------------------------

               |_______|_______|________________________|
               |_SYMBOL|__VALUE|__MEANING_______________|
               | ON    |    1  |  Output Normal         |
               | OH    |    2  |  Output High           |
               | OI    |    3  |  Output Invisible (?)  |
               | IN    |    4  |  Input Normal          |
               | IH    |    5  |  Input High            |
               | II    |    6  |  Input Invisible       |
               | INC   |    7  |  Input Normal Cursor   |
               | IHC   |    8  |  Input High Cursor     |
               |_IIC___|____9__|__Input_Invisible_Cursor|

                       Table 1.    Table of Types

Variable should be a character pointer.   It points to the characters  to
be displayed.  For input  fields, variable should  be declared as a  char
array because the user response will be stored in it.

Length is the length of  the field.  At most  length characters from  the
variable will be displayed.  If  a null byte is reached, the rest of  the
field will be filled with nulls (they  appear blank on the screen).   For
input fields, at most length  characters will be stored in the  variable.
Character arrays used as  input variables should  have room for  length+1
bytes because a null byte will be added at the end.

Input fields are also output fields.   Data in the variable is  displayed
and the user is  given the ability  to change it.   If you want an  input
field to  be initially  blank, its  first byte  should be  null.   Output
fields cannot be altered by  the user and the keys will lock if he  tries
to do so.

        main()
        {
                char name[16];

                strcpy(name,"allen");
                at 1001;
                panel {
                Please verify your name: #INC,name,15#
                }
        }

This program will erase the screen, display:

        Please verify your name: allen

on line 10, and  put the cursor on  the 'a' in  "allen".  The user  could
then change the name  in any way  by overtyping, inserting, deleting,  or
adding.  If he  changed "allen"  to "alan"  and pressed  ENTER, the  char

-------------------------------- Page  9 --------------------------------

that was 15 characters long, it would have just fit in the array.

A few syntactic problems (or features):

  *  If type begins with a digit, the comma  after it may be omitted  and
     variable will begin with the next character.

  *  If length is <=  0 or omitted  (with the preceding  comma), it  will
     become strlen(variable).

  *  If there is only one expression between  the #'s, it will be  inter-
     preted  as  variable.   Type   will  be  ON   and  length  will   be
     strlen(variable).

  *  Embedded fields  cannot be  adjacent.  There  must be  at least  one
     blank between them.  Constant text can be adjacent to type ON fields
     but not to any others.

These features allow many ways to code embedded fields:

        #hello#   #1hello#   #1hello,6#   #1,hello,6#

        #ON,hello#   #ON,hello,6#

The last two are recommended.

Here are two uncommon uses of embedded fields:

        # OH, "WARNING!" #

        #i+4, (j == 2)? hello: goodbye, m+(n/4)#

The first displays constant  text at  high intensity.  The  second has  a
non-constant expression for  type, variable, and  length.  See the  value
column in the table of types.


7.4      EMBEDDED ATS

Embedded ats are used within text lines to reposition text on the screen.
The syntax is:

        #@ expr #

Expr is a row and column position {#6}.

-------------------------------- Page 10 --------------------------------

        at 101;
        panel {
        Dear Ernest,
        #@2004#How are you.
        I am fine.
        }

The 'D' will be at 101.
The 'H' will be at 2004.
The 'I' will be at 2104.

Each embedded at establishes a reference point which is used to  position
succeeding constant text and embedded fields.

It is  a weakness  of quickscreen's  syntax that  field descriptions  are
embedded within the panel.  In this example:

        #@303##ON,hello,1# I am fine.
          How are you.

the 'I' and the 'H' will be lined up on  the screen even though they  are
far apart in the panel.  The problem is that the field description in the
panel is not the same length as the field on the screen.  This is an awk-
ward problem that might be solved like this:

        #@205#
        I am fine.
        How are you.
        #@303##ON,hello,1#

but then it's not clear that the variable hello and "I am fine." will  be
on the same line.  The  at construct {#6} can be used instead of an  ini-
tial embedded at and is often clearer:

        at 201;
        panel {           panel {               panel {
        Dear Annie,       #@201#Dear Annie,     #@101#
        How are you       How are you.          Dear Annie,
        }                 }                     How are you.
                                                }

These are all equivalent.

What if there is  no preceding at  construct and no  initial embedded  at
(not a good programming practice)?


        main()
        {

-------------------------------- Page 11 --------------------------------

                panel {
                Dear Ethyl,
                How are you.
                }

                panel {
                I am fine.
                }
        }

The first panel  will use  a default "at  101;".  The  second will  begin
where the first one left off (the 'I' will be at 301).

See Appendix B for an exact definition of what the embedded at does.


7.5      WHICH KEY WAS PRESSED AND WHERE WAS THE CURSOR?

When a panel construct is executed, quickscreen sets the variable qskp to
a value indicating which "action key" the user pressed to enter the data.
The values are as follows:

                           __________________
                          |__SYMBOL__|_VALUE|
                          |_ENTER____|____0_|
                          | PF1      |    1 |
                          | PF2      |    2 |
                          | PF3      |    3 |
                          | PF4      |    4 |
                          | PF5      |    5 |
                          | PF6      |    6 |
                          | PF7      |    7 |
                          | PF8      |    8 |
                          | PF9      |    9 |
                          | PF10     |   10 |
                          | PF11     |   11 |
                          | PF12     |   12 |
                          | PA1      |   25 |
                          | PA2      |   26 |
                          | CLEAR    |   28 |
                          | TEST REQ |   29 |
                          | OTHER    |  100 |
                          |__________|______|

                 Table 2.    Table of Key Pressed Values


When making comparisons with qskp  you can either use  the symbol or  the
value.  Qs will define the symbols for you by doing a

-------------------------------- Page 12 --------------------------------

        #include <qsdefs.h>

This file also contains definitions of the type symbols, ON, OH, ...  and
declarations of qskp, qscrow, qsccol, qsmod, qspos.

The variables qscrow and qsccol  are set to the  row and column  position
that the cursor was on when the user pressed the action key.

An example illustrating these ideas:

        panel {
        ...
        }

        if (qskp == PF3)
                writefile();
        else if (7 <= qskp && qskp <= 11 && qskp != PF9)
                scroll();
        else if (qskp == TESTREQ)
                abort();

        if (qscrow < top || bottom < qscrow)
                switchscreens();

There are three problems with the action keys:

  *  PA1 will normally kill a full-screen program by sending an interrupt
     signal to it.  If you want to avoid this you should use:

                signal(SIGINT,SIG_IGN);

            or  signal(SIGINT,catch);

     Do a "man  signal" for details.   PA2 does  not send a  signal to  a
     full-screen program.

  *  If the  user presses  PA1, PA2,  or CLEAR,  any data  he entered  in
     fields on the screen will  not be stored in the corresponding  vari-
     able.

  *  If the user presses PA1, PA2,  CLEAR, or TESTREQ, qscrow and  qsccol
     will not be set.

See {#11.5} for a technique to partially remedy the last two problems.

-------------------------------- Page 13 --------------------------------

7.6      WHICH FIELDS WERE CHANGED AND WHERE WERE THOSE FIELDS?

If you want to process only those input fields that the user has modified
you can  use the function  qsmod.  Qsmod  returns 1 if  its argument  was
modified on the screen and 0 otherwise.

The function qspos returns  the row  and column position  {#6} where  its
argument was  displayed.  It  can be  used to  position the  cursor at  a
specified field without knowing exactly where it is.

The following program illustrates several  techniques.  It asks the  user
for their name, age, and  sex.  Name must not have any digits in it,  age
must be a positive integer, and sex must be 'm' or 'f'.  If any of  these
checks fail, the bell will ring, an error message will  be displayed, and
the cursor will be placed  on the erroneous field.  If  a field passes  a
check it will not  be checked again unless  it is modified.  Age and  sex
will be invisible unless an error is made in  which case they will be  in
high intensity.  The program cannot  be killed but the user can abort  by
pressing TEST REQ.  The functions anystr and patoi would also need to  be
written.

-------------------------------- Page 14 --------------------------------

#include <signal.h>

main()
{
        int pos;
        char *msg, *digits;
        char name[11], age[4], sex[2];

        signal(SIGINT,SIG_IGN);
        digits = "0123456789";
        msg = "";
        *name = 0;
        *age = 0;
        *sex = 0;
        /*
         * unfortunately we cannot say
         *    pos = qspos(name);
         * because name has not yet been displayed.
         */
        pos = 207;

        while (1) {
                at 101;
                panel(cursor = pos, bell = *msg) {
                #ON,msg#
                name? #IN,name,10#
                 age? #(*msg)? IH: II,age,3#
                 sex? #(*msg)? IH: II,sex,1#
                }

                if (qskp == TESTREQ)
                        exit(1);
                if (!*name ||
                    (qsmod(name) && anystr(name,digits) >= 0)) {
                        msg = "invalid name";
                        pos = qspos(name);
                } else if (!*age ||
                           (qsmod(age) && patoi(age) <= 0)) {
                        msg = "invalid age";
                        pos = qspos(age);
                } else if (!*sex ||
                           (qsmod(sex) && !any(*sex,"mf"))) {
                        msg = "sex must be m or f";
                        pos = qspos(sex);
                } else
                        exit(0);
        }
}

-------------------------------- Page 15 --------------------------------

8.    THE ERASE INPUT CONSTRUCT

The erase input construct will do the following:

  *  Clear all input fields on the screen to nulls.

  *  Place the cursor at the beginning of the first input field.

  *  Wait for the user to enter data.

  *  When the  user presses  an action  key, store  the new  data in  the
     appropriate variables.

Its syntax is:

        erase  input  ;

This construct may  be useful  in "form-filling"  applications where  the
user repetitively typing new data into the same form.  The  program could
display the form and receive  the first set of data  with the panel  con-
struct.  Next would come a loop which contained the processing  for a set
of input data at the top and an erase input construct at the bottom.




9.    THE COPYSCREEN CONSTRUCT

The copyscreen construct copies the screen image into a character  array.
Its syntax is:

        char buf[1921];

        copyscreen ( buf ) ;

The character  array buf  should be  at least  1921 (24*80+1)  characters
long.  It  will  receive the  24  lines of  the screen  all  concatenated
together as one character string.  All nulls on the screen are  converted
to blanks.

This construct may be useful if one wants to  get a hard copy listing  of
the screen.  The buffer would have to be reformatted into lines.

-------------------------------- Page 16 --------------------------------

10.   HOW TO DEBUG QUICKSCREEN PROGRAMS

One can use printfs  to debug  quickscreen programs but  you should  keep
these things in mind:

  *  Remember to do a setbuf(stdout,NULL); (and #include <stdio.h>).

  *  Printfs cannot be displayed at the  same time as a panel  construct.
     The tube can be in either line-by-line mode or full-screen  mode but
     not both.

  *  While the tube is in full-screen mode the output from the printfs is
     accumulated in a buffer of  length 1024 bytes.  When the next  panel
     construct erases the screen, the program is interrupted, the  printf
     output displayed, the message "More ..." placed at the bottom of the
     screen, and a wait state entered until the user presses CLEAR.  When
     CLEAR is pressed, the panel construct will be displayed and the pro-
     gram will continue.

  *  If the printf  buffer is  overflowed, the terminal  will hang.   The
     only way to restore the tube is to log on  to another terminal, do a
     "ps" to find the process id of the full-screen program, and issue  a
     "kill -9 pid" to terminate the hung program.

  *  The above can be remedied in two ways:

      1.  Redirect the standard output  to a file  and examine that  file
          when the program finishes.  This is recommended.

      2.  Place the statement "qsclose();" after every panel.  This  will
          cause the program to  be in full  screen mode only when  panels
          are displayed.  At other times it will be in line-by-line  mode
          so that the printfs will  be displayed directly.  If there  are
          less than 23 lines of  output, the message "More ..." will  not
          be shown and the next  panel construct will display its  screen
          immediately.  This  may not  give you  enough time  to see  the
          printfs.

          The above can be remedied in two ways:

           a.  Put out 23  newlines before  each panel.   This is  recom-
               mended.

           b.  Put a sleep statement before each panel.

  *  When the program is working properly, remember to remove all  printf
     and qsclose statements.

-------------------------------- Page 17 --------------------------------

11.   ADVANCED, HARD, OBSCURE, AND RARELY USED FEATURES

This section  contains some  tricky things  to be  used in  special  cir-
cumstances.  If quickscreen does something  you don't like or it  doesn't
do something you would like check here.

No attempt  has been  made to  be  rigorous or  complete.  For  an  exact
description of how these things work you should consult reference [2] and
the source for the quickscreen runtime routines.


11.1     ADVANCED PANEL COMMANDS

Understanding the advanced panel  commands requires a  knowledge of  what
happens when a panel construct is executed.

        panel {
        name: #INC,name,10#
        }

The above panel generates calls to 4 quickscreen runtime routines:

qsbfinit  This tells the terminal to erase the screen, not ring the bell,
          not lock the keys, and  to reset the "modified data tags"  (see
          {#11.5}).  It initializes the screen.

qsbuffld  This call is made for each field within the text lines.

qswrite   The above two calls  fill a buffer  with information.   Qswrite
          will write it to the terminal to be displayed.

qsread    Qsread will read the user  response and return  it to the  pro-
          gram.  It sets qskp, qsccol, qscrow, and copies any fields  the
          user changed into program variables.

The panel commands init, write, and read control whether or not the calls
qsbfinit, qswrite, and  qsread will  be made.  The  default action is  to
make the calls.  These commands are useful when a single screen image  is
being generated by more than one panel construct.  Different sections  of
the screen  could be  controlled by  different functions  and this  would
modularize and structure the program.   The first panel should have  com-
mands of nowrite and noread.  Middle panels should have noinit,  nowrite,
and noread.  The last panel should have noinit.  The noinit  is important
to prevent the screen from blinking.

        main()
        {
                at 101;
                panel(nowrite,noread) {

-------------------------------- Page 18 --------------------------------

                Greetings,
                }
                panel(noinit,nowrite,noread) {
                How are you.
                }
                panel(noinit) {
                I am fine.
                }
        }

Note that it makes no sense to have commands of noinit and bell together.
If there is no initialization there is no bell.


11.2     TRIMMING BLANKS AND DOUBLE CHARACTERS

Quickscreen will  normally remove  trailing  blanks from  modified  input
fields.  It does  this because it  is often convenient  to blank out  the
rest of a field rather than use the ERASE EOF key.  If you want your pro-
gram to see  those trailing blanks set  the integer qstrim  to 0.  It  is
initially 1.

The integer qsodbl controls whether the characters:

        {,  },  [,  ],  ^,  '

will be put out as double character sequences:

        (<, >), (|, |), \~, \<

Qsodbl is initially 0 if you did an  "stty memorex" and 1 otherwise.   It
can be changed  either before the first  panel or in  the middle of  your
program.  If qsodbl is  1 the  above characters will  be translated  into
double character sequences.

-------------------------------- Page 19 --------------------------------

11.3     WAITING AND SLEEPING

The panel command wait controls whether  or not the qsread function  will
wait for the user to press an action key.  The default action is to wait.

        while (1) {
                generate();
                panel(noread) {
                  .
                  .
                  .
                }
        }

The above program will  produce a quick  series of screens  much like  an
animated film.  The user cannot control when the film should stop.

        while (qskp != PF3) {
                generate();
                panel(nowait) {
                  .
                  .
                  .
                }
        }

This program will do the same except that  it can be stopped by  pressing
PF3.  Other PF keys could affect the way the screen is generated.

If the screens in the  animated film come too quickly,  it can be  slowed
down.  A  panel  command of  "sleep  = expr"  will  place  "sleep(expr);"
between the qswrite and the qsread.  This is better than putting your own
sleep after  the panel  because it  gives the  user time to  press a  key
before the read is done.  A panel command of  "alarm = expr" will do  the
same as "sleep = expr" except that if the user  presses an action key the
program will return right away and not sleep the full time.  The variable
"qsalarm" will be true if  the panel returned because of the alarm  going
off rather than the user pressing a key.

-------------------------------- Page 20 --------------------------------

11.4     C SOURCE WITHIN A PANEL

One can insert C source  lines within the code that  is generated by  the
panel construct by making the first character on the line a 'C'.  This is
sometimes useful but potentially dangerous.

        panel {
        Verify the information below:
        Sex: #IN,sex,1#
C       if (*sex == 'f') {
        Number of children: #IN,nchildren,3#
C       } else {
        Military Service? #IN,military,1#
C       }
        }

        panel {
C       for (i = 1; i <= nrows; ++i) {
        #@100*i+1##ON,line[i],10#       /* the embedded at IS needed */
C       }
        }

Remember to use braces { around  } fields within the panel.   Quickscreen
generates more than  one statement  for each field.   The embedded at  is
needed in the second example because quickscreen cannot always figure the
row and column positions when the embedded field is within a loop.


11.5     PA1 - PA2 PROBLEMS

PA1 and PA2 will normally cause any data  entered in input fields to  not
be stored in the associated  program variables.  Here is a trick to  par-
tially remedy this:

        panel {
          .
          .
          .
        }
        while (qskp == PA1 || qskp == PA2)
                panel(noerase,noresetmdt);

If the user presses PA1 or PA2, nothing will happen until he presses some
other action key.  The data entered in fields within the first panel will
be preserved.  The command  noresetmdt means to  not reset the  "modified
data tags".  The data fields  that were modified in the first panel  will
remain as they were until the while loop exits.  It is important to  have
the noerase  along with  the noresetmdt.   If the screen  is erased,  all
fields are lost.  See reference [2] for a better explanation of this.

-------------------------------- Page 21 --------------------------------

11.6     WHO HAS THE TUBE?

If quickscreen cannot open the tube it will terminate with the message:

        cannot open /dev/tub##

This can happen if some other process has the tube open or if the program
is running from  an ASCII paper-type  terminal.  The quickscreen  runtime
routine qsopen will return a -1 if it was unable to open the tube.  Users
could put a loop like this:

        while (qsopen() < 0)
                sleep(5);

in their program to wait until the tube became available.




12.   REFERENCES

 [1]  Introduction to  Programming the  IBM 3270,  IBM Publication  GC27-
      6999.

 [2]  IBM 3270 Information Display System Component Description, IBM Pub-
      lication GA27-2749.

 [3]  Design of  Man-Computer  Dialogues, James  Martin,  Prentice  Hall,
      Inc., Englewood Cliffs, New Jersey, 1973.

-------------------------------- Page 22 --------------------------------

APPENDIX A.    CONVERTING OLD QUICKSCREEN PROGRAMS

There are a few things  that need to be changed  in old quickscreen  pro-
grams.  The at, erase, and copyscreen constructs can remain as they were.
Each panel construct should be examined for possible changes.

  *  In the old quickscreen the  "erase" panel command  had a default  of
     "noerase".  It has been changed  to "erase".  All panels without  an
     "erase" or "noerase" should be given a command of "noerase".

  *  The panel commands "wait" and  "nowait" should be changed to  "read"
     and "noread".  There is a subtle difference between the two  that is
     explained in {#11}.

  *  The embedded field:

             #hello,4#

     was interpreted by the old quickscreen as a type ON field of  length
     4.  The new quickscreen  will see the  "hello" as an expression  for
     the type and the  4 as the  variable.  A  type of ON  should be  put
     before the "hello".

  *  Blanks within embedded fields and embedded ats are not collapsed but
     can be used for purposes  of clarity.  This change may cause  align-
     ment problems in old quickscreen programs.

  *  Rules that were implied by the old quickscreen are now enforced.

-------------------------------- Page 23 --------------------------------

APPENDIX B.    EXACT DEFINITIONS OF THE AT CONSTRUCT AND THE EMBEDDED AT

These definitions  were placed  in an  appendix because  they are  rather
obscure.  When used in a normal fashion the at construct and embedded ats
are simple and  intuitively clear.   One should  need to  refer to  these
definitions only in abnormal situations.

The meaning of the at construct,

        at  expr  ;

depends on the contents of the first text line within the next panel con-
struct.

 a.  If it begins with  constant text, the  first non-blank character  on
     the line will be placed at the specified position.

 b.  If it begins  with an  embedded field,  the first  character in  the
     field will be placed at the specified position.

 c.  If it is blank, the first blank character on the line will be placed
     at the specified position.

The rest of the panel is positioned with reference to this first  charac-
ter.

The embedded at,

        #@ expr #

begins and ends with a sharp #.  The  first character after the ending  #
will be placed at the specified position.  Succeeding lines in  the panel
are not positioned with reference to the first character after the ending
# but with reference  to the beginning  #.  It is  as if the embedded  at
were collapsed to nothing, sliding the rest of the line over.

-------------------------------- Page 24 --------------------------------

APPENDIX C.    QUICKSCREEN RUNTIME ROUTINES

This appendix contains definitions of  the quickscreen runtime  routines.
The ambitious user may desire  (or need) to call them individually.   The
source code should be consulted for details.

qsopen();
          Opens the tube  for full  screen I/O.   Returns 0  if the  tube
          could be opened, otherwise -1.

qsclose();
          Closes the tube.

qsat(rowcol);
          Sets the variables qsrow and qsslm.

qsbifc();
          Puts an IC order into qstiobf.

qsbfinit(eau, erase, bell, lock, resetmdt);
          Issues a command to the terminal and puts a Write Control Char-
          acter into qstiobf.  The parameters are booleans (0 or 1).

qsbfsba(rowcol);
          Puts an SBA order and address in qstiobf for the given row  and
          column position.

qstxtinit(plm);
          Sets the variable qsplm.

qsbfra();
          Calls qsbflinit() to put  an SBA order  and address in  qstiobf
          for the beginning of  a new line and  then puts an RA order  in
          qstiobf to null out that line on the screen.

qsbflinit(skips, begcol);
          Sets qsrow and puts an SBA order and address in qstiobf for the
          beginning of a new line.

qsbuffld(attr, fc, fl);
          Puts a field in qstiobf.  The field consists of an SF order and
          an attribute character if necessary, an IC order if the  cursor
          is to be placed in  this field, and the  data to be  displayed.
          If the field is an  input field, then an entry is added to  the
          input fields table qsift which correlates the screen offset  of
          the field with the address of its associated program variable.

-------------------------------- Page 25 --------------------------------

copyscreen(buf);
          Issues a read buffer command  and gets a  copy of the  terminal
          buffer into  qstiobf.   It  then  copies  the  characters  from
          qstiobf into  the specified  program variable  deleting all  SF
          orders and replacing all attribute characters and null  charac-
          ters with blanks.

qswrite();
          Sends qstiobf to the terminal.

qsread(waitforaid);
          Gets data from the terminal  into qstiobf.  Sets qskp,  qscrow,
          qsccol, and  update all  program variables for  which the  user
          entered new data.   If the  parameter is false,  the read  will
          return immediately rather than  wait until the user presses  an
          action key.

qsmod(s);
          Returns true if the  field corresponding to  the parameter  was
          modified on the screen otherwise false.

qspos(s);
          Returns the row and column position of the field  corresponding
          to the parameter.
