Created by Daniel Hellerstein (last modified Jan 2006)

                Useful GRBL2 Procedures. 

                -------------------

Contents:

1. Introduction
2. Loading the GRBL2 Batch Procedures
3. The GRBL2 Batch procedures
4. Using a G_BATCH2 procedure to specify additional keywords

                -------------------

1. Introduction 

GRBL2 includes a number of useful procedures. This includes I/O procedures, matrix
manipulation procedures, and variable selection/creation procedures.


2. Loading the GRBL2 Procedures

To use the GRBL2 batch procedures, include at the top of your main program file 
(that implements your model):
        #include grbl2_PROCS.inc ;
        #include grbl2_file.inc ;

       
This assumes that these .INc files are either in the current directory, or in GAUSS's path.

Hint: you can run the GRBL2_INI.PRG program when you first start up GAUSS. This will
      change the GAUSS path to include directories you specify.

Note: the G_BATCH "GRBL2 BATCH procedure" is described in GRBL2_BATCH.TXT.


                -------------------


3. The GRBL2 procedures:

The following lists the procedures supported by GRBL2:

  G_ADDROWS : Add rows to a matrix (an extension of the X|Y syntax)
  G_ADDROWS2 : Similar to G_ADDROWS, plus track #of columns
  G_ADD_SUFFIX:  add a suffix to variables names in a vector

  G_ABBREV   : Is arg1 an abbrevation of arg2

  G_ADDCOMMA : Add commas to a number

  G_ASKVAL: Ask for a numeric value (recognize function keys)
  G_ASKFIL: Ask for the name of a file, with directory browsing capabilities
  G_ASKOPT: Ask for  an option from a list (using keyboard or cursor keys)
  G_ASKV1:  Ask for a variable from a list, return name and position
  G_ASKVS:  Ask for one or many vars from a reference list, with defaults.
  G_ASKVS2: Ask for one or many vars from a reference list, with defaults and help messages.
  G_ASK_FOR_VARS: Ask for one or many vars from a reference list, with defaults and help messages.

  G_AS_DIR: return valid directory name,  and check if this is a legit directory.

  G_BATCH: Process a GRBL2 batch file
  G_CONS1: Read a string, with ESC and function key support
  G_CONS2: Read a string, with ESC and function key support
  G_CONS3: Read a string, a character at a time

  G_DIRLST : list of files, and subdirectories, in a directory
  G_DOSLCT: Create an index of "retained" observations

  GET_COPT: get the value of an option, from a list of options
  GET_COPT_MATCH: get the value of an option, from a list of options; and match value to a list

  G_EDITDATA: edit, or view, a gauss data file.
  G_EXISTS: checks if a file, or directory, exists
  G_EXISTS2: checks if a file, or directory, exists -- first check altdir, then check current path

  GRBL2_ERROR: Record error to screen, output file, and to GRBL2 Error file

  G_FSPEC: Extract information about a file
  G_FSPEC2: Extract drive, path, and name information about a file; with alternative path support
  G_FTOS2 : Convert number to a string.

  G_GOSUB0: Replaces, in a text string, GOSUB labels with corresponding blocks
  G_GETWRD: Parse word from a string (similar to the gauss TOKEN command)

  G_IS_DIR: check if this is a legit directory.
  G_ISNUM: Check if string is a number
  G_INDCV2: INDCV, with substring capability

  G_MKINDX: Construct an index from a 0/1 vector
  G_OKINDX: Construct an index to non-missing observations, with iterative calls

  G_MXKVC: Create XVC, a concatenated set of variance covariance matrices, by reading a XVC fle

  G_1OPT: get 1 variable (or a number) from batch command -- return index,name,ie

  G_NOPTs: get list of variables from batch command -- return index,name,nvars,ie

  G_PAUSE: Pause for a timespan, or until key is hit
  G_PAUSE2: Pause for timespan, return value of key hit
  G_PADWORD: Pad a word with spaces, to desired length
  G_PNLIND: Construct an index identifying panels of data (ID version)
  G_PNLIND_COUNT: Construct an index identifying panels of data (COUNT version)

  G_PARSEMIME: Parse a "mime like", return fieldnames and values in string vectors

  G_REPLACESTRING : Replace substrings in a string
  G_REPSTG: Do substring replacements, use QUERY and DEFINE definitions
  G_SCREEN: Set screen display attributes (in the dos compatability box)
   Related to G_SCREEN:
        boldon,blueon,cyanon,yellowon,
        grey_bkg,cyan_bkg,blue_bkg,gold_bkg,
        blockon,normalon


  G_STRIP: Strip spaces from a string, or from all elements in a string matrix
  G_STRIPC: Strip any character from  a string
  G_SUBST : Alternate version of SUBSTUTE procedure

  G_SHOWVEC : Write a vector of character strings in a pretty format.

  G_USRSET: ask for values for coefficients, displaying Variable names and  old values (if available).

  G_VUSLCT: View the current list of observation selection criteria.
  G_VUDUM: View the current list of make dummy variables specifications
  G_VUXNEW: View the current list of XNEW new variable equations
  G_VUFILE:  View a text file
  G_VUTEXT:  View a text string

  G_WORD : Pull nth word from astring, or return #words in a string

  G_YESNO:  Prompt for a yes/no answer
  G_YES_NO:  Prompt for a yes/no answer (with special key detection)
  G_ZAPCMT: Remove comments from a string.


The following describes these  procedures in greater detail.

G_ADDROWS: Append a new matrix to the bottom of an old matrix -- adjusting columns if necessary

  Append, to bottom, the newmtx to the oldmtx. Returns the combined result

        matrix2=g_addrows(0,mymtx1);
        matrix2=g_addrows(matrix2,mymtx2);
               ...
        matrix2=g_addrows(matrix,mymtxn);

   If oldmtx = . or equals 0, returns newmtx
   If cols(oldmtx) <> cols(newmtx), then concatenate columns containing
   missing values to the matrix with fewer columns.

  Caution: when appending an Kx1 vector to an NxK oldmatrix, be sure to transpose the vector.
      I.e.;  allobs=g_addrows(allobs,thisobs');

G_ADDROWS2: Same as G_ADDROWS, also returns vector containing # of columns for each row or returned matrix


  Same as g_addrow, but also returns a vector indicating number of legit
  columns in each row of oldmtx. This requires an additional argument: oldcols
  Oldcols will also be appended to, adding the number of columns in newmtx.

  example:  {matrix2,cols2}=g_addrows2(0,mymtx1,0);
            {matrix2,cols2}=g_addrows2(matrix2,mymtx2,cols2);
                ...
            {matrix2,cols2}=g_addrows2(matrix,mymtxn,cols2);

  Caution: when appending an Kx1 vector to an NxK oldmatrix, be sure to transpose the vector.
      I.e.;  {allobs,allcols}=g_addrows(allobs,thisobs',allcols);


 
G_ADD_SUFFIX:  add a suffix to variables names in a vector 
  Syntax:
        newlist=g_add_suffix(varlist,addit)
  where:
   varlist: list of variables to add a suffix to
   addit: A code indicating what to add
                A value : add _, then the value (i.e.;  1)
              . or ""   : Add _, then a sequential number (. means missing)

        Option: if addit is a two row vector, and addit[2]=1,
                then instead of adding number, add characters (A,B,..)
                
           
  Examples:
     varlist=g_add_suffix("JOE"|"DAN"|"ALAN",""))
        would yield: JOE_1 DAN_2 ALAN_3
     varlist=g_add_suffix("JOE"|"DAN"|"ALAN",2)
        would yield: JOE_2 DAN_2 ALAN_2
     varlist=g_add_suffix("JOE"|"DAN"|"ALAN",""|1)
        would yield: JOE_A DAN_B ALAN_C


  User changeable globals used by G_ADD_SUFFIX:
  * g_add_suffix_char
    g_add_suffix_char variable can be used to change the
        seperator character from "_" to something else.
        Examples:
            g_add_suffix_char=""  -- NO seperator (JOE2 instead of JOE_2)
            g_add_suffic_char=":"  -- would yield JOE:2)
  * G_ADD_SUFFIX_PADLEN
     G_ADD_SUFFIX_MAXLEN tells how long the resulting elements in
     newlist can be.  By default, the max is 8 characters long.
     You can change this to any size.
     Note: if varlist is an array (not a string array), then maxlen can
            not be greater then 8 (g_add_suffix will impose this).     

  Hint:
     You can produce a Nx1 character vector containing numbers ("1"|"2"|...) by using:
   alist=g_add_stuff(zeros(N,1),"");
   
     or, containing letters using  (not recommended for N>26)
   alist=g_add_stuff(zeros(N,1),""|1);


G_ABBREV : Check if arg1 is an abbrevation of arg2

   isit=g_abbrev(arg1,arg2);
   where:
      arg1 is a string, or a string vector
      arg2 is a string
      isit is either 0 or 1
          If ARG1 is an abbrevation of arg2, isit=1
          Otherwise, isit=0

   Arg1 can be a string vector -- if ANY of the elements is an abbrevation, 1 is returned
   (0 is returned if NONE of the elements are)

   Note that the matching is case insenstive, and spaces are stripped from ARG1 and ARG2.
   

G_ADDCOMMA: Add commas to a number

   astring=g_addcomma(aval,ndec)

    aval: a numeric value
    ndec: number of places to right of decimal point

    A string containing a version of the value of aval is returned.
    Commas are inserted where appropriate.
    If ndec=0, an integer is returned (rounded down).

    Examples:
      g_addcomma(12562,0)  == 12,562
      g_addcomma(12562,2)  == 12,562.00
      g_addcomma(12561.52,1)  == 12,561.5
    

G_ASKVAL: Ask for a numeric value (recognize function keys)

   {avalue,status}=g_askval(prompt,default_value)

   prompt : a 1 line prompt
   default_value : A value returned if Enter is hit 
         Or a 2 element vector:  default_Value|precision
         where precision is the number of right-of-decimal-point characters to use
                              when displaying the default value
   avalue: The value that is returned
   status: status of value. If a number is entered, status will be 0

   The client can enter a number (that can contain commas, the commas are removed),
   a function key, or several special entries.

  Typically, avalue is a number, and status is 0. However, function keys and special
   values yield non-zero values for status.

  The special entries  yield special values of avalue and status. These are (without the quotes):
    Enter  :       avalue=default   status=0
    "M" or "."  :   avalue=Miss(1,1)    status=27
    "PI"   :        avalue=3.14...      status=32
    "E"    :        avalue=exp(1)       status=32
    "?"    :        avalue=default      status=1059
    ESC    :       avalue=default      status=miss(1,1)
    FunctionKey :   avalue=default  status=ascii of function key

  Some "ascii of function key values":
     F1 = 1059, F2=1060, F3=1061,...,F9=1067
     HOME=1071,  PGUP=1073, END=1079, PGDN=1081



G_ASKFIL: Ask for the name of a file, with directory browsing capabilities
G_ASKFIL2: Ask for the name of a file, with directory browsing capabilities, and filtering

  {filename,dirname,usename}=g_askfil(oldfile,olddir,tempdir,g_only,sortby,header)
     or
  {filename,dirname,usename}=g_askfil2(oldfile,olddir,tempdir,g_only,sortby,header,filter)

  Note: g_askfil is simply a shortcut for calling g_askfil2 using filter=""

    filename : name of file returned.
    dirname : directory of filename (filename will include directory info)
    usename : gauss file corresponding to filename (if g_only<>0)

    oldfile : default filename (if it exists in default directory, or if ESC hit)
    olddir  : directory to start in (relative oldfile is relative to this directory)  
    tempdir : tempdir (where generated gauss datasets    will be stored)
    g_only : 0=all files, 1 = gauss data files only,  2= all files, but convert to gauss datafile
        3= choose between 1 and 2
    sortby : "" -- default (by name)
        "SIZE" -- byte size
        "DATE" -- last modification date
             "NAME"    -- no sort (same as default)
        "-SIZE" -- byte size (large to small)
        "-DATE" -- reverse date (latest to oldest)
        "-NAME"  -- reverse (Z to A)
   
    header : header message. If "", use default message 
    filter: if 0, or "", display all files. Otherwise, only display files that match the filter.
       For example, "*.IN" means "only display files that have a .IN extension"

  Notes: 

  *  The user can change the sort order on-the-fly

  *  G_only=0 should be used if you want to select a non-data file

  *  If g_only>0, usename will point to a temporary file that contains a gauss dataset that
     is the same as the chosen gauss dataset, or is built from a chosen text file
     (the chosen text file's name is returned in filename).  That is, it will NOT have
     an extension (GAUSS will assume a .DAT extension).

  *  If G_only=0, usename and filename are the same

  *  Thus, if g_only =1 or 2 or 3, usename is the file that should be "opened" as a gauss dataset.

  *  Source code for G_ASKFIL and G_ASKFIL2 is located in the GRBL2FIL.INC "include" file.


G_ASKOPT : Select an option from a list (using keyboard or cursor keys)

   my_opt=g_askopt(prompt,list,def,helps,c_prompt,c_help)

where:
  Prompt-- A string used as a prompt
   List -- A  L x 1 vector of names: this is the list to choose from (8 character max per name)
   def  -- The default choice (one of the values in LIST, or the numeric index of the default 
   helps -- if scalar 0, it is ignored.
            or, a  L x 1 string vector of 1 sentence help messages for each choice in the LIST vector.
  c_prompt -- Scalar: how to display prompt:   0=normal, 1=bold, 2=block, 3=bold yellow, 4=cyan, 5=white on cyan, else=normal
  c_help -- Scalar, how to display help (use same values as c_prompt)
 
   my_opt will be one of the values in LIST. Or, miss(1,1) if ESC was hit



G_ASKOPT2 : Select an option from a list (using keyboard or cursor keys) -- indicates how option selected

   {my_opt,keyuse}=g_askopt(prompt,list,def,helps,c_prompt,c_help)
 
   Same as G_ASKOPT< but the keyuse argument indicates how the option was chosen.
   In particular, 
     27 = esc hit (my_opt will equal miss(1,1) )
     1  = crlf hit
     1059  = F1 hit


where:
  Prompt-- A string used as a prompt
   List -- A  L x 1 vector of names: this is the list to choose from (8 character max per name)
   def  -- The default choice (one of the values in LIST, or the numeric index of the default 
   helps -- if scalar 0, it is ignored.
            or, a  L x 1 string vector of 1 sentence help messages for each choice in the LIST vector.
  c_prompt -- Scalar: how to display prompt:   0=normal, 1=bold, 2=block, 3=bold yellow, 4=cyan, 5=white on cyan, else=normal
  c_help -- Scalar, how to display help (use same values as c_prompt)
 
   my_opt will be one of the values in LIST. Or, miss(1,1) if ESC was hit



G_ASKV1:  Select a variable from a list, return name and position
           Or Return missing if no match -- (ESC).
      Or, return a numeric value

    NOTE: This can also be called as G_GETVAR

   {indx,vname}=g_askv1(prompt,default,varlist,helpmess,force,numbok)

Where:
    Prompt --- 1 line prompt
    Default -- Default value
    Varist -- Valid list of variables
    Helpmess  -- 1 line help line, shown if ? or cursor key hit
    Force  -- If 1, disable ESC (force acceptance)
    numbok  -- If 1, numeric values can be input

  indx and vname are:
   if chosen from varlist: Pointer,Varname  ( into Varlist)
   if number selected: 0, entered_Value
   if ESC: miss(1,1) ," "

   Note: to clear typed input, hit ESC. Hitting ESC with nothing on line (say, just after hitting
         ESC to clear typed input), will return miss(1,1),"".
   


G_ASKVS: select one or many vars from a reference list, with defaults.

    NOTE: This can also be called as G_GTVARS

    newlist=g_askvs(current,reflist);

  where:

     current: Mx1 vector of already selected values
     reflist: Nx1 (N usually > M) vector of possible choices
 
     newlist : choices from reflist
 
   G_ASKVS supports keyboard input by name, as wel as arrow keys.

   G_ASKVS Will do  substring matches !! (after checking for exact matches) 
   Also, if you enter XXX.FMT (XXX-a valid filename), then will
   attempt to load a list of names contained in gauss matrix file   XXX.FMT !

   G_ASKVS is a simplification of G_ASK_FOR_VARS.

G_ASKVS2: select one or many vars from a reference list, with defaults.

    {vindex,vnames}=g_askvs2(current,reflist,prompt,helpmess);

   Similar to G_ASKVS, but will display prompt at the top of the screen, and will display
   helpmess if F1 is hit.
 
   Vnames: vector of names, from reflist, that were chosen
   vindex: index of vnames, into reflist
   prompt: 1 line prompt displayed at top of screen
   helpmess: 1 line help message display if help requested

   G_ASKVS2 is a simplification of G_ASK_FOR_VARS.

G_ASK_FOR_VARS: select one or many vars from a reference list, with defaults.

 {vlist,vindex}=ask_for_vars(prompt,varlist,oldlist,helpmessage,force)
  
   prompt: prompt to display at screen top
   varlist: list of variables to chose from
   oldlist: list of variables that are already selected
   helpmessage: extra message to display
   force:  if 1, disable ESC (force acceptance)
  
   vlist : list of selected variables
   vindex :index of vlist into varlist 


G_AS_DIR: return valid directory name,  and check if this is a legit directory.
   dirname=g_is_dir(adir,check)
  
 Simiilar to G_IS_DIR. If CHECK Ne 1, just return the name (don't check to see if
 if exists)

  Note: see G_ISDIR for a simpler version of this.
   

G_BATCH: Process a GRBL2 batch file
   {new_string,status}=G_BATCH(text_string,reset,use_custom_proc)
   The batch processor. Described above.



G_CONS1: Read a string, a character at a time

    An interactive cons -- returns values as it's being built.
    Recognizes a number of special keys

    {ans,iat,ak}=g_cons1(ans0,at0,redo)

   where:
   ans0 : current value of answer
   at0  : character position where character input begins (the column on the screen). 0 means "use current column"
   redo : display and return option
       ans   : new value of ans
       iat   : next position in ans to modify. If 0, end-of-string character hit,
          typically Enter key, but possibly Esc, or cursor key.
   ak   : ascii value of last key hit
   
   If cursor key hit, return ascii value of cursor key, and iat=0.
   
   AK is useful when a "end of entry" key is hit. These include:
                 10 and 13 : ENTER key
       27      : ESC key

       Redo values are:
    0  : At start, do not write current value of ANS0. If ESC hit, ans=miss(1,1) and IAT=0
    1  : At start, write current value of ANS0.  If ESC hit,ans=miss(1,1) and IAT=0, and <ESC> is displayed
    2  : At start, write current value of ANS0. If ESC hit, return current value if ans, IAT=0, and AK=27
              Careful -- writing takes place at current column!

      Example:
      {ans,iat,ak}=cons3("",0,0);
      do until iat==0;
             {ans,iat,ak}=cons3(ans,iat,2);
               .. check for special values of ans ..
          .. if iat=0, check AK for esc (27) --
         if so, 
             if ans<>"", set ans="', iat=0, and continue (ie. erase current stuff)
             if ans="", break (use ANS="")
         if not, break (and use the value of ANS)
      endo;

     Note: This routine does not work quite right under gauss 5.0 (i.e.; backspace is ignored).
         



G_CONS2: Read a string

    astring=g_cons2();

    Like cons, but returns a number if one of the arrow keys, etc. is hit.
    For example:
        astring=g_cons2()
    and you hit F1
        astring will be  1059

   Due to peculiarities of GAUSS 5, backspace doesn't work.
   Instead, use ESC to clear what you have typed.
   If you hit ESC with nothing entered (or just after hitting ESC to clear typed input), 
   a miss(1,1) returned.



G_CONS3: Read a string, a character at a time

    Same as G_CONS1, but don't bother with AK.

    {ans,iat}=cons3(ans0,at0)

   where:
   ans0 : current value of answer
   at0  : character position where character input begins
       ans   : new value of ans
       iat   : next position in ans to modify. If 0, end-of-string character hit,
          typically Enter key, but possibly Esc, or cursor key.
   
   If cursor key hit, return ascii value of cursor key, and iat=0.


      {ans,iat}=cons3("",0);
      do until iat==0;
          {ans,iat}=cons3(ans,iat);
             .. check for special values of ans ..
      endo;

     Note: This routine does not work quite right under gauss 5.0 (i.e.; backspace is ignored).
         
      
G_DIRLST  : list of files, and subdirectories, in a directory
and G_DIRLST2

     {filelist,filebytes,filedate,dirlist}=g_dirlst2(adir,filter)
    or
     {filelist,filebytes,filedate,dirlist}=g_dirlst(adir)

  Filter is a pattern -- only files matching this pattern are displayed. 
  For example, filter="*.IN" means "only include files that have a .IN extension".
  If filter ="", 0, or *.*, then return all files.
 
  Basically, g_dirlst is a shortcut to g_dirlst2 (using FILTER="*.*")

  IF adir="", look at current path.
  If adir does not exist, return miss(1,1),0,0,miss(1,1)

   Filelist will be a string array of filenames (not including the path)
   Filebytes is the size of these files (in bytes)
   Filedate is the last modification date of these files (as the number of seconds since 1 Jan 1970)
   dirlist will be a string array of subdirectories (not including the path)

   If no files, filelist will be "" and filebytes=filedate=0
   If no subdirectories, dirlist will be ""

  Both filelist and dirlist will NOT include path information
 
  If adir is not an existing directory, returns Miss(1,1),Miss(1,1)

  The . and .. files (subdirectories?) are NOT returned in either list.

  Thus, a totally empty directory will return filelist="" and dirlist=""

                  

G_DOSLCT: Create an index of "retained" observations

    slctids=G_DOSLCT(CLIST,DATASET)

    Clist: the matrix  generated by G_BATCH when  a SELECT ... keyphrase is processed 
      In particular, you can use the SLCTLIST global variable.
    Dataset: name of dataset

    slctids: a vector of observation row numbers, pointing to the observations in DATASET
        These are the observations to keep.
             If clist is empty, then slctids=0 (keep all observations). 

    If problem opening DATASET, slctids will be missing.



G_EDITDATA: edit, or view, a gauss data file.


  foo=g_editdata(afile,nowrite);

  afile: name of a gauss datafile
  nowrite: if 1, then do NOT save changes (just view current values)

  
  This will edit, or just view, the values of the variables in a gauss data file.
  All the values for an observation will be displayed on a DOS window.



G_EXISTS: checks if a file, or directory, exists

    newname=g_exists(afile_or_adiretory,altdir);

  Returns fully qualified filename for this afile, if afile exits.
     or
  Returns fully qualified directory (ending with \), if it exists.

  or, returns "" if the file (or directory) does not exist.

  Note: to look for a directory, the afile_or_adirectory MUST end with a \.
        Otherwise, it is assumed that filename is being looked for

  If altdir ne "", and aname not fully qualified, aname is relative to altdir.

  Altdir MUST be a properly specified path name (it must start with "x:\", where
  x is a drive letter).

  Otherwise (if altdir="" or is not properly specified) a non-fully qualified filename
  (or directory name)  will be relative to the current path.

  Note: G_EXISTS uses G_FSPEC2


G_EXISTS2: checks if a file, or directory, exists -- several altdirs

  Syntax:
      newname=g_exists(afile_or_adirectory,altdir,altdir2);

  Returns fully qualified filename for this afile, if afile exits.
     or
  Returns fully qualified directory (ending with \), if it exists.

  Or, returns "" if the file (or directory) does not exist.

  Note: to look for a directory, the afile_or_adirectory MUST end with a \.
        Otherwise, it is assumed that filename is being looked for

  For relative filenames,  G_EXISTS2 will look in 3 locations:
        i) In the altdir directory
       ii) If not found, in the altdir2 directory
       iii) If still not found, in GAUSS's current working directory

  Altdir and altdir2 MUST be a properly specified path name (it must start with "x:\", where
  x is a drive letter). Or, they can be "" (the current working directory).

  Note: G_EXISTS2 uses G_EXIST


GRBL2_ERROR

   Write an error message to the GRBL2.ERR file (if called by a GRBL2 program).
   
   If called by a grbl2 program (if the GRBL2_PROGRAM global variable has been defined),
   then error information is written to GRBL2_ERRFILE, and a GRBL2_ERRFLAG is augmented.
   If GRBL2_ERRFILE is defined, use it as the GRBL2.ERR file.
   Otherwise, write to gauss50dir\GRBL2.ERR (gauss50dir is the result of sysstate(2)) 
   In any case... output to screen and/or to current output file

   Arguments:
     message: message to display (and save to grbl2.err)
     doout: where to display.
            0= screen only
            1= screen and output file (output on)
           i|j = (2x1 vector): i = 0/1 to screen,  j=0/1 to output file (0=no, 1=yes)

  Returns # of lines written to GRBL2.ERR
  Also, if called by GRBL2 program, adds 1 (or sets to 1) the GRBL2_ERRFLAG variable

  You can also set three variables: 
    GRBL2_PROGRAM (the name of the grbl2 program)
         a=grbl2_error("MY_PROGRAM","PROGRAM");
         a=grbl2_error(0,"PROGRAM");    -- (this will suppress recording of data to grbl2_errfile)
         
    GRBL2_ERRFILE:
         a=grbl2_error("F:\TEMP\ERRORS.TXT","ERRFILE") ;
         a=grbl2_error(0,"ERRFILE");    -- (use GRBL2.ERR in GAUSS directory)

    GRBL2_ERRFLAG:
         a=grbl2_error(0,"ERRORS") ;    -- reset flag to 0
       

GET_COPT:  extract an option from a line of text. Typically, the line of text is a command from
            the command file.

  This procedure looks, in aline, for sub strings of the form:
      ANOPT=Opt_value 

  You can have spaces on either side of the = sign.
  If you want to have spaces in "opt_value", you MUST include Opt_value between " characters

  Or, it can look for "flags" of the form:
      -anopt
  or of the form
    " xxx"  (without the quotes)
 
 Syntax:  
   thevalue=get_copt(aline,anopt,errmess)
  where;
     aline : a line of text
     anopt : an option to look for. or, a vector of "synonyms" 
   errmess : if not "",, and if anopt not found, then write errmess and stop the program

   thevalue: value of the option (in some cases, a 2 row vector is returned) 

 Notes:

   * In aline, an ANOPT must be preceded by a space (or be at the beginning of the aline)

   * Options that begin with a dash (-) are treated specially. If there are no ANOPT=xxx
     matches, then -anopts are searched for. GET_COPT will return the first such option found.

   * Options that begin with spaces (i.e. " LOG" ) are treated special. 
     GET_COPT will return the first such option found (the leading space is ignored).
    
     Note that -options are searched for BEFORE " xxx" options.

   *  if a "wildcard match", 
          -- return a two row string vector -- 
                first row is value of option,
                second row is value of "suffix" (what the * wildcard matches)
   *  if "" is one of the anopts, then
           -- if no match is found (for any of the other items in the anopt list),
         return the SECOND word (or a quoted string after the first word) in aline.
   *  if anopt equals ""
           --  return the SECOND word (or the  quoted string after the first word) in aline.
   *  if anopt not found (and "" is not one of the anopts)
           --  return a "".
       or, if errmess <> "", 
          --  print errmess and exit.
   

  Example of an aline:
    TYPE=XB  file=D:\DATA\FOO  HEADER = "This is my model" 

  Examples of anopt:
      anopt="TYPE"
      anopt="TYPE"|"TYPES"|"ATYPE"
      anopt="VAL"|"VAL_*";
      anopt="VAR"|"";
      anopt="VAR"|"-PRICE";
      anopt="DOLOG"|" LOG";
                anopt="COMMANDER"$|"TOP_GENERAL" ;


 Notes:

    * anopt vectors that contain "" is meant to support syntaxes of the form:

       myresp=get_copt(aline,"VAR"|"","");

       where aline could be:
           RESPONSE VAR=FOO ;
       or
           RESPONSE FOO ;  
 
  *  anopt vectors that contain -options are meant to support syntaxes of the form:
           MODEL LOGIT -BHHH ;
       or
     MODEL LOGIT  METHOD=BHHH ;
  
      Both of these cases would be covered with the following:
       amethod=get_copt(cmdline,"METHOD","-BHHH","");
      so that you could use...
            if amethod$=="BHHH" or amethod$=="-BHHH" ;  .... 
       
      Note that the -option match, if one occurs, will return the -option INCLUDING the 
      leading dash.

  * anopt vectors that contain " options" are meant to support syntaxes of the form:
        LOGY  YES ;
     or
   LOGY 1 ;

     So that one can use:
   If get_copt(aline," YES"|" 1","") $/="" ; dolog=1; else ; dolog=0 ; endif;

     Note that if match to a " xx" (without the quotes) occurs, the xx is returned
     (leading spaces are stripped).
     

GET_COPT_MATCH:  extract an option from a line of text, and match option to a list.
     This is GET_COPT with an extra step -- match the found value to a list of values,
     and return the row number containing the list.

 Syntax:
         {thevalue,theind}=get_copt_match(aline,anopt,errmess,vlist)
 where
        aline, anopt, and errmess : as described in GET_COPT
        vlist : a vector of values.
        thevalue : as described in GET_COPT (might be a two element vector)
        theind:  matching row in vlist (or missing if no match)

  GET_COPT_MATCH first uses GET_COPT to find a match.
  If no match can be found, a missing is returned.
  Otherwise, the matching row (in vlist) is returned.

  Example:
      {mvar,mind}=get_copt_match("RESPONSE VAR=Z ","VAR","","Y1"|"X"|"Y2"|Z")
   would return
      mvar=Z
      mind=4


G_FSPEC: Extract drive, path, and name information about a file

   info=g_fspec(todo,filename)

  Where todo can be
     D : drive letter (without trailing :)
     P : path (start and end with \)
     N : name
     F : name, without extension
     A:  fully qualified file name
     DP : Drive letter followed by : followed by path (ends with a \ )

  Note that you can use A to avoid bugs in Gauss's GETPATH.

  If filename is not fully qualified, it will be relative to the current path

  If todo is not D,P,N,F,A, or DP, a miss(1,1) is returned.


G_FSPEC2: Extract drive, path, and name information about a file; with alternative path support


   info=g_fspec2(todo,filename,altpath)

   Same as g_fspec, but you can provide an alternative "path", which will be used
   (instead of the current path) for non fully-qualified filenames.

   if altpath="", or if altpath is not properly specified (it must begin with a "x:\ ", where
   x is a drive letter), the current path is used.

   Note: g_FSPEC calls G_FSPEC2 with altpath="".

   Special feature:  g_fspec2('DP',"..",altpath) will give the parent directory to the
           path (or file) in altpath.



G_FTOS2 : Convert number to a string.

   Make a number into a string. G_FTOS2 will determine an appropriate format.
   If isint0=1, make into an integer
    Or, if isint0 is two rows:
       row 1 = 0/1 "integer" dummy
       row 2 = length of string (spaces added)

   Examples:
    a=g_ftos2(16.36,1);  ==> "16"
    a=g_ftos2(16.36,0);  ==> "16.36"
    a=g_ftos2(16.36,0|7);  ==> "  16.36"



G_GOSUB0: Replaces GOSUB labels with corresponding blocks

    newstring=g_gosub0(oldstring)

   G_GOSUB0 should be called BEFORE calling G_BATCH. You need only call it
   once. That is, if you are looping through a string, with many RUN commands
   in it (and you recall G_BATCH after each RUN), you do NOT need to recall
   G_GOSUB0.

   G_GOSUB0 will first remove STARTBLOCK ... ENDBLOCK "labeled blocks" from 
   oldstring.
   The remaining portion of oldstring is examined for GOSUB commands.
   These are GOSUB commands are replaced by the appropriate "labeled blocks".
   
   The end result is returned in newstring.

    The syntax of these blocks and calls, in the string, is:
     a) to call a block:
          GOSUB block_name  arg1 , arg2 ....

    b) to define a block
         i) start with STARTBLOCK block_name;
        ii) grbl type statments (ending with ;).
            These may include %1, %2, etc -- which are substituted with
            arg1, arg2, etc. from the CALL
       iii) end with ENDBLOCK ;

    c) blocks are textual substituions -- hence can be thought of as
       subroutine calls (and NOT procedure calls) -- all variables within
       a block are global

 
    Return 0 if astring  is not a number, 1 if it is.


G_GETWRD: Parse word from a string
  
      {KEYWURD,iat_now}=g_getwrd(astring,iat) ;

      Get next word starting from string, starting at character IAT.
      By default, commas, spaces, and ascii vals <= 32 delimit a word.

      IAT_NOW is the where to start looking for the next word.
      If IAT_NOW=0, then no more words left.
    
      KEYWURD is the word drawn from astring, with leading spaces, etc. stripped.

      You can augment the list of "word delimters" by modifying the 
       _G_GETWRD global -- it should contain a string of delimiter charactrs.

     Example:
        z="This is a test, are you ready for more? ";
        iat_nu=1; iat=1;
        do until iat_nu==0;
           {aword,iat_nu}=g_getwrd(z,iat);
           ia  aword ;
           if iat_nu ne 0 ; iat=iat_nu+1; endif;
        endo;

     Would yield:
         1  This
         5  is
         8  a
         11 test
         16 are
         21 you
         25 ready
         31 for
         35 more?
         41



G_IS_DIR: check if this is a legit directory.

   dirname=g_is_dir(adir)

  Returns a valid directory name (with trailing \) if adir is an existing directory.
  If not, returns ""

  If a filename detected at the end of adir, it is dropped (filenames are assumed to contain a period).

  If adir="", return current path.

  Note: see G_ASDIR for an alternative to G_ISDIR


G_ISNUM: Check if string is a number (0 if no, 1 if yes).


    isnum=g_isnum(astring)

    astring should be a 1x1 character scalar, or a 1x1 string.

    GAUSS's ISNUMBER function does not work with scientific notation. G_ISNUM does.
    
    G_ISNUMBER is a synonym for G_ISNUM (they call the exact same function).


G_INDCV2: INDCV, with substring capability

    aindx=g_indcv2(avar,varlist)
        
    First, see if AVAR in VARLIST. If so, return index to varlist.
    If not, see if AVAR is a substring of one of the VARLIST values. If so, return
    index to varlist.
    If not, return miss(1,1);

    Example:
        let dogs=ABC YZGHI DEF GHI JKLMNOP ;
        FOO1=G_INDCV2("GHI",DOGS);
        FOO2=G_INDCV2("ZGHI",DOGS);
    FOO1 will be 4, FOO2 will be 2


G_MKINDX: Construct an index from a 0/1 vector
       
     Construct an index, given a vector of 0s and 1s.
     Retp(missing) if all zeros

     Example:
        let z=0 0 0 1 0 1 0 0 1;
        aindx=g_mkindx(z);
     aindx will be a 3x1 vector: 4 6 9


G_OKINDX: Construct an index to non-missing observations, with iterative calls

    newindx=g_okindx(dat,nowindx,prots,no_nans)

 where:
    dat: the N x K dat that might contain missing values
    nowindx: The M x 1 (M<=N) "cumulative index" of non-missing value observations
             or, a scalar 0 (to  start with this dat)
             or a N x 1  0/1 "dummies" vector, where 0 means "don't include this row"
     prots:  An N x 1 0/1 vector "protected" observations (if prots[n]=1, then
             this observation is always retained, regardess of dat[n,.]
        Or, scalar 0 to "not protect" any rows
     no_nans : if 1, nans, infs, etc are treated as missings
  and
     newindx: new index of non-missing obervations


  g_okindx is used to modify a current index (nowindx) by removing pointers to rows 
  of dat that contain missing values -- provided that a row with missing values is
  not "protected" (prots).

  The notion is to extract several different "dat" matrices from a reference dataset,
  and then call g_okindx for each of these "dat" matrices (using the prior value  of
  newindx as the nowindx argument)
 
  The net result is a array that points to non-missing observations -- observations for 
  which none of the (corresponding rows) of the dat matrices have missing values 
  (with the exception of "protected" observations).

  Thus: Newindex points to rows in DAT that contain non missing values AND that are listed in
        nowindx.

  Notes:

  * when calling g_okindx sequentially, each dat MUST be N x ki, where N is always the same,  
    but ki can vary.


  * Given that N is rows(dat) then NowIndx must be either
      a scalar 0, or
      a N x 1 vector of 0/1 dummies, or
      a M x 1  (M<=N) vector containing integer values between 1 and  N
  
  * Prots must be 
       a scalar 0, or 
       a N x 1  vector of 0/1 dummies

  * "prots" is used when a control variable will be used to
    recode missing values, but only for selected observations.
    For these selected observations, you do NOT want to remove missing
    values -- prots is used to indicate this "protection from removal"



G_MXKVC: Create  XVC -- a concatenated set of variance covariance matrices

  Create  XVC -- a concatenated set of variance covariance matrices

  The notion is:
    i )  Given a Kx1  vector of X variables for N observations (Xn)
   ii )  Given information on each of the N observation-specific variance/covariance matrices (VCn)
   iii) Create a XVC: a (M*K)xK matrix containing " these VCn
     M is less than or equal to N (it can be 1)
    iv) And create XVC_IND: a Nx1 vector of pointers into XVC

  Syntax:
     {XVC,XVC_IND}=g_mkxvc(xvcfile,xname,classids,class_name);

  where:
   xvcfile: name of a grbl-style VCI  file (described below)
        xname: Kx1 vector of names of the X variables in the main gauss dataset.
          More specifically, the X variables you will be using in your regression
   classids: Nx1 vector of "class" identifiers -- each observation in the "main" gauss
        dataset has a class identifier. However, it need not be unique -- several, or
        even all, of the N observations can have the save value for classids
        class_name: The name. in XVCFILE. of the class-identifier variable. Values in classids will
          be matched to values of this variable in xvcfile.

   If xvcfile does not exist, or there is no class_name (or _NAME_) variable in the xvcfile, a fatal
   error will occur.

  The XVCFILE -- a special "grbl2 style" variance-covariance-information (VCI) file. 

  XVCFILE should contain variable names that are identical to the variable names
  in your main gauss dataset. In addition, two other variables must be present:

   * The class ID (the class_name variable). This identifies the "class" this row belongs.
     If there are KX variables, there will be KX rows with the same class ID.
     These will be matched to class IDS in the main gauss dataset.

       Important note: different observations in the main gauss dataset can share the 
       same class identifiers !!

       In fact, every single observation (every single row) in the main gauss dataset 
       can have the same value for this "class" identifier.

     Thus, if a set of observations have different "observed" values of X, but the 
     same variance/covariance (say, the same noisiness features), one should
     use the same "class" identifer value for each observation.


   * A _NAME_ variable (must have a name of "_NAME_").
       
  Example:
           CLSID    _NAME_     X1  X12   X5  X4 ;
         1    X1        20    1    5   -3
         1    X12        1   51   -3    6    
              1      X5         5   -3   22   12 
         1      X4          -3   12    6    8 
         2    X1        23    2    0   -13
         2    X12        2   31    0    12
         2      X4         -13   12    0    2 

   Notes:
           *  Symmetry should be maintained: the value of row XA and column XB should match that
         of row XB column XA. GRBL2 programs will enforce symmetry, but not necessarily in a way you
         intend.
                *  Note that the X5 row is missing for CLSID=2 -- value of 0 are used (as reflected in the
         X5 column for CLSID=2)
            * If a model uses the  X variables: X1 Z1  X12 X4, 
         then the variance/covariance matrix used for CLSID=1 will be
            20  0  1  -3
                      0   0  0   0
                 1   0 51   6
                 -3  0  6   8
         Note that since Z1 is not specified in either columns are rows, 0s are used.


        



 
G_1OPT: get 1 variable (or a number) from batch command -- return index,name,ie 

   {index_into_varnames,varname_or_number,okflag,next_ie}=
     g_1opt(astr,acommand,ie,exactxyz,vrnames,numok,others)

      Astr = Error message header
  acommand = string to read the "option" from
       ie  = start location for reading from acommand
  exactxyz = if =1 , then exact variable matches only
   vrnames = names of current variables
    numok  = if 1, input might be a number
    others = vector of "other" commands, that are legit (not vars or numbers). If one of 
             these is selected, status=3.

   index_into_varnames: if variable, this is the index of this variable (into vrnames)
                        if a number, this is a string containing the number
   varname_or_number : variable name, or a number
   status: 0=error, 1=variable, 2=number, 3=special command
   next_ie: used by g_getwrd to get next command 

  Note: If others="";
       index_into_varnames points into the vrnames. Hence, vrnames[index_into]=varname
        However, others ne "";
            if any of the "others" are chosen, index_Into_varnames will equal 0.
 


G_NOPTS: get list of variables from batch command -- return index,name,nvars,ie @

   {index_into_varnames,varnames,#_of_vars,next_ie}=
     g_nopts(astr,acommand,ie,exactxyz,vrnames,others)

      Astr = Error message header
  acommand = string to read  these "variable names" from
       ie  = start location for reading from acommand
  exactxyz = if =1 , then exact variable matches only
   vrnames = names of current variables. or *, if no checking is desired
    others = vector of "other" commands, that are legit (not in vrnames)

   index_into_varnames:  the index of these variables (into vrnames)
                        
   varnames : variable names
   #of _vars : # of variables
   next_ie: used by g_getwrd to get next command 
 
  Notes:
      * if others="";
         index_into_varnames points into the vrnames. Hence, vrnames[index_into]=varnames
        if others ne "", then...
            if any of the "others" are chosen, that row of index_Into_varnames will equal 0.
      * if vrnames="*", index_Into_varnames is always equal to missing.  
        That is, if vrnames="*", g_Nopts simply returns a list of words (no matching to
        varnames is attempted).

G_PAUSE: Pause for a timespan, or until key is hit
   hh=g_pause(seconds,int_key)
   
    seconds: seconds to pause
       or
    int_key: stop when key with ascii value=INT_KEY is hit

     INTKEY=0 -- any key
         27   --  escape
    
    Special: Ctrl-Home wait forever, or until any key is hit

    Returns either 0 or 1, depending on what key was hit and what INT_KEY value is.
    (experiment to find out which and when).

G_PAUSE2: Pause for timespan, return value of key hit

    dakey=g_pause2(prompt,seconds)

    Prompt is a string -- it will be displayed (against a grey background)
    before the "pause for keystroke"  occurs.

    Returns ascii value of key hit.
    If no key is hit, return miss(1,1)

G_PADWORD: Pad a word with spaces, to desired length

        newtext=g_padword(atext,ilen)

      Returns a string of length ilen.  
      Pads atext with  spaces (spaces added to end of word) if strlen(atext)<ilen.

G_PADWRD: Pad a word with spaces, to desired length -- front or back

        newtext=g_padwrd(atext,ilen,front)

      Returns a string of length ilen.  
      Pads atext with  spaces if strlen(atext)<ilen.
      If front=0, add spaces to back of word. Otherwise, add to front.

G_PNLIND: Construct an index identifying panels of data (ID version)

      pnl_indx=g_pnlind(panelids)
  
     Construct an index, given a vector of panelids.
     pnl_index will be npanels x 2, where 
       npanels: number of unique panels. 
          pnl_index[ith,1] = pointer to first row of ith panel
          pnl_index[ith,2] = pointer to last row of ith panel
     Note that pnl_index[1,1] will always equal 1, and pnl_Index[rows(pnl_Index),2] will
     always equal rows(panelids)

     Example:
        let z=1 1 1 2 2 40 40 40 40 3 1002 1002 ;
        pnl_indx=g_pnlind(z);
     aindx will be a 5x2 vector: 
                1 3
                4 5
                6 9
               10 10
               11 12

    Note that panels are identified by runs of the same panel_id.  Hence, a panel_id
    that is used in several "runs of observations" does NOT identify a single
    panel. Rather each run (where a run is seperated by some other panel_id) is 
    a unique panel.

    Also, "missing value" is a legitimate panel identifier.

G_PNLIND_COUNT: Construct an index identifying panels of data (COUNT version)

      pnl_indx=g_pnlind_count(panelids)
  
     Construct an index, given a vector of panelids.
     pnl_index will be npanels x 2, where 
       npanels: number of unique panels.
          pnl_index[ith,1] = pointer to first row of ith panel
          pnl_index[ith,2] = pointer to last row of ith panel
     Note that pnl_index[1,1] will always equal 1, and pnl_Index[rows(pnl_Index),2] will
     always equal rows(panelids)

     Example: 
         let z=3 3 3 2 2 4  4  4  4  1  2 2 ;
         pnl_indx=g_pnlind_count(z);

      pnl_indx will be a 5x2 vector: 
                1 3
                4 5
                6 9
               10 10
               11 12

    Note that panels are identified by the "count" of the number of observations.

    Only the count (from the first row in a set) is used.
    Thus, in the above example, the following would yield the same result:
         let z=3 0 0 2 1 4  3 2 1  1  2 2 ;
    (the 2 and 3 values are ignored, the 5 value is ignored, etc)

    Also, "missing value" is assumed to mean 1 (a one row panel)

G_PARSEMIME: Parse a "mime like" file
    {field_names,the_values}=g_parsemime(filename);

  where:
     filename: fully qualified name of a "mime like" file
     field_names: Nx1 string vector of "field names". Or "" if no valid "mime like" rows found
     the_values: Nx1 string vector of "field values" (corresponding to field_names)
  
  Mime like files have the structure:
     Field_name:  a string 
   
  Blank lines, lines that begin with @, and lines with no ":" are ignored.

  Example:
     Suppose that D:\MYSTUFF.CFG contains
         @This is my configuration file @
         UPDATE: 3 March 2006

         DIR: E:\DATA\SIMPLE
         INIT:    10
   
    
  Then
     {f1,v1}=g_parsemime("d:\mystuff.cfg")
   would return Nx1 string vectors:
     F1[1]=UPDATE         
     F1[2]=DIR
     F1[3]=INIT
     V1[1]=3 March 2006
     v1[2]=E:\DATA\SIMPLE
     V1[3]=10

   Note that leading and trailing spaces are stripped from all elements in both vectors,
   and all field-names are capitalized.



G_REPLACESTRING: Do substring replacements

    newstring=g_replacestring(haystack,needle,new1,all)
 
   Where:
      haystack : what to look in
      needle   : what to look for
      new1     : occurences of needle are replaced by new1
      all      : if 1, replace all occurences (otherwise, just the first)

   Example:
     newstirng=g_replacestring("Joe has 1, Sam has 1 ","1","one",1);
     yields newstring of "Joe has one, Sam has one"

    Note: searchs for needle are case-insensitive (but cases of haystack and new1 are retained). 


G_REPSTG: Do substring replacements, use QUERY and DEFINE definitions
     
       nustring=g_repstg(oldstring,definew,defines)

       Any substring, in oldstring, of the form "$XYZ", that has a match of the form "XYZ" 
       in DEFINEW, will  be replaced by the corresponding value of DEFINES.

       In general, you can use the DEFINEW and DEFINES  global string arrays set by
       G_BATCH (as specified in DEFINE keyphrases).

       Note that GRBL2 initializes 4 "generic" strings in DEFINEW:
       MODEL, BASETITLE, VARLIST, and FILENAME


G_SCREEN: Set screen display attributes (in the dos compatability box)

 foo=g_screen("",attribs_list)

 The attribs_list contains a list of screen display attributes. These attributes
 effect characters written after the current location of the cursor (as
 determined by csrrow and csrcol).

 The following lists some of the effects of different attributes:

    1 :  bright
    7 : reverse background


   for n:
      31 : red    32: green   33: yellow  34: blue
      35: pink 36: cyan 37: white

   n :  dim version on black background
   1|n : bright version of above
   1:(n+10) white text on bright-version-background of above
   n+10 : gray text on dim-version-background of above
   7:(n+10) : above on gray background 



   Examples:
      call g_screen("",31) ;        -- red text on black background
      call g_screen("",1|31) ;      -- bright red text on black background
      call g_screen("",45) ;        -- grey text on magenta background
      call g_screen("",1|33);       -- bright yellow text on black background
      call g_screen("",1|46) ;      -- bright white text on cyan background
      call g_screen("",7);          -- black text on grey background 
      call g_screen("",7|44);       -- blue text on grey background 
      call g_screen("",1|7|42) ;    -- green text on bright white background
      call g_screen("",1|33|42);    -- bright yellow text on a green background
      call g_screen("",1|36|43);    -- bright cyan text on yellow background
      call g_screen("",1|7|33|41);  -- red text on bright yellow background
      call g_screen("",7|36|41);    -- magenta text on cyan

   Note that including 7 in a long list has very odd effects!


 Notes:

   *  THESE SCREEN CONTROLS ONLY WORK WHEN YOU ARE RUN YOUR GAUSS PROGRAMS IN A
      DOS COMPATABILITY WINDOW.

   * G_SCREEN (and the procedures noted below) do NOT add characters to the screen, nor
     to they change the current location  of the screen cursor (that is, of where
     characters will be written to on the screen).

   * There are several procedures, that use G_SCREEN, which provide shortcuts:
      call normalon ;  -- revert to normal screen atributes
      call boldon ;    -- bold text -- same as: call g_screen("",1); 
      call blockon ;   -- reverse (grey background) -- same as: call g_screen("",7); 
      call blueon ;    -- blue text
      call cyanon ;    -- cyan text
      call yellowon ;  --  yello text
      call grey_bkg ;  -- grey background
      call blue_bkg ;  -- blue background
      call gold_bkg ;  -- yellow/gold background


      Example:
          call boldon ;" Dependent Variable: ";;call normalon ;
          call blockon; "SALES04" ; call normalon;


  *  The several "screen attribute" procedures listed above use the first argument of G_SCREEN.
     However, for explicit use of G_SCREEN, it is simplest not to use the first argument.

  *  HINT: it is good practice to call the normalon procedure before, and after,
           calling G_SCREEN and the desired output.
      Example:
      call normalon ;
             call g_screen("",33) ; " hello " ;; 
           call normalon ;

  *  G_SCREEN uses "ansi" control sequences. 


G_STRIP: Strip spaces from a string, or from all elements in a string matrix
        newstrg=G_STRIP(oldstrg)

G_STRIPC: Strip any character from  a string

      newstrg=G_STRIP(oldstrg,achar)
  
      If achar="", then G_STRIP is the same as G_STRIPC.

     G_STRIPC does NOT work with string matrices -- just with single strings.


G_SHOWVEC: Write a vector of character strings in a pretty format.
  Syntax:
     foo=g_showvec(cvector,columns,indent,amessage)
  where
   
     cvector: an Nx1 (N can be any value) vector of character strings.  Each element contains an 8 character or less
         string.
     columns: number of columns to use when displaying. Each column uses 9 characters.
     indent : number of columns to indent (From left)
    message: message to display in the indented area. Message will be broken at word boundaries.
        If a word is longer than the indent, that row will ONLY have the message 

Example of output:

    this code ...

        aa=getname("mydata");
        call g_showvec(aa,7,20,"the variable list ");

     could yield:

       the variable   ID        YEAR      ALTID     XREP      X_001     X_002     X_003     
       list           X_004     X_005     TX_001    TX_002    TX_003    TX_004    TX_005    
                      RESP      YTRUE     GROUP     INGROUP   VCID 



G_SUBSTUTE: substitue values in a vector

  newvec=g_substute(avec,inds,newvals);

 where:
   avec : an Nx1 vector of values
   inds : an Nx1 vector of 0/1 variables
   newvals: a scalar, or a Nx1 vector of replacement values

   newvec : modified version of avect

  Values in AVEC will be replaced by valeus in NEWVALS, but only when the corresponding row in 
  inds is equal to 1.

 Example:
    v_censored=g_substute(v_original,old1.<0,0)

  Notes:

   *  avec, inds, and newvals can be 1xN or Nx1 -- a Nx1 vector is returned in either case
   *  SUBSTUTE seems to be flakey, hence the need for this procedure



G_VUSLCT: View the current list of observation selection criteria.


   list_string=g_VuSlct(clist,dataset,noprint)

   Clist: the matrix  generated by G_BATCH when  a SELECT ... keyphrase is processed 
      is processed.  Currently,  G_BATCH sets the SLCTLIST variable

   Dataset: name of dataset
   noprint: if 1, do NOT print the results (just return it)
       Option: you can add a second row to noprint containing "suffix".       
          This will be added to the beginning of each row.
          Typically, the suffix is extra spaces (to indent the output)

   list_string: a string containing viewable description of the criteria coded into clist

   Note on clist: 
   Clist is typically the SLCTLIST global matrix created by G_BATCH when a 
      SELECT ....
    command is processed.

    Clist's structure is:
       if missrv(clist,0)==0, use all observations.
    Otherwise;
       each row of clist is a selection criteria
           col1: Logical operation: OR or AND
           col2: Varindex (into the VARLIST variable: the variables in DATASET)
           col3: Condition: EQ, NE, GE, LE, GT, or LT
           col4: A numeric value


G_VUDUM: View the current list of make dummy variables specifications

    list_string=g_Vudum(dlist,dataset,noprint,long,othervars)

   dlist  : the matrix  generated by G_BATCH when  a DUMMY ... keyphrase is processed 
      is processed.  Currently,  G_BATCH sets the DINFO variable
   Dataset: name of dataset
   noprint: if 1, do NOT print the results (just return it)
   long: output format...
   0 : returns a vector of variables names (that correspond to DUMMY matrix created by
       g_mkdata)
   1 : short (4 or so line) description of the dummy variable definitions
      2 : long -- dummy names followed by underlying dummy value
   othervars : a vector of other variables names, that can be used as cardinal variables
       Or, a "" if there are no such other variables
         Often, you can use xnewinfo.names[1:nxnew] (if nxnew>0)
   
   Note on dlist: 
   Dlist is typically the DINFO global matrix created by G_BATCH when a 
      DUMMY ....
    command is processed.

    dlist's structure is:
      Each row  constains instructions for creating a set of dummy variables.
      The structure of the row is:

            O_INDEX ~ C_INDEX ~ NLEVELS ~  Level1 ~ ... ~ LevelN

       O_index refer to the "ordinal variable".
       O_index is an index into the list of  variables contained in DATASET.
      
           The ordinal variable is used determine which dummy is non-zero. 
           More precisely, the number of unique values (across all observations)
           of O_NAME is used  to determine the number of dummies to create.
         And, the particular value of an observation's O_NAME variable is used to determine
      which one of these dummies gets the non-zero value (nb: there is only one non-zero
           value per set of dummies).

        c_index is the "cardinal variables".
   c_index is an index into the list of variables contained in DATASET.

           The cardinal variables  are used as the actual value of the non-zero dummy.
           Often, the goal is to create a set of 0/1 dummies.
      To do this, set C_NAME to anything you  want (say, "DUMMY") and C_INDEX=0.

   NLEVELS is the number of levels, where one dummy is created per level.
   This is the number of unique values eld by O_NAME (Or one less).

        LEVEL1 ... LEVELN are the actual values for these NLEVELS unique values.


         If more then one DUMMY is being created, the rows may be of unequal length
         (missings are used  to pad the matrix size to the length of the longest row,
         where the longest row is belongs to the ordinal variable with largest number of
    unique values).


       Note: when GRBL2 creates dummies, it will compare an observations value of O_NAME
        to the NLEVELs levels. If none match, all the dummies will have a zero value.
        If the m'th level matches, then the m'th dummy will have the value of C_NAME
        (or a value of 1).  Note that the values of the levels can be ANYTHING, they
        do NOT have to be consecutive integers.


G_VUXNEW: View the current list of XNEW new variable equations

   list_string=g_VuSlct(mstruct,dataset,noprint)

   mstruct: the "structure variable", of the kind generated by G_BATCH when  a XNEW ... keyphrase
      is processed.  Currently, this is G_BATCH sets the XNEWinfo variable
   Dataset: name of dataset
   noprint: if 1, do NOT print the results (just return it)


  Note on mstruct:
   Mstruct is typically the XNEWinfo global matrix created by G_BATCH when a
      XNEW  ....
    command is processed.

    Mstructs's structure is:
       mstruct.neq=0 if there are no defined new-variables

    Otherwise

       mstruct.neq   : 1x1 scalar, the # of equations defined
       mstruct.names : 20x1 vector, the "new variable names" to create.
       nterms :  20x1 vector of # of terms in each equation.
       vtypes : 20x5 matrix of  VAR/NUM/FUNC indicators -- "VAR" for "variable", "NUM" for numeric value,
      NEWVAR for one of the mstruct.names "new" variables, and FUNC for function name
       vvals  : 20x5 matrix of values.
              If "VAR" vtype, pointer to VARLIST (varlist is the list of variables in dataset)
         IF "NUM" vtype, the actual numeric value
         If "FUN", the function to use (on cumulative value)
        opers : 20x5 matrix of "operators".
      There are 5 operators: "+", "-", "*", "/", and "=".
      The "=" operator is only used with the first value/variable -- it's really just a
      placeholder.

        Note that only the first NEQ rows of the vectors & matrices are actually filled (the others
   will have missing values).


   Supported functions are: LN, EXP, LN_vv.vvv, SIND, and COSD

       LN_vv.vvv means "use log of vv.vvv if value is <= 0 "

G_WORD : Pull nth word from astring, or return #words in a string
    aword=g_word(nth,astring)

    If nth=0, return the number of words in a string.
    Words are seperated by spaces, commas, line feeds, periods, semi-colons, colons,
    exclamation points, question marks, " and ' characters, and tabs.
    
    Aword will be the value of the nth word (stripped of spaces, etc.)
    
    Example:
    aword=g_word(0,"This is, without a doubt, an example")  : aword=7
    aword=g_word(3,"This is, without a doubt, an example")  : aword=without

    If nth is a Nx1 vector, returns a Nx1 string vector
    (in which case, nth[j]<1 yields "").

    Nth=-1 returns a string vector containing all the words in the string.
    Thus:   
          aa=g_word(seqa(1,1,g_word(0,astring)),astring)
            is the same as
          aa=g_word(-1,astring)

    If nth<-1, or nth># words, returns "".


G_VUFILE:  View a text file

    call g_vufile(afile,aheader)

    View a file (AFILE), and display HEADER at the top of the screen.
    Viewing area is lines 3 to 22.

G_VUTEXT:  View a text string

  call g_vutext(topline,botline,astring,&proc1,&proc2)

  Display a long text string, with user given ability to scroll
  back and forth in the string.
  Display area is from topline to botline.
  Display string is in astring
  Proc1 and proc2 (called as &aproc1,&bproc1) contain names of
  "character attribute" routines: such as boldon, blueon, etc.

  Note: G_DSPTXT is an alternate name for this procedure.


G_WORD

G_YESNO:  Prompt for a yes/no answer

      ians=g_yesno(prompt,defans)

      DEFANS should be NO, YES,0 or 1 (0 and NO are synonymous, as are 1 and YES).
      Returns 0 if NO, 1 if YES.



G_YES_NO:  Prompt for a yes/no answer (with special key detection)
      {ians,istat}=g_yesno(prompt,defans)

      DEFANS should be NO, YES,0 or 1 (0 and NO are synonymous, as are 1 and YES).
      IANS set to 0 if NO, 1 if YES.

      ISTAT=0 if normal (NO or YES) answer.
      If ESC hit, ISTAT=miss(1,1)
      If ?, Alt-h, or F1 hit, ISTAT=1


G_ZAPCMT: Remove comments from a string.

      nustuf=g_zapcmt(stuf,cmt_char);

      Stuf is a string, often one that is read from a file.
      cmtchar is a character used to delimit comments.
      This is almost always '@';
      Nustuf is stuff, with @ xxx @ comments removed.

     Example: Nustuff=g_zapcmt('This is @ a comment @ real! ','@')
              Nustuff will be "This is real!"




