home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / dongrovs.zip / cmdline.cmd < prev    next >
OS/2 REXX Batch file  |  1996-10-16  |  31KB  |  976 lines

  1. /* REXX */  
  2.  /* BEGINNING OF CmdLine CODE BY ALBERT CROSBY                         */
  3.  /*     CmdLine.CMD Version 1.0                                        */
  4.  /*     (c) 1994 by Albert Crosby <acrosby@comp.uark.edu>              */
  5.  /*                                                                    */
  6.  /*     This code may be distributed freely and used in other programs.*/
  7.  /*     Please give credit where credit is due.                        */
  8.  /*                                                                    */
  9.  /*     CmdLine.CMD is REXX code that creates a full featured version  */
  10.  /*     of the OS/2 command line parser that may be called from your   */
  11.  /*     programs.                                                      */
  12.  /*                                                                    */
  13.  /*     see also the Documentation                                     */
  14.  /*                                                                    */
  15.  /*     bug corrections by Bernd Schemmer                              */
  16.  /*                                                                    */
  17.  /*     03.10.1994 /bs                                                 */
  18.  /*       - changed variable "key" to "key1"                           */
  19.  /*       - added variable "userDefinedKey"                            */
  20.  /*                                                                    */
  21.  /* This is a CmdLine function for REXX.  It supports                  */
  22.  /*     *  OS/2 style command history. (1)                             */
  23.  /*     *  Keeps insert state. (1)                                     */
  24.  /*     *  Command line _can_ include control chars.                   */
  25.  /*     *  Allows for "hidden" input, for passwords.                   */
  26.  /*     *  A call can be restricted from accessing the history.        */
  27.  /*     *  A call can be restricted from updating the history.         */
  28.  /*     *  A predefined value can be given to extended keys. (1) (2)   */
  29.  /*                                                                    */
  30.  /* NOTE                                                               */
  31.  /* (1) These functions work ONLY if CmdLine is included in the source */
  32.  /*     file for your program.                                         */
  33.  /* (2) Format: !history.nn="string" where nn is the DECIMAL           */
  34.  /*     value for the second character returned when the extended      */
  35.  /*     key is pressed.                                                */
  36.  /*                                                                    */
  37.  /* By: Don E. Groves, Jr                                              */
  38.  /*    Modified to use Object REXX                                     */
  39.  /*                                                                    */
  40.  /*  First off I removed the restriction of (1) above.                 */
  41.  /*  Can either be included as '::requires cmdline'                    */
  42.  /*        cmd_obj= cmdline~new( optional parameters)                  */
  43.  /*        cmd= cmd_obj~cmdline( optional parameters)                  */
  44.  /*                                                                    */
  45.  /*  Or as  cmd=cmdline( optional parameters)                          */
  46.  /*                                                                    */
  47.  /*  The first allows a single session to have multi cmdline objects   */
  48.  /*  each with it's own command history. While the second is easy to   */
  49.  /*  use in old style rexx files.                                      */
  50.  /*                                                                    */
  51.  /*  Second (2) above format change:                                   */
  52.  /*    The Format: of !history.nn="string" is now                      */
  53.  /*     cmd_obj~s_key[nn]="string" where nn is the same as above       */
  54.  /*                                                                    */
  55.  /*    The above used 'cmd_obj' is an example name only each           */
  56.  /*     .cmdline object has it's own history and s_keys object         */
  57.  /*                                                                    */
  58.  /*  Other methods provided are:                                       */
  59.  /*                                                                    */
  60.  /* INIT           Init the object.                                    */
  61.  /*                  Optional parameters:                              */
  62.  /*                    First  - minum width of history.                */
  63.  /*                    Second - default insert state.                  */
  64.  /*                                                                    */
  65.  /* SUPPLIER       returns a .Supplier object filled with that objects */
  66.  /*                current history list.                               */
  67.  /*                                                                    */
  68.  /* MAKEARRAY     returns a .ARRAY object filled with that objects     */
  69.  /*               current history list.                                */
  70.  /*                                                                    */
  71.  /* ClearHistory  clears the current onjects history information.      */
  72.  /*                                                                    */
  73.  /* HistoryAdd    Adds string entries from a .Supplier or Object that  */
  74.  /*               can provide a Supplier method to that objects        */
  75.  /*               current history list.                                */
  76.  /*                                                                    */
  77.  /* insert        Allows get/set state of insert.                      */
  78.  /*                                                                    */
  79.  /* reset         Reset the object to default state.                   */
  80.  /*                                                                    */
  81.  /*                                                                    */
  82.  
  83.  /* Note how I test which way this was invoked. */
  84. parse source . a2 name
  85. atRc= 0
  86. SELECT
  87.  WHEN a2 = 'FUNCTION'
  88.   THEN do  /* Called as 'cmd= cmdline()' uses a session local object. */
  89.     name = filespec('NAME',name)
  90.     if .local['ALBERT_CROSBY_'|| name] = .nil
  91.     then .local['ALBERT_CROSBY_'|| name] = .Cmdline~new
  92.     atRc = .local['ALBERT_CROSBY_'|| name]~cmdline(ARG(1,'A'))
  93.   end
  94.  WHEN a2 = 'COMMAND'
  95.   THEN do  /* called from OS2 command-line. Simple test handler */
  96.     say 'used as a ' || a2
  97.     say 'Test of .Cmdline'
  98.     cmd= 5
  99.     ac = .Cmdline~new(cmd)
  100.     q=.list~of('exit','clear','This is a sample history item','This is another one')
  101.     say 'Minum history width is' cmd
  102.     say '-'~copies(20)
  103.     bc = ac~copy
  104.     cmd='restore'
  105.     do while translate(cmd) \= 'EXIT'
  106.       if translate(cmd) = 'TEST'
  107.       then do
  108.         say '-'~copies(20)
  109.         say 'current history is:'
  110.         su= bc~supplier
  111.         do while su~available
  112.           say ' '~''(su~item)
  113.           su~next
  114.         end
  115.         say '-'~copies(20)
  116.         cmd = bc~cmdline('P=This is BC >')
  117.       end
  118.       if translate(cmd) = 'COPY'
  119.       then do
  120.         say 'making a copy'
  121.         bc= ac~copy
  122.       end
  123.       if translate(cmd) = 'RESTORE'
  124.       then ac~HistoryAdd(q)
  125.       if translate(cmd) = 'CLEAR'
  126.       then do
  127.         ac~ClearHistory
  128.         say 'History was cleared'
  129.       end
  130.       if translate(cmd) = 'SAVE'
  131.       then do
  132.         say 'Saving History'
  133.         su= ac~supplier
  134.         do while su~available
  135.           q~insert(su~item)
  136.           su~next
  137.         end
  138.       end
  139.       say '-'~copies(20)
  140.       say 'current history is:'
  141.       su= ac~supplier
  142.       do while su~available
  143.         say ' '~''(su~item)
  144.         su~next
  145.       end
  146.       say '-'~copies(20)
  147.       cmd = ac~cmdline('P=Type >')
  148.       /* cmd = ac~cmdline('X=5','P=Type >     to end'~''(8~d2c~copies(11)),'D=EXIT') */
  149.       /* 'cls' */
  150.       say '-'~copies(20)
  151.       say 'cmd=' cmd
  152.     end
  153.   end
  154.  WHEN a2 = 'SUBROUTINE'
  155.   THEN nop  /* happens when '::requires cmdline' or 'call cmdline' is used */
  156.  OTHERWISE
  157.    nop /* I've no idea, but then maybe everything will work out ok anyway. */
  158. end
  159. return atRc
  160.  
  161. ::requires RexxUtil_Req
  162.  
  163. ::routine DebugOut
  164.   use arg what
  165.   call charout, 27~d2c~''('[s')~''(27~d2c)~''('[8;15H')~''(what)~''(27~d2c)~''('[u')
  166. return ''
  167.  
  168. ::class History
  169. ::method init
  170.   expose History s_historical LastFind d_search
  171.   self~init:super                       /* Run init method of superclass  */
  172.   self~reset
  173. return self
  174.  
  175. ::method reset
  176.   expose History s_historical
  177.   History = .list~new
  178.   s_historical= .nil
  179.   self~newfind
  180. return self
  181.  
  182. ::method MAKEARRAY
  183.   expose History
  184. return History~MAKEARRAY
  185.  
  186. ::method SUPPLIER
  187.   expose History
  188. return History~SUPPLIER
  189.  
  190. ::method newfind
  191.   expose LastFind d_search
  192.   LastFind = .nil
  193.   d_search = ''
  194. return self
  195.  
  196. ::method count private
  197.   expose History
  198.   use arg i , direction
  199.   if direction
  200.   then do  /* up. Towards the top of the list */
  201.     i = History~previous(i)
  202.     if i = .nil    /* if reached the top then loop to the bottom. */
  203.     then i = History~last
  204.   end
  205.   else do /* down. Towards the bottom of the list */
  206.     i = History~next(i)
  207.     if i = .nil    /* if reached the bottom then loop to the top. */
  208.     then i = History~first
  209.   end
  210. return i
  211.  
  212. ::method LastFind
  213.   expose LastFind
  214. return LastFind
  215.  
  216. ::method search
  217.   expose History s_historical LastFind d_search
  218.   use arg word , direction , relative
  219.   answer = .false
  220.   if (History~items > 0 )
  221.   then do
  222.     direction= \(direction = 0)  /* true = up * false = down */
  223.     start = s_historical
  224.     if start = .nil
  225.     then start = History~last
  226.     word= word~request('string')
  227.     if word = .nil
  228.     then word= ''
  229.     if LastFind \= word
  230.     then do
  231.       d_search= word~translate
  232.       if .false \= relative & LastFind \= .nil
  233.       then start= History~last
  234.       if \direction  /* down */
  235.       then start= self~count(start , direction )
  236.     end
  237.     else start= self~count(start , direction )
  238.     LastFind= .nil
  239.     i = start
  240.     do until i = start
  241.       if History[i]~translate~abbrev(d_search)
  242.       then do
  243.         s_historical=i
  244.         LastFind= History[i]
  245.         answer = .true
  246.         leave
  247.       end
  248.       i = self~count(i , direction )
  249.     end
  250.   end
  251. return answer
  252.  
  253. ::method DelEntry
  254.   expose History s_historical LastFind
  255.   use arg word
  256.   answer = .false
  257.   if ( History~items > 0 & .nil \= s_historical & .nil \= LastFind ) & LastFind == word
  258.   then do
  259.     x = s_historical
  260.     s_historical = self~count(s_historical , .false )
  261.     History~remove(x)
  262.     answer = .true
  263.   end
  264. return answer
  265.  
  266. ::method AddEntry
  267.   expose History s_historical LastFind
  268.   use arg word
  269.   word = word~request('string')
  270.   answer = .false
  271.   if (.nil \= word)
  272.   then do
  273.     if (LastFind \= word)
  274.     then do
  275.       History~insert(word~makestring)
  276.       s_historical=History~last
  277.       answer = .true
  278.     end
  279.   end
  280. return answer
  281.  
  282. ::method From
  283.   expose LastFind d_search
  284.   use arg in
  285.   insup= in~request('Supplier')
  286.   answer = .false
  287.   if .nil == insup
  288.   then do
  289.     if in~hasmethod('supplier')
  290.     then insup= in~Supplier
  291.   end
  292.   if .nil \= insup
  293.   then do
  294.     do while insup~available
  295.       self~AddEntry(insup~item)
  296.       insup~next
  297.     end
  298.     insup = in~request('History')
  299.     if .nil \= insup
  300.     then LastFind= insup~lastFind
  301.     answer = .true
  302.   end
  303. return answer
  304.  
  305. ::method copy
  306. return self~new~From(self)
  307.  
  308. ::class Datum
  309. ::method edited ATTRIBUTE
  310. ::method init
  311.   expose data maxwidth s_insert hidden pos s_sameline
  312.   use arg width,  s_insert , s_hidden , s_sameline, prompt, col, row
  313.   self~init:super                       /* Run init method of superclass  */
  314.   self~edited= .false
  315.   maxwidth= 4096
  316.   if datatype(width,"Whole")
  317.   then maxwidth= width
  318.   s_insert = \(.false = s_insert)
  319.   hidden = \(.false = s_hidden)
  320.   s_sameline = \(.false = s_sameline)
  321.   pos = 0
  322.   data = ''
  323.   parse value SysCurPos() with x y
  324.   if datatype(col,"Whole")
  325.   then y= col
  326.   if datatype(row,"Whole")
  327.   then x= row
  328.   Call SysCurPos x, y
  329.   if prompt \= .nil
  330.   then self~Out(prompt)
  331. return
  332.  
  333. ::method End_Of_Input
  334.   expose s_sameline
  335.   if \s_sameline
  336.   then say
  337. return
  338.  
  339. ::method Out private
  340.   use arg word
  341.   call charout, word
  342. return
  343.  
  344. ::method OutData private
  345.   expose hidden
  346.   use arg word
  347.   if hidden
  348.   then word= '*'~copies(word~length)
  349. return word
  350.  
  351. ::method put
  352.   expose data maxwidth pos s_insert
  353.   use arg key , count
  354.   if datatype(count,"Whole")
  355.   then key= key~copies(count)
  356.   if key~length > 0
  357.   then do
  358.     if s_insert
  359.     then do
  360.       q= maxwidth - data~length
  361.       if key~length > q
  362.       then key= key~left(q)
  363.       data= data~insert(key,pos)
  364.     end
  365.     else do
  366.       q= maxwidth - pos
  367.       if key~length > q
  368.       then key= key~left(q)
  369.       data= data~overlay(key,pos+1)
  370.     end
  371.     self~edited= .true
  372.     if key~length > 0
  373.     then do
  374.       self~Out(self~OutData(key))
  375.       pos=pos+ key~length
  376.       if s_insert & pos < data~length
  377.       then self~Out(self~OutData(data~substr(pos+1))~''(8~d2c~copies(data~length-pos)))
  378.     end
  379.   end
  380. return (key~length > 0)
  381.  
  382. ::method TAB
  383.   expose pos
  384.   use arg width, what
  385.   if \datatype(width,"Whole")
  386.   then width=8
  387.   if width < 1
  388.   then width=1
  389.   what = what~request('string')
  390.   retcode = .false
  391.   if what \= .nil
  392.   then do
  393.     t= 0
  394.     do until t > pos
  395.       t = t + width
  396.     end
  397.     retcode= self~put(what~left(1,' '),t - pos)
  398.   end
  399. return retcode
  400.  
  401. ::method Delete
  402.   expose data pos
  403.   if pos < data~length
  404.   then do
  405.     data= data~delstr(pos+1,1)
  406.     self~Out(self~OutData(data~substr(pos+1)||" ")~''(8~d2c~copies(data~length - pos+1)))
  407.     self~edited= .true
  408.   end
  409. return self
  410.  
  411. ::method BackSpace
  412.   expose data pos
  413.   if data~length > 0 & pos > 0
  414.   then do
  415.     data= data~delstr(pos,1)
  416.     pos = pos - 1
  417.     t= 8~d2c~" "(8~d2c)
  418.     if pos < data~length
  419.     then t=t~''(self~OutData(data~substr(pos+1)~''(" "))~''(8~d2c~copies(data~length - pos+1)) )
  420.     self~Out(t)
  421.     self~edited= .true
  422.   end
  423. return self
  424.  
  425. ::method Left
  426.   expose data pos
  427.   if pos > 0
  428.   then do
  429.     self~Out(8~d2c)
  430.     pos=pos-1
  431.   end
  432. return self
  433.  
  434. ::method Right
  435.   expose data pos
  436.   if pos < data~length
  437.   then do
  438.     self~Out(self~OutData( data~substr(pos+1,1)))
  439.     pos = pos + 1
  440.   end
  441. return self
  442.  
  443. ::method Word_Left
  444.   expose data pos
  445.   if pos > 0
  446.   then do
  447.     do until (data~substr(pos+1,1)\==" " & data~substr(pos,1)==" ")
  448.       self~Out(8~d2c)
  449.       pos=pos-1
  450.       if pos = 0
  451.       then leave
  452.     end
  453.   end
  454. return self
  455.  
  456. ::method Word_Right
  457.   expose data pos
  458.   if pos < data~length
  459.   then do
  460.     do until (pos= data~length | ( data~substr(pos,1)==" " & data~substr(pos+1,1)\==" "))
  461.       self~Out(self~OutData( data~substr(pos+1,1)))
  462.       pos = pos + 1
  463.     end
  464.   end
  465. return self
  466.  
  467. ::method home
  468.   expose data pos
  469.   if pos \= 0
  470.   then do
  471.     self~Out(8~d2c~copies(pos))
  472.     pos=0
  473.   end
  474. return self
  475.  
  476. ::method k_end
  477.   expose data pos
  478.   if pos < data~length
  479.   then do
  480.     self~Out(self~OutData( data~substr(pos+1)))
  481.     pos= data~length
  482.   end
  483. return self
  484.  
  485. ::method Delete_to_end
  486.   expose data pos
  487.   if pos < data~length
  488.   then do
  489.     self~Out(' '~copies(data~length-pos)~''(8~d2c~copies(data~length-pos)))
  490.     data= data~left(pos)
  491.     self~edited= .true
  492.   end
  493. return self
  494.  
  495. ::method replace
  496.   use arg word
  497.   self~home~Delete_to_end~put(word)
  498. return self
  499.  
  500. ::method Delete_to_Beginning
  501.   expose data pos
  502.   if pos > 0
  503.   then self~replace(data~substr(pos+1))~home
  504. return self
  505.  
  506. ::method length
  507.   expose data
  508. return data~length
  509.  
  510. ::method makestring
  511.   expose data
  512. return data~makestring~copy
  513.  
  514. ::method insert
  515.   expose s_insert hidden
  516.   use arg p_insert
  517.   s_insert = (.false = p_insert)
  518. return s_insert
  519.  
  520. ::class do_args
  521. ::method init
  522.   expose do_args current
  523.   use arg parm1 , parm2
  524.   self~init:super                       /* Run init method of superclass  */
  525.   d = parm1~request('ARRAY')
  526.   if d = .nil
  527.   then do_args= .list~of(parm1)
  528.   else do
  529.     do_args= .list~new
  530.     do current = 1 to d~items
  531.       do_args~insert(d[current])
  532.     end
  533.   end
  534.   drop d
  535.   if parm2~items > 0
  536.   then do
  537.     do current = 1 to parm2~items
  538.       do_args~insert(parm2[current])
  539.     end
  540.   end
  541.   current= do_args~first
  542.   if current \= .nil
  543.   then do
  544.     do until current = .nil
  545.       if do_args[current] = .nil
  546.       then do_args~remove(current)
  547.       current= do_args~next(current)
  548.     end
  549.     current= do_args~first
  550.     if current \= .nil
  551.     then do_args= do_args~section(current)
  552.     current= do_args~first
  553.   end
  554. return
  555.  
  556. ::method Available
  557.   expose do_args current
  558. return (current \= .nil)
  559.   
  560. ::method Item
  561.   expose do_args current
  562.   use arg ans
  563.   if current \= .nil
  564.   then ans= do_args[current]
  565. return ans
  566.  
  567. ::method ItemInc
  568.   expose do_args current
  569.   use arg ans
  570.   if current \= .nil
  571.   then do
  572.     ans= do_args[current]
  573.     current= do_args~next(current)
  574.   end
  575. return ans
  576.   
  577. ::class cmdline_table
  578. ::method init  class
  579.   expose s_lower s_upper
  580.   s_lower = .nil
  581.   s_upper = .nil
  582.   forward class (super)
  583. ::method table class
  584.   expose s_lower s_upper
  585.   if s_lower = .nil
  586.   then do
  587.     s_lower = ''
  588.     s_upper = ''
  589.     do i = 1 to 255
  590.       l= i~d2c
  591.       u= l~translate
  592.       if l \= u
  593.       then do
  594.         s_lower= s_lower || l
  595.         s_upper= s_upper || u
  596.       end
  597.     end
  598.   end
  599. return
  600. ::method tolower class
  601.   expose s_lower s_upper
  602.    .cmdline_table~table
  603.    use arg mstring
  604. return mstring~translate(s_lower,s_upper)
  605. ::method toupper class
  606.   expose s_lower s_upper
  607.    .cmdline_table~table
  608.    use arg mstring
  609. return mstring~translate(s_upper,s_lower)
  610.  
  611. ::routine tolower
  612.    use arg mstring
  613. return .cmdline_table~tolower(mstring)
  614.  
  615. ::routine toupper
  616.    use arg mstring
  617. return .cmdline_table~toupper(mstring)
  618.  
  619.  
  620. ::class cmdline public
  621. ::method s_key attribute
  622.  
  623. ::method init
  624.   expose s_insert default_insert s_History s_key s_histwidth
  625.   use arg s_histwidth , default_insert , p_key , p_History
  626.   self~init:super                       /* Run init method of superclass  */
  627.   if \datatype(s_histwidth,"Whole")
  628.   then s_histwidth = 0
  629.   if s_histwidth < 0
  630.   then s_histwidth = 0
  631.   default_insert = \( .false = default_insert)  /* default to insert mode */
  632.   self~reset
  633.   c = p_key~request('Directory')
  634.   if .nil \= c
  635.   then s_key= c~copy
  636.   c = p_History~request('History')
  637.   if .nil \= c
  638.   then self~HistoryAdd(c)
  639. return self
  640.  
  641. /* allow program to reset independently of 'method cmdline' */
  642. ::method reset
  643.   expose s_insert default_insert s_History s_key
  644.   s_History = .History~new
  645.   s_key= .Directory~new
  646.   s_insert = default_insert
  647. return self
  648.  
  649. ::method Copy
  650.   expose s_insert default_insert s_History s_key s_histwidth
  651.   o= self~class~new(s_histwidth, default_insert,s_key,s_History)
  652.   o~insert(s_insert)
  653. return o
  654.  
  655. /* allow program to get/set insert state independently of 'method cmdline' */
  656. ::method insert
  657.   expose s_insert
  658.   hold = s_insert
  659.   if arg() > 0
  660.   then s_insert = \(.false = arg(1))  /* anything but .false equals true. */
  661. return hold
  662.  
  663. /* allow program to get/set minum History Width independently of 'method cmdline' */
  664. ::method HistoryWidth
  665.   expose s_insert
  666.   use arg width
  667.   hold = s_Histwidth
  668.   if datatype(width,"Whole")
  669.   then s_Histwidth= width
  670.   if s_histwidth < 0
  671.   then s_histwidth = 0
  672. return hold
  673.  
  674. /* add entries to history list. */
  675. /* Allows for insertion of default history lists. */
  676. ::method HistoryAdd
  677.   expose s_History
  678.   use arg in
  679.   s_History~From(in)
  680. return self
  681.  
  682. ::method ClearHistory
  683.   expose s_History
  684.   s_History~reset
  685. return
  686.  
  687. ::method MAKEARRAY
  688.   expose s_History
  689. return s_History~MAKEARRAY
  690.  
  691. ::method SUPPLIER
  692.   expose s_History
  693. return s_History~SUPPLIER
  694.  
  695. /* User typed an invalid key. */
  696. ::method Chirp
  697.   beep(400,4)
  698. return
  699.  
  700. ::method cmdline
  701.   expose s_insert s_History s_key hidden s_histwidth
  702.  
  703.  /* Parameters can be any combination of                                */
  704.  /* Hidden      Characters are displayed as "*", no history, not kept.  */
  705.  /* Forget      Do not add the result of this call to the history list. */
  706.  /* No history  Do not allow access to the history list.                */
  707.  /* Clear       Clear the history list with this call (no input action  */
  708.  /*             action made.)  Also clears any predefined keys!         */
  709.  /* Insert      Set insert mode ON.                                     */
  710.  /* Overwrite   Set overwrite mode OFF.                                 */
  711.  /* SameLine    Keep cursor on sameline after input. (Default off)      */
  712.  /* Required    null values are not accepted. (Default off)             */
  713.  /* Valid       Next parameter specifies the valid characters           */
  714.  /*             (no translation) unless specified elsewhere. (1)        */
  715.  /* Upper       Translate input to upper case. (1)                      */
  716.  /* Lower       Translate input to lower case. (1)                      */
  717.  /* Width       Next parameter specifies the maximum width. (1)         */
  718.  /* Autoskip    Do not wait for enter after last char on a              */
  719.  /*             field with a width.                                     */
  720.  /* X           Next parameter specifies the initial X (column) position. */
  721.  /* Y           Next parameter specifies the initial Y (row) position.    */
  722.  /* Prompt      Displays the next parameter as a prompt in front of the   */
  723.  /*             entry field.                                              */
  724.  /* Z           Next parameter specifies the Minum history keep width.    */
  725.  /* Default     Next parameter specifies the default value.               */
  726.  /*                                                                       */
  727.  /* Only the first letter matters.                                        */
  728.  /*  Enter each desired parameter seperated by commas.                    */
  729.  /*                                                                       */
  730.  /* Used letters are: a c d f h i l n o p r s u v w x y z                 */
  731.  /*                                                                       */
  732.  /* NOTES                                                                 */
  733.  /* (1) Upper, Lower, Width, and VALID preclude access to the history list */
  734.  /*      and user defined keys.                                            */
  735.  /*                                                                        */
  736.  /* The first parameter can be an .Array of parameter strings              */
  737.  /*                                                                        */
  738.  hidden= .false
  739.  history= .true
  740.  keep= .true
  741.  sameline= .false
  742.  required= .false
  743.  valid= xrange()
  744.  caps= 0         /* 0 = No Translation, 1 = UpperCase, 2 = lowercase */
  745.  width= 0
  746.  autoskip= .false
  747.  prompt= .nil
  748.  row= ''
  749.  col= ''
  750.  default=''
  751.  if arg() > 0
  752.  then do
  753.    inargs = .do_args~new(ARG(1),ARG(2,'A'))
  754.    do while inargs~available
  755.      cmd= inargs~ItemInc(.nil)~request('string')
  756.      if cmd \= .nil
  757.      then do
  758.        PARSE VALUE cmd WITH cmd '=' parm 1 current_arg
  759.        cmd= cmd~left(1)~translate
  760.        select
  761.         when cmd="X"       /* set the X (column) position. */
  762.          then do
  763.            if parm=""
  764.            then parm= inargs~itemInc('')
  765.            col=parm
  766.          end
  767.         when cmd="Y"       /* set the Y (row) position. */
  768.          then do
  769.            if parm=""
  770.            then parm= inargs~itemInc('')
  771.            row=parm
  772.          end
  773.         when (cmd="P"  | cmd='T')    /* Prompt */
  774.          then do                     /*  with support for undocumented T */
  775.            if parm=""
  776.            then parm= inargs~itemInc('')
  777.            prompt=parm
  778.          end
  779.         when cmd="H"      /* Hidden. Characters are displayed as "*". */
  780.          then do
  781.            hidden= .true
  782.            keep= .false
  783.            history= .false
  784.          end
  785.         when cmd="C"      /* Clear. Reset everthing to default state. */
  786.          then do
  787.            self~reset
  788.            return ""
  789.          end
  790.         when cmd="O"      /* set Insert mode off. */
  791.          then s_insert= .false
  792.         when cmd="I"      /* set Insert mode on. */
  793.          then s_insert= .true
  794.         when cmd="F"      /* Forget. Don't add to history list */
  795.          then keep= .false
  796.         when cmd="S"     /* Keep cursor on sameline. */
  797.          then sameline= .false
  798.         when cmd="R"     /* input is Required. */
  799.          then required= .true
  800.         when cmd="V"     /* valid characters only */
  801.          then do
  802.            if parm=""
  803.            then parm= inargs~itemInc('')
  804.            if parm \= ""
  805.            then valid= parm
  806.            history= .false
  807.            keep= .false
  808.          end
  809.         when cmd="U"    /* Upper case */
  810.          then do;
  811.            caps = 1
  812.            history= .false;
  813.            keep= .false;
  814.          end
  815.         when cmd="L"     /* Lower case */
  816.          then do;
  817.            caps = 2
  818.            history= .false;
  819.            keep= .false;
  820.          end
  821.         when cmd="A"      /* Autoskip */
  822.          then autoskip= .true
  823.         when cmd="W"      /* maximum input width. */
  824.          then do
  825.            if parm=""
  826.            then parm= inargs~itemInc('')
  827.            width=parm
  828.            if \datatype(width,"Whole")
  829.            then width = 0
  830.            if width < 0
  831.            then width = 0
  832.            history= .false
  833.            keep= .false
  834.          end
  835.         when cmd="Z"      /* set Minum history keep width. */
  836.          then do
  837.            if parm=""
  838.            then parm= inargs~itemInc('')
  839.            s_histwidth=parm
  840.            if \datatype(s_histwidth,"Whole")
  841.            then s_histwidth = 0
  842.            if s_histwidth < 0
  843.            then s_histwidth = 0
  844.          end
  845.         when cmd="D"      /* set Default value. */
  846.          then do
  847.            if parm=""
  848.            then parm= inargs~itemInc('')
  849.            default= parm
  850.          end
  851.         otherwise nop
  852.        end  /* select */
  853.      end  /* if inargs~item \= .nil */
  854.    end  /* do while inargs~available */
  855.    drop inargs parm cmd current_arg
  856.  end  /* if arg() > 0 */
  857.  if width = 0
  858.  then do
  859.    width = 4096
  860.    autoskip= .false
  861.  end
  862.  /* Done processing parameters from the dumb programmer. (almost to many) */
  863.  
  864.  /* Now create my Datum object. */
  865.  datum = .Datum~new(width, s_insert,hidden,sameline,prompt,col,row)
  866.  /* Fill it with the default data and home the cursor. */
  867.  datum~replace(default)~home
  868.  drop hidden sameline prompt col row
  869.  /* Now set up my local state variables. */
  870.  s_History~newfind
  871.  userDefinedkey= .false
  872.  key1 = 0
  873.  /* Now fill in the Datum with the Users keyboard input */
  874.  do key1 = 0 Until (13 = key1 & \(required & datum~length = 0)) | (autoskip & datum~length = width) | userDefinedKey
  875.    key1= SysGetKey("NoEcho")~c2d
  876.    select
  877.     when key1 = 13    /* Enter key */
  878.      then do
  879.        if (required & datum~length = 0)
  880.        then self~Chirp
  881.      end
  882.     when key1 = 8     /* Backspace */
  883.      then datum~BackSpace
  884.     when key1 = 27      /* Escape */
  885.      then datum~replace('')
  886.     when key1 = 4   /* Ctrl-D  Delete History Entry and erase line */
  887.      then do
  888.        if (history) & s_History~DelEntry(datum)
  889.        then datum~replace('')
  890.        else self~Chirp
  891.      end
  892.     when key1 = 10   /* Ctrl-Enter */
  893.      then self~Chirp; /* Ignored */
  894.     when key1 = 224 | key1 = 0  /* Extended key handler */
  895.      then do
  896.        key2 = SysGetKey("NoEcho")~c2d
  897.        select
  898.         when key2 = 72 | key2 = 80 /* Up arrow or Down arrow */
  899.          then do
  900.            if (history) & s_History~Search(datum,(key2 = 72),datum~edited)
  901.            then datum~replace(s_History~LastFind)
  902.            else self~Chirp
  903.            datum~edited= .false
  904.          end
  905.         when key2 = 75   /* Left arrow */
  906.          then datum~Left
  907.         when key2 = 77          /* Right arrow */
  908.          then datum~Right
  909.         when key2 = 115          /* Ctrl-Left arrow */
  910.          then datum~Word_Left
  911.         when key2 = 116         /* Ctrl-Right arrow */
  912.          then datum~Word_Right
  913.         when key2 = 83          /* Delete key */
  914.          then datum~Delete
  915.         when key2 = 82          /* Insert key */
  916.          then s_insert= datum~insert(s_insert)
  917.         when key2 = 79          /* End key */
  918.          then datum~k_end
  919.         when key2 = 71      /* Home key */
  920.          then datum~home
  921.         when key2 = 117     /* Control-End key */
  922.          then datum~Delete_to_end
  923.         when key2 = 119      /* Control-Home key */
  924.          then datum~Delete_to_Beginning
  925.         otherwise
  926.          do
  927.            if history & s_key~hasindex(key2)  /* Is there a defined string? */
  928.            then do
  929.              datum~replace(s_key[key2])
  930.              userDefinedkey= .true
  931.              keep= .false  /* user defined keys are concidered singleton keys */
  932.            end
  933.            else self~Chirp
  934.          end
  935.        end  /* of inner select */
  936.        drop key2
  937.      end  /* Extended key handler */
  938.     when datum~length <= width
  939.      then do      /* The key is a normal key & within width */
  940.        ok = .false
  941.        if default~length \= 0
  942.        then datum~replace('')
  943.        key = key1~d2c
  944.        if key1 = 9  /* TAB */   /* put tab key processing where it belongs. */
  945.        then do
  946.          ok = (valid~pos(key) \= 0 & valid~pos(' ') \= 0)
  947.          if ok
  948.          THEN ok= datum~TAB(8,' ')
  949.        end
  950.        else do
  951.          if caps > 0
  952.          then if caps = 1
  953.            then key = toupper(key)
  954.            else key = tolower(key)
  955.          ok = ( valid~pos(key) \= 0 )
  956.          if ok
  957.          then ok=datum~put(key)
  958.        end
  959.        if \ok
  960.        then self~chirp
  961.        drop key ok
  962.      end
  963.     otherwise self~Chirp
  964.    end /* select */
  965.    default = ''
  966.  end /* Until (key1 = 13 & \(required & datum~length = 0)) | (autoskip & datum~length = width) | userDefinedKey */
  967.  datum~End_Of_Input
  968.  if (keep) & (datum~length > s_histwidth)
  969.  then s_History~AddEntry(datum)
  970.  /* and return the Datum as a string to the caller. */
  971. return datum~makestring
  972.  
  973.  /* END OF CmdLine CODE BY ALBERT CROSBY */
  974.   
  975.  
  976.