/**********************************************************************/
/* (c) Copyright IBM Corporation 1987, 2020                           */
/* This programming example is to be used as a sample program only.   */
/* Although this program may have been reviewed by IBM                */
/* for accuracy in a specific environment, there is no                */
/* guarantee that the same or similar results will be obtained        */
/* elsewhere.  The code is being provided on an 'As is' basis         */
/* without any warranty express or implied.                           */
/*                                                                    */
/* Function:  This program will present a window in which data can    */
/*            be entered, changed, or deleted.                        */
/*                                                                    */
/* Author:  Alan Altmark, IBM                                         */
/*                                                                    */
/*---------------------------  SYNTAX  -------------------------------*/
/* Parameter:   name             determines the name of notepad to    */
/*                               be viewed.  The data is contained    */
/*                               in a file called 'name NOTEPAD A'.   */
/*                               Default: your userid                 */
/*                                                                    */
/* Options:     COLOR c1 c2      c1 is the color of the data area.    */
/*                               c2 is the color of the border.       */
/*                               Reverse video will be used.          */
/*                               Default: TURQUOISE WHITE             */
/*                                                                    */
/*                               If you want to change the color,     */
/*                               edit the last line of the NOTEPAD    */
/*                               file.                                */
/*                                                                    */
/*              SIZE rows cols   The dimensions of the notepad        */
/*                               data area.                           */
/*                               Default: 20 40                       */
/*                               This program sets a rather arbitrary */
/*                               minimum of 20 rows and a maximum of  */
/*                               75 colums.  It was originally        */
/*                               written when 24x80 was standard.     */
/*                                                                    */
/*              PAGES n          The number of pages the notepad      */
/*                               will have.                           */
/*                               Default: 4 pages                     */
/*                                                                    */
/* Control:     PF1              Exit, leaving the notepad displayed. */
/*              PF2              Add a line                           */
/*              PF3              Exit, drop the window                */
/*              PF7              Scroll backward (also PA1)           */
/*              PF8              Scroll forward (also PA2)            */
/*              PF10             Delete a line                        */
/*              PF12             Exit, cancel any updates made        */
/*              ATTN             Pop Window Manager window            */
/**********************************************************************/
address command
 
arg padname padtype . "(" options  ")" trc
 
padname = word(padname userid() , 1)
padtype = word(padtype "NOTEPAD", 1)
padfile = padname padtype "A"
 
if trc <> "" then
  do
    Address CMS
    Call Trace strip(trc)
  end
 
/* If this is a pre-existing notepad, get data from the    */
/* last line.  It contains info on the parameters that     */
/* were used to create it.                                 */
"ESTATE" padfile
padfile_exists = (rc = 0)
 
if padfile_exists then
  do
    "PIPE <" padfile,
     "| take last 1",
     "| var opts_from_file"
    if opts_from_file = "" then
      do
        say "Unable to display notepad.  File corrupted."
        exit 24
      end
    else
      options = opts_from_file
  end
else
  options = GenOpts( options ) "LASTPAGE 1"
 
Parse var options        ,
  =1 "COLOR" color bord  . ,
  =1 "SIZE"  rows  cols  . ,
  =1 "PAGES" maxpage     . ,
  =1 "LASTPAGE" page     .
 
/* OK.  Now ready to start building the window.  First, get rid of */
/* any pre-exisitng windows.                                       */
 
"WINDOW  DELETE" padname
"VSCREEN DELETE" padname
 
/* Calculate the size of the VSCREEN.  It must be able to hold ALL  */
/* of the data.  Most of it is invisible.  The WINDOW slides up and */
/* down over the VSCREEN in "page" sized chunks.                    */
vrows = rows * maxpage
"VSCREEN DEFINE" padname vrows cols+2 "1 1 (REV" color
 
/* Window has 2 extra columns to allow for SF at start and end */
/* Has 2 extra rows to account for top & bottom reserved lines */
/* It looks a little wonky beause of the use of reverse video, */
/* but this program is for learning, not a contest.            */
"WINDOW  DEFINE" padname rows+2 cols+3 "4 38 (NOBORDER"
"SET LOCATION" padname "OFF"   /* Don't want built-in beacon.  */
 
/* Yep.  Old school.  This was written back in the 1980s.      */
/* Create the file.                                            */
if \padfile_exists then
  "EXECIO" vrows "DISKW" padfile "1 F" cols "(FINIS STRING  "
 
/* Populate the VSCREEN from the data file.                    */
"VSCREEN GET" padname padfile "1" vrows
 
/* Header and footer setup */
"VSCREEN WRITE" padname " 1 1" cols+1 "(RESERVED" bord "REV PROT FIELD   "
"VSCREEN WRITE" padname "-1 1" cols+1 "(RESERVED" bord "REV PROT FIELD   "
 
/* Place the window on top of the VSCREEN.  Whatever is behind it shows through. */
"WINDOW SHOW" padname "ON" padname "1 1"
"VSCREEN CURSOR" padname "1 2"
errmsg = ""
 
/* Now just process input from the window */
do until quit = yes
  header = justify("Notepad:_"padname "Page_"page, cols)
  header = translate(header, " ", "_")
  footer = "2=Add 3=Quit 7=Back 8=Fwd 10=Del 12=Cncl"
 
  if errmsg <> "" then       /* Sound the alarm for errors */
    do
      "VSCREEN ALARM" padname
      footer = errmsg
    end
 
  "VSCREEN WRITE" padname  "1 1" cols   "(RESERVED DATA" header
  "VSCREEN WRITE" padname "-1 1" cols   "(RESERVED DATA" left(footer, cols)
  "VSCREEN WRITE" padname "-1 1" cols   "(RESERVED COLOR" ,
                       copies("2", length(errmsg)) || copies("0",cols-length(errmsg))
  errmsg = ""
 
 
  /* Wait for the user to do something */
  "VSCREEN WAITREAD" padname /*2*/
  if rc <> 0 then exit rc
  parse var WAITREAD.1 keytype keynum .
 
  /* Find out where the cursor is.  */
  "QUERY CURSOR (STACK LIFO"
  pull "IN " vcurs cursorpos .  "(" rcursor .      /* msi */
 
  /* Map PF13-24 to PF1-12 */
  if keynum > 12 then keynum = keynum - 12
  keyhit = keytype || keynum
  quit = no
 
  /* If we're not cancelling, write any changed data to the */
  /* VSCREEN.                                               */
  if find("UNKNOWN PFKEY12", keyhit) = 0 then
    do
      do i = 3 to WAITREAD.0
        parse var WAITREAD.i dtype r c data
        "VSCREEN WRITE" padname r c cols "(DATA" strip(data, "T")
      end
    end
 
  /* Position the cursor and update the VSCREEN with the data  */
  "VSCREEN CURSOR" padname "1 2" /*2*/
  "VSCREEN WAITT" padname /*2*/
 
  /* Now process the key that was pressed */
  Select
    when keyhit = "UNKNOWN" then "WINDOW POP WM"
    when keyhit = "ENTER" then nop
 
   /* PF2: Insert a line.  Whatever is at the bottom of the  */
   /*      VSCREEN will be rolled off and deleted.           */
    when keyhit = "PFKEY2" & vcurs = padname then
      do
        if rcursor = "RESERVED" then
          cursorpos = "0"
        Call Update "LOCATE :"cursorpos"#ADD 1#LOCATE :*#DELETE 1"
        "VSCREEN CURSOR" padname cursorpos+1 "2" /*2*/
      end
 
    /*  PF3: Quit.  Remember the attributes of this notepad in the        */
    /*       last line of the file.                                       */
    when keyhit = "PFKEY3" then
      do
        quit = yes
        lastline = "* DO NOT DELETE *",
          "COLOR" color bord "SIZE"  rows  cols "PAGES" maxpage     ,
          "LASTPAGE" page
        Call Update "LOCATE :*#DELETE 1#INPUT" lastline
      end
 
    /*  PF7: Go back one page.  Wrap to the last page if already at the   */
    /*       top.                                                         */
    when keyhit = "PFKEY7" then
      do
        if page > 1 then
          do
            page = page - 1
            "WINDOW BACKWARD" padname
            "WINDOW UP" padname
          end
        else   /* Wrap to bottom */
          do
            page = maxpage
            "WINDOW BOTTOM" padname
            "WINDOW BACKWARD" padname
            errmsg = "Wrapped..."
          end
        "VSCREEN CURSOR" padname "1 2" /*2*/
      end
 
    /*  PF7: Go forward one page.  Wrap to the top if we're already on    */
    /*       the last page.                                               */
    when keyhit = "PFKEY8" then
      do
        if page = maxpage then
          do
            page = 1
            "WINDOW TOP" padname /*2*/
            errmsg = "Wrapped..."
          end
        else
          do
            page = page + 1
            "WINDOW FORWARD" padname
            "WINDOW DOWN" padname
          end
        "VSCREEN CURSOR" padname (page-1)*(rows)+1 "2" /*2*/
      end
 
    /*  PF10: Delete a line.  A blank line will be added to the bottom of */
    /*        the notepad to make up for it.                              */
    when keyhit = "PFKEY10" & rcursor = "DATA" & vcurs = padname then
      do
        Call Update "LOCATE :"cursorpos"#DELETE 1#LOCATE :*#ADD 1"
        "VSCREEN CURSOR" padname cursorpos "2" /*2*/
      end
 
    /*  PF12: Quit without processing any changes on the current page.    */
    when keyhit = "PFKEY12" then
      quit = yes
 
    when vcurs ^= padname | rcursor = "RESERVED" then    /* msi      */
      errmsg = "Invalid cursor location"
 
    otherwise
      errmsg = keytype keynum "not defined"
  end
end
 
"WINDOW  DELETE" padname
"VSCREEN DELETE" padname
 
exit
 
UPDATE:
  /* Write the VSCREEN contents back to the NOTEPAD file */
  arg updparm
  "ERASE" padfile
  "VSCREEN PUT" padname padfile
  if updparm ^= "" then
    do
      /* queue updparm"#SET LRECL" cols "#SET RECFM F#FILE" */
      queue updparm"#COMMAND FILE"
      "XEDIT" padfile "(NOPROF"
    end
  if quit = yes then return
  "VSCREEN CLEAR" padname /*2*/
  "VSCREEN GET" padname padfile "1" vrows
  "VSCREEN WAITT" padname
  return
 
GenOpts: Procedure
  Call Trace 'OFF'
  arg options
  parse value options "COLOR TURQ WHITE" with "COLOR" filea border .
  parse value options "SIZE  20 40"      with "SIZE" rows cols .
  parse value options "PAGES 4"          with "PAGES" pages .
  if rows < 20 then rows = 20  /* Minimum */
  if cols > 75 then cols = 75
  return "SIZE" rows cols "COLOR" filea border "PAGES" pages