home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 35 Internet
/
35-Internet.zip
/
dongrovs.zip
/
cmdline.cmd
< prev
next >
Wrap
OS/2 REXX Batch file
|
1996-10-16
|
31KB
|
976 lines
/* REXX */
/* BEGINNING OF CmdLine CODE BY ALBERT CROSBY */
/* CmdLine.CMD Version 1.0 */
/* (c) 1994 by Albert Crosby <acrosby@comp.uark.edu> */
/* */
/* This code may be distributed freely and used in other programs.*/
/* Please give credit where credit is due. */
/* */
/* CmdLine.CMD is REXX code that creates a full featured version */
/* of the OS/2 command line parser that may be called from your */
/* programs. */
/* */
/* see also the Documentation */
/* */
/* bug corrections by Bernd Schemmer */
/* */
/* 03.10.1994 /bs */
/* - changed variable "key" to "key1" */
/* - added variable "userDefinedKey" */
/* */
/* This is a CmdLine function for REXX. It supports */
/* * OS/2 style command history. (1) */
/* * Keeps insert state. (1) */
/* * Command line _can_ include control chars. */
/* * Allows for "hidden" input, for passwords. */
/* * A call can be restricted from accessing the history. */
/* * A call can be restricted from updating the history. */
/* * A predefined value can be given to extended keys. (1) (2) */
/* */
/* NOTE */
/* (1) These functions work ONLY if CmdLine is included in the source */
/* file for your program. */
/* (2) Format: !history.nn="string" where nn is the DECIMAL */
/* value for the second character returned when the extended */
/* key is pressed. */
/* */
/* By: Don E. Groves, Jr */
/* Modified to use Object REXX */
/* */
/* First off I removed the restriction of (1) above. */
/* Can either be included as '::requires cmdline' */
/* cmd_obj= cmdline~new( optional parameters) */
/* cmd= cmd_obj~cmdline( optional parameters) */
/* */
/* Or as cmd=cmdline( optional parameters) */
/* */
/* The first allows a single session to have multi cmdline objects */
/* each with it's own command history. While the second is easy to */
/* use in old style rexx files. */
/* */
/* Second (2) above format change: */
/* The Format: of !history.nn="string" is now */
/* cmd_obj~s_key[nn]="string" where nn is the same as above */
/* */
/* The above used 'cmd_obj' is an example name only each */
/* .cmdline object has it's own history and s_keys object */
/* */
/* Other methods provided are: */
/* */
/* INIT Init the object. */
/* Optional parameters: */
/* First - minum width of history. */
/* Second - default insert state. */
/* */
/* SUPPLIER returns a .Supplier object filled with that objects */
/* current history list. */
/* */
/* MAKEARRAY returns a .ARRAY object filled with that objects */
/* current history list. */
/* */
/* ClearHistory clears the current onjects history information. */
/* */
/* HistoryAdd Adds string entries from a .Supplier or Object that */
/* can provide a Supplier method to that objects */
/* current history list. */
/* */
/* insert Allows get/set state of insert. */
/* */
/* reset Reset the object to default state. */
/* */
/* */
/* Note how I test which way this was invoked. */
parse source . a2 name
atRc= 0
SELECT
WHEN a2 = 'FUNCTION'
THEN do /* Called as 'cmd= cmdline()' uses a session local object. */
name = filespec('NAME',name)
if .local['ALBERT_CROSBY_'|| name] = .nil
then .local['ALBERT_CROSBY_'|| name] = .Cmdline~new
atRc = .local['ALBERT_CROSBY_'|| name]~cmdline(ARG(1,'A'))
end
WHEN a2 = 'COMMAND'
THEN do /* called from OS2 command-line. Simple test handler */
say 'used as a ' || a2
say 'Test of .Cmdline'
cmd= 5
ac = .Cmdline~new(cmd)
q=.list~of('exit','clear','This is a sample history item','This is another one')
say 'Minum history width is' cmd
say '-'~copies(20)
bc = ac~copy
cmd='restore'
do while translate(cmd) \= 'EXIT'
if translate(cmd) = 'TEST'
then do
say '-'~copies(20)
say 'current history is:'
su= bc~supplier
do while su~available
say ' '~''(su~item)
su~next
end
say '-'~copies(20)
cmd = bc~cmdline('P=This is BC >')
end
if translate(cmd) = 'COPY'
then do
say 'making a copy'
bc= ac~copy
end
if translate(cmd) = 'RESTORE'
then ac~HistoryAdd(q)
if translate(cmd) = 'CLEAR'
then do
ac~ClearHistory
say 'History was cleared'
end
if translate(cmd) = 'SAVE'
then do
say 'Saving History'
su= ac~supplier
do while su~available
q~insert(su~item)
su~next
end
end
say '-'~copies(20)
say 'current history is:'
su= ac~supplier
do while su~available
say ' '~''(su~item)
su~next
end
say '-'~copies(20)
cmd = ac~cmdline('P=Type >')
/* cmd = ac~cmdline('X=5','P=Type > to end'~''(8~d2c~copies(11)),'D=EXIT') */
/* 'cls' */
say '-'~copies(20)
say 'cmd=' cmd
end
end
WHEN a2 = 'SUBROUTINE'
THEN nop /* happens when '::requires cmdline' or 'call cmdline' is used */
OTHERWISE
nop /* I've no idea, but then maybe everything will work out ok anyway. */
end
return atRc
::requires RexxUtil_Req
::routine DebugOut
use arg what
call charout, 27~d2c~''('[s')~''(27~d2c)~''('[8;15H')~''(what)~''(27~d2c)~''('[u')
return ''
::class History
::method init
expose History s_historical LastFind d_search
self~init:super /* Run init method of superclass */
self~reset
return self
::method reset
expose History s_historical
History = .list~new
s_historical= .nil
self~newfind
return self
::method MAKEARRAY
expose History
return History~MAKEARRAY
::method SUPPLIER
expose History
return History~SUPPLIER
::method newfind
expose LastFind d_search
LastFind = .nil
d_search = ''
return self
::method count private
expose History
use arg i , direction
if direction
then do /* up. Towards the top of the list */
i = History~previous(i)
if i = .nil /* if reached the top then loop to the bottom. */
then i = History~last
end
else do /* down. Towards the bottom of the list */
i = History~next(i)
if i = .nil /* if reached the bottom then loop to the top. */
then i = History~first
end
return i
::method LastFind
expose LastFind
return LastFind
::method search
expose History s_historical LastFind d_search
use arg word , direction , relative
answer = .false
if (History~items > 0 )
then do
direction= \(direction = 0) /* true = up * false = down */
start = s_historical
if start = .nil
then start = History~last
word= word~request('string')
if word = .nil
then word= ''
if LastFind \= word
then do
d_search= word~translate
if .false \= relative & LastFind \= .nil
then start= History~last
if \direction /* down */
then start= self~count(start , direction )
end
else start= self~count(start , direction )
LastFind= .nil
i = start
do until i = start
if History[i]~translate~abbrev(d_search)
then do
s_historical=i
LastFind= History[i]
answer = .true
leave
end
i = self~count(i , direction )
end
end
return answer
::method DelEntry
expose History s_historical LastFind
use arg word
answer = .false
if ( History~items > 0 & .nil \= s_historical & .nil \= LastFind ) & LastFind == word
then do
x = s_historical
s_historical = self~count(s_historical , .false )
History~remove(x)
answer = .true
end
return answer
::method AddEntry
expose History s_historical LastFind
use arg word
word = word~request('string')
answer = .false
if (.nil \= word)
then do
if (LastFind \= word)
then do
History~insert(word~makestring)
s_historical=History~last
answer = .true
end
end
return answer
::method From
expose LastFind d_search
use arg in
insup= in~request('Supplier')
answer = .false
if .nil == insup
then do
if in~hasmethod('supplier')
then insup= in~Supplier
end
if .nil \= insup
then do
do while insup~available
self~AddEntry(insup~item)
insup~next
end
insup = in~request('History')
if .nil \= insup
then LastFind= insup~lastFind
answer = .true
end
return answer
::method copy
return self~new~From(self)
::class Datum
::method edited ATTRIBUTE
::method init
expose data maxwidth s_insert hidden pos s_sameline
use arg width, s_insert , s_hidden , s_sameline, prompt, col, row
self~init:super /* Run init method of superclass */
self~edited= .false
maxwidth= 4096
if datatype(width,"Whole")
then maxwidth= width
s_insert = \(.false = s_insert)
hidden = \(.false = s_hidden)
s_sameline = \(.false = s_sameline)
pos = 0
data = ''
parse value SysCurPos() with x y
if datatype(col,"Whole")
then y= col
if datatype(row,"Whole")
then x= row
Call SysCurPos x, y
if prompt \= .nil
then self~Out(prompt)
return
::method End_Of_Input
expose s_sameline
if \s_sameline
then say
return
::method Out private
use arg word
call charout, word
return
::method OutData private
expose hidden
use arg word
if hidden
then word= '*'~copies(word~length)
return word
::method put
expose data maxwidth pos s_insert
use arg key , count
if datatype(count,"Whole")
then key= key~copies(count)
if key~length > 0
then do
if s_insert
then do
q= maxwidth - data~length
if key~length > q
then key= key~left(q)
data= data~insert(key,pos)
end
else do
q= maxwidth - pos
if key~length > q
then key= key~left(q)
data= data~overlay(key,pos+1)
end
self~edited= .true
if key~length > 0
then do
self~Out(self~OutData(key))
pos=pos+ key~length
if s_insert & pos < data~length
then self~Out(self~OutData(data~substr(pos+1))~''(8~d2c~copies(data~length-pos)))
end
end
return (key~length > 0)
::method TAB
expose pos
use arg width, what
if \datatype(width,"Whole")
then width=8
if width < 1
then width=1
what = what~request('string')
retcode = .false
if what \= .nil
then do
t= 0
do until t > pos
t = t + width
end
retcode= self~put(what~left(1,' '),t - pos)
end
return retcode
::method Delete
expose data pos
if pos < data~length
then do
data= data~delstr(pos+1,1)
self~Out(self~OutData(data~substr(pos+1)||" ")~''(8~d2c~copies(data~length - pos+1)))
self~edited= .true
end
return self
::method BackSpace
expose data pos
if data~length > 0 & pos > 0
then do
data= data~delstr(pos,1)
pos = pos - 1
t= 8~d2c~" "(8~d2c)
if pos < data~length
then t=t~''(self~OutData(data~substr(pos+1)~''(" "))~''(8~d2c~copies(data~length - pos+1)) )
self~Out(t)
self~edited= .true
end
return self
::method Left
expose data pos
if pos > 0
then do
self~Out(8~d2c)
pos=pos-1
end
return self
::method Right
expose data pos
if pos < data~length
then do
self~Out(self~OutData( data~substr(pos+1,1)))
pos = pos + 1
end
return self
::method Word_Left
expose data pos
if pos > 0
then do
do until (data~substr(pos+1,1)\==" " & data~substr(pos,1)==" ")
self~Out(8~d2c)
pos=pos-1
if pos = 0
then leave
end
end
return self
::method Word_Right
expose data pos
if pos < data~length
then do
do until (pos= data~length | ( data~substr(pos,1)==" " & data~substr(pos+1,1)\==" "))
self~Out(self~OutData( data~substr(pos+1,1)))
pos = pos + 1
end
end
return self
::method home
expose data pos
if pos \= 0
then do
self~Out(8~d2c~copies(pos))
pos=0
end
return self
::method k_end
expose data pos
if pos < data~length
then do
self~Out(self~OutData( data~substr(pos+1)))
pos= data~length
end
return self
::method Delete_to_end
expose data pos
if pos < data~length
then do
self~Out(' '~copies(data~length-pos)~''(8~d2c~copies(data~length-pos)))
data= data~left(pos)
self~edited= .true
end
return self
::method replace
use arg word
self~home~Delete_to_end~put(word)
return self
::method Delete_to_Beginning
expose data pos
if pos > 0
then self~replace(data~substr(pos+1))~home
return self
::method length
expose data
return data~length
::method makestring
expose data
return data~makestring~copy
::method insert
expose s_insert hidden
use arg p_insert
s_insert = (.false = p_insert)
return s_insert
::class do_args
::method init
expose do_args current
use arg parm1 , parm2
self~init:super /* Run init method of superclass */
d = parm1~request('ARRAY')
if d = .nil
then do_args= .list~of(parm1)
else do
do_args= .list~new
do current = 1 to d~items
do_args~insert(d[current])
end
end
drop d
if parm2~items > 0
then do
do current = 1 to parm2~items
do_args~insert(parm2[current])
end
end
current= do_args~first
if current \= .nil
then do
do until current = .nil
if do_args[current] = .nil
then do_args~remove(current)
current= do_args~next(current)
end
current= do_args~first
if current \= .nil
then do_args= do_args~section(current)
current= do_args~first
end
return
::method Available
expose do_args current
return (current \= .nil)
::method Item
expose do_args current
use arg ans
if current \= .nil
then ans= do_args[current]
return ans
::method ItemInc
expose do_args current
use arg ans
if current \= .nil
then do
ans= do_args[current]
current= do_args~next(current)
end
return ans
::class cmdline_table
::method init class
expose s_lower s_upper
s_lower = .nil
s_upper = .nil
forward class (super)
::method table class
expose s_lower s_upper
if s_lower = .nil
then do
s_lower = ''
s_upper = ''
do i = 1 to 255
l= i~d2c
u= l~translate
if l \= u
then do
s_lower= s_lower || l
s_upper= s_upper || u
end
end
end
return
::method tolower class
expose s_lower s_upper
.cmdline_table~table
use arg mstring
return mstring~translate(s_lower,s_upper)
::method toupper class
expose s_lower s_upper
.cmdline_table~table
use arg mstring
return mstring~translate(s_upper,s_lower)
::routine tolower
use arg mstring
return .cmdline_table~tolower(mstring)
::routine toupper
use arg mstring
return .cmdline_table~toupper(mstring)
::class cmdline public
::method s_key attribute
::method init
expose s_insert default_insert s_History s_key s_histwidth
use arg s_histwidth , default_insert , p_key , p_History
self~init:super /* Run init method of superclass */
if \datatype(s_histwidth,"Whole")
then s_histwidth = 0
if s_histwidth < 0
then s_histwidth = 0
default_insert = \( .false = default_insert) /* default to insert mode */
self~reset
c = p_key~request('Directory')
if .nil \= c
then s_key= c~copy
c = p_History~request('History')
if .nil \= c
then self~HistoryAdd(c)
return self
/* allow program to reset independently of 'method cmdline' */
::method reset
expose s_insert default_insert s_History s_key
s_History = .History~new
s_key= .Directory~new
s_insert = default_insert
return self
::method Copy
expose s_insert default_insert s_History s_key s_histwidth
o= self~class~new(s_histwidth, default_insert,s_key,s_History)
o~insert(s_insert)
return o
/* allow program to get/set insert state independently of 'method cmdline' */
::method insert
expose s_insert
hold = s_insert
if arg() > 0
then s_insert = \(.false = arg(1)) /* anything but .false equals true. */
return hold
/* allow program to get/set minum History Width independently of 'method cmdline' */
::method HistoryWidth
expose s_insert
use arg width
hold = s_Histwidth
if datatype(width,"Whole")
then s_Histwidth= width
if s_histwidth < 0
then s_histwidth = 0
return hold
/* add entries to history list. */
/* Allows for insertion of default history lists. */
::method HistoryAdd
expose s_History
use arg in
s_History~From(in)
return self
::method ClearHistory
expose s_History
s_History~reset
return
::method MAKEARRAY
expose s_History
return s_History~MAKEARRAY
::method SUPPLIER
expose s_History
return s_History~SUPPLIER
/* User typed an invalid key. */
::method Chirp
beep(400,4)
return
::method cmdline
expose s_insert s_History s_key hidden s_histwidth
/* Parameters can be any combination of */
/* Hidden Characters are displayed as "*", no history, not kept. */
/* Forget Do not add the result of this call to the history list. */
/* No history Do not allow access to the history list. */
/* Clear Clear the history list with this call (no input action */
/* action made.) Also clears any predefined keys! */
/* Insert Set insert mode ON. */
/* Overwrite Set overwrite mode OFF. */
/* SameLine Keep cursor on sameline after input. (Default off) */
/* Required null values are not accepted. (Default off) */
/* Valid Next parameter specifies the valid characters */
/* (no translation) unless specified elsewhere. (1) */
/* Upper Translate input to upper case. (1) */
/* Lower Translate input to lower case. (1) */
/* Width Next parameter specifies the maximum width. (1) */
/* Autoskip Do not wait for enter after last char on a */
/* field with a width. */
/* X Next parameter specifies the initial X (column) position. */
/* Y Next parameter specifies the initial Y (row) position. */
/* Prompt Displays the next parameter as a prompt in front of the */
/* entry field. */
/* Z Next parameter specifies the Minum history keep width. */
/* Default Next parameter specifies the default value. */
/* */
/* Only the first letter matters. */
/* Enter each desired parameter seperated by commas. */
/* */
/* Used letters are: a c d f h i l n o p r s u v w x y z */
/* */
/* NOTES */
/* (1) Upper, Lower, Width, and VALID preclude access to the history list */
/* and user defined keys. */
/* */
/* The first parameter can be an .Array of parameter strings */
/* */
hidden= .false
history= .true
keep= .true
sameline= .false
required= .false
valid= xrange()
caps= 0 /* 0 = No Translation, 1 = UpperCase, 2 = lowercase */
width= 0
autoskip= .false
prompt= .nil
row= ''
col= ''
default=''
if arg() > 0
then do
inargs = .do_args~new(ARG(1),ARG(2,'A'))
do while inargs~available
cmd= inargs~ItemInc(.nil)~request('string')
if cmd \= .nil
then do
PARSE VALUE cmd WITH cmd '=' parm 1 current_arg
cmd= cmd~left(1)~translate
select
when cmd="X" /* set the X (column) position. */
then do
if parm=""
then parm= inargs~itemInc('')
col=parm
end
when cmd="Y" /* set the Y (row) position. */
then do
if parm=""
then parm= inargs~itemInc('')
row=parm
end
when (cmd="P" | cmd='T') /* Prompt */
then do /* with support for undocumented T */
if parm=""
then parm= inargs~itemInc('')
prompt=parm
end
when cmd="H" /* Hidden. Characters are displayed as "*". */
then do
hidden= .true
keep= .false
history= .false
end
when cmd="C" /* Clear. Reset everthing to default state. */
then do
self~reset
return ""
end
when cmd="O" /* set Insert mode off. */
then s_insert= .false
when cmd="I" /* set Insert mode on. */
then s_insert= .true
when cmd="F" /* Forget. Don't add to history list */
then keep= .false
when cmd="S" /* Keep cursor on sameline. */
then sameline= .false
when cmd="R" /* input is Required. */
then required= .true
when cmd="V" /* valid characters only */
then do
if parm=""
then parm= inargs~itemInc('')
if parm \= ""
then valid= parm
history= .false
keep= .false
end
when cmd="U" /* Upper case */
then do;
caps = 1
history= .false;
keep= .false;
end
when cmd="L" /* Lower case */
then do;
caps = 2
history= .false;
keep= .false;
end
when cmd="A" /* Autoskip */
then autoskip= .true
when cmd="W" /* maximum input width. */
then do
if parm=""
then parm= inargs~itemInc('')
width=parm
if \datatype(width,"Whole")
then width = 0
if width < 0
then width = 0
history= .false
keep= .false
end
when cmd="Z" /* set Minum history keep width. */
then do
if parm=""
then parm= inargs~itemInc('')
s_histwidth=parm
if \datatype(s_histwidth,"Whole")
then s_histwidth = 0
if s_histwidth < 0
then s_histwidth = 0
end
when cmd="D" /* set Default value. */
then do
if parm=""
then parm= inargs~itemInc('')
default= parm
end
otherwise nop
end /* select */
end /* if inargs~item \= .nil */
end /* do while inargs~available */
drop inargs parm cmd current_arg
end /* if arg() > 0 */
if width = 0
then do
width = 4096
autoskip= .false
end
/* Done processing parameters from the dumb programmer. (almost to many) */
/* Now create my Datum object. */
datum = .Datum~new(width, s_insert,hidden,sameline,prompt,col,row)
/* Fill it with the default data and home the cursor. */
datum~replace(default)~home
drop hidden sameline prompt col row
/* Now set up my local state variables. */
s_History~newfind
userDefinedkey= .false
key1 = 0
/* Now fill in the Datum with the Users keyboard input */
do key1 = 0 Until (13 = key1 & \(required & datum~length = 0)) | (autoskip & datum~length = width) | userDefinedKey
key1= SysGetKey("NoEcho")~c2d
select
when key1 = 13 /* Enter key */
then do
if (required & datum~length = 0)
then self~Chirp
end
when key1 = 8 /* Backspace */
then datum~BackSpace
when key1 = 27 /* Escape */
then datum~replace('')
when key1 = 4 /* Ctrl-D Delete History Entry and erase line */
then do
if (history) & s_History~DelEntry(datum)
then datum~replace('')
else self~Chirp
end
when key1 = 10 /* Ctrl-Enter */
then self~Chirp; /* Ignored */
when key1 = 224 | key1 = 0 /* Extended key handler */
then do
key2 = SysGetKey("NoEcho")~c2d
select
when key2 = 72 | key2 = 80 /* Up arrow or Down arrow */
then do
if (history) & s_History~Search(datum,(key2 = 72),datum~edited)
then datum~replace(s_History~LastFind)
else self~Chirp
datum~edited= .false
end
when key2 = 75 /* Left arrow */
then datum~Left
when key2 = 77 /* Right arrow */
then datum~Right
when key2 = 115 /* Ctrl-Left arrow */
then datum~Word_Left
when key2 = 116 /* Ctrl-Right arrow */
then datum~Word_Right
when key2 = 83 /* Delete key */
then datum~Delete
when key2 = 82 /* Insert key */
then s_insert= datum~insert(s_insert)
when key2 = 79 /* End key */
then datum~k_end
when key2 = 71 /* Home key */
then datum~home
when key2 = 117 /* Control-End key */
then datum~Delete_to_end
when key2 = 119 /* Control-Home key */
then datum~Delete_to_Beginning
otherwise
do
if history & s_key~hasindex(key2) /* Is there a defined string? */
then do
datum~replace(s_key[key2])
userDefinedkey= .true
keep= .false /* user defined keys are concidered singleton keys */
end
else self~Chirp
end
end /* of inner select */
drop key2
end /* Extended key handler */
when datum~length <= width
then do /* The key is a normal key & within width */
ok = .false
if default~length \= 0
then datum~replace('')
key = key1~d2c
if key1 = 9 /* TAB */ /* put tab key processing where it belongs. */
then do
ok = (valid~pos(key) \= 0 & valid~pos(' ') \= 0)
if ok
THEN ok= datum~TAB(8,' ')
end
else do
if caps > 0
then if caps = 1
then key = toupper(key)
else key = tolower(key)
ok = ( valid~pos(key) \= 0 )
if ok
then ok=datum~put(key)
end
if \ok
then self~chirp
drop key ok
end
otherwise self~Chirp
end /* select */
default = ''
end /* Until (key1 = 13 & \(required & datum~length = 0)) | (autoskip & datum~length = width) | userDefinedKey */
datum~End_Of_Input
if (keep) & (datum~length > s_histwidth)
then s_History~AddEntry(datum)
/* and return the Datum as a string to the caller. */
return datum~makestring
/* END OF CmdLine CODE BY ALBERT CROSBY */