OpenVMS Source Code Demos
DECNET_TASK_C.BAS
1000 %title "decnet_task_c_xxx"
%ident "Version_101.1" ! <<<---+---
declare string constant k_version = "101.1" , ! <<<---+ &
k_program = "DECnet Task Demo (Client)" !
!=========================================================================================================================
! Title : decnet_task_c_xxx (client)
! Author : Neil S. Rieck
! Purpose: Starts a similar server task on a remote node
! Caveat : This is a quick hack for demo purposes only (for my buddies on comp.os.vms)
!=========================================================================================================================
! History:
!
! Ver Who When What
! --- --- ------ -------------------------------------------------------------------------------------------------------
! 100 NSR 110924 1. original program (using RMS calls like sys$open, sys$read, sys$write)
! 101 NSR 110925 1. now bypass RMS (using calls like sys$assign and sys$qio)
!=========================================================================================================================
OPTION type = explicit ! cuz tricks are for kids
!
%include "starlet" %from %library "sys$library:basic$starlet" ! system services
%include "$ssdef" %from %library "sys$library:basic$starlet" ! ss$
%include "lib$routines" %from %library "sys$library:basic$starlet" ! lib$
%include "$libdef" %from %library "sys$library:basic$starlet" ! lib$_normal
%include "$iodef" %from %library "sys$library:basic$starlet" ! io$
!
%if %declared (%IOSBREC) = 0 %then
record IosbRec ! structure of I/O Status Block
variant
case
group one ! this variation is used with I/O transfers
word rc ! return code
word xfer_count ! transfer count
long long_0 ! device specific info
end group one
case
group two ! this variation is used to satisfy the compiler
basic$quadword quad_0 ! unsigned quad word (system calls)
end group two
case
group three ! this variation is used in $SNDJBC + $SNDJBCW
long job_status ! job status
long long_3 ! device specific info
end group three
end variant
end record IosbRec
%let %IOSBREC = 1
%end %if
!
external long function get_timer_bit_vector(long) ! required for used with SYS$WFLOR
external string function wcsm_dt_stamp ! returns current time: ccyymmddhhmmss
!
!=======================================================================
! Internal Declarations
!=======================================================================
declare long rc% , ! Return Code (system status) &
junk% , ! &
count_r% , ! &
count_w% , ! &
qio_ef% , ! event flag(s) &
timer_ef% , ! &
timer_ef_state% , ! &
qio_ef_state% , ! &
mask% , ! &
word funct% , ! &
io_chan% , ! &
funct_bits_xmit , ! &
funct_bits_recv , ! &
string junk$ , ! &
yada$ , ! &
my_file$ , ! &
IosbRec iosb_xmit , ! &
IosbRec iosb_recv , ! &
basic$quadword DeltaQuad !
declare word constant b256_size = 256 !
map(b256) string b256$ = b256_size !
!=======================================================================
! Main
!=======================================================================
2000 on error goto trap !
margin #0, 132 !
print k_program +"_"+ k_version !
print string$(len(k_program +"_"+ k_version), asc("=")) ! underline previous line
!
! "decnet_demo_s" is the name of my DCL server script
! "decnet_task_s" is the name of a DCL script which runs my BASIC app
!
!~~ my_file$ = 'kawc15"neil hiddenpass"::"task=decnet_demo_s"' x strange but true
my_file$ = 'kawc15"neil hiddenpass"::"task=decnet_task_s"' ! strange but true
!
rc% = sys$assign( my_file$, io_chan%,,) ! assign an i/o channel
if (rc% and 7%) <> 1% then
print "-e- sys$assign: "+str$(rc%)
goto fini_rc
end if
!
rc% = lib$get_EF(qio_ef%) ! get an event flag
if (rc% and 7%) <> 1% then
print "-e- lib$get_ef (1): "+str$(rc%)
goto fini_rc
end if
!
rc% = lib$get_EF(timer_ef%) ! get an event flag
if (rc% and 7%) <> 1% then
print "-e- lib$get_ef (1): "+str$(rc%)
goto fini_rc
end if
!-----------------------------------------------------------------------
! send something
!-----------------------------------------------------------------------
count_w% = 1 !
xmit_loop: !
yada$ = "this is a test. Pass #"+ str$(count_w%) !
b256$ = yada$ !
!
! <<< xmit data >>>
!
! SYS$QIO [efn] ,chan ,func ,[iosb] ,[astadr] ,[astprm] ,[p1] ,[p2] ,[p3] ,[p4] ,[p5] ,[p6]
!
funct_bits_xmit = IO$_WRITEVBLK
!
print "-i- calling sys$qio (write "+str$(count_w%) +")"
rc% = sys$qio( qio_ef% by value, ! efn &
io_chan% by value, ! chan &
funct_bits_xmit by value, ! func &
iosb_xmit::quad_0 by ref, ! iosb &
, ! ast addr &
, ! ast param &
b256$ by ref, ! p1=buf addr &
len(yada$) by value, ! p2=buf size &
, ! p3=ignored &
, ! p4=cr spec &
, ! p5=N/A &
) ! p6=N/A
!
if (rc% and 7%) <> 1% then !
print "-e- sys$qio rc: ";str$(rc%) !
goto fini_rc ! adios...
else !
print "-i- sys$qio rc: ";str$(rc%) !
end if !
!
! since we didn't use $QIOW (on purpose), arm timer then wait for the one of the event flags
!
rc% = sys$bintim("0 00:00:10", DeltaQuad ) ! init delta time (10 seconds from now)
print "-e- sys$bintim rc: "+ str$(rc%) if ((rc% and 1%) <> 1%) !
rc% = sys$setimr(timer_ef%, DeltaQuad by ref,,,) ! now use it to schedule a wake up
print "-e- sys$setimr rc: "+ str$(rc%) if ((rc% and 1%) <> 1%) !
!
! note: for the SYS$WFLOR call to work, both event flags must be in the same event flag cluster.
! The first parameter is only used to determine which event flag cluster to test.
! The second parameter (mask) contains bits representing event flags within that cluster
!
mask% = get_timer_bit_vector( qio_ef%) ! insert vector 1 into mask
mask% = mask% or get_timer_bit_vector(timer_ef%) ! insert vector 2 into mask
!
! <<< wait for either the 'QIO event flag' or the 'TIMER event flag' to change state >>>
!
junk$ = wcsm_dt_stamp ! get snap shot of current time
print "-i- waiting for flag ";qio_ef%;" or flag ";timer_ef%;" time: ";left$(junk$,8)+"."+right$(junk$,9)
!
rc% = sys$wflor( qio_ef%, mask%) ! wait for a response from one of two flags
print "-e- sys$waitfr rc: "+ str$(rc%) if ((rc% and 1%) <> 1%) !
junk$ = wcsm_dt_stamp ! get snap shot of current time
print "-i- waking from event some flag at time: ";left$(junk$,8)+"."+right$(junk$,9)
!
! <<< cancel all timer requests (if any) >>>
!
print "-i- Calling $CanTim" !
rc% = sys$cantim(,) ! cancel all timer requests
print "-e- sys$cantim rc: "+ str$(rc%) if ((rc% and 1%) <> 1%) !
!
! which event flag is set? QIO or TIMER?
!
rc% = sys$readEF(qio_ef%, junk%) ! test QIO event flag
select rc% !
case SS$_WASCLR !
qio_ef_state% = 0 !
case SS$_WASSET !
qio_ef_state% = 1 !
case else !
print "-e- sys$readef-qio rc: "+ str$(rc%) !
end select !
print "-i- QIO-EF-State: ";str$(qio_ef_state%);" "; ! first line half (no <cr>)
!
rc% = sys$readEF(timer_ef%, junk%) ! test TIMER event flag
select rc%
case SS$_WASCLR
timer_ef_state% = 0
case SS$_WASSET
timer_ef_state% = 1
case else
print "-e- sys$readef-timer rc: "+ str$(rc%)
end select
print "-i- Timer-EF-State: ";str$(timer_ef_state%) ! second line half
!
! at this point either the QIO-EF or the TIMER-EF could be set
!
if (timer_ef_state% = 1) and ! if the TIMER-EF expired &
( qio_ef_state% = 0) ! and the QIO-EF didn't...
then ! then the I/O didn't finish
print "-w- oops, the qio seems hung (1)" !
junk% = sys$cancel(io_chan%) !
goto fini !
else ! we've got data so fall thru
if (iosb_xmit::rc and 7%) <> 1 then !
print "-e- the qio failed with status code: "+ str$(iosb_xmit::rc) +" ("+ str$(iosb_xmit::rc and 7%) +")"
else !
print "-i- the qio completed properly" !
end if !
end if !
!-----------------------------------------------------------------------
! receive something
!-----------------------------------------------------------------------
count_r% = 1 !
recv_loop: !
!
!
! <<< receive data >>>
!
! SYS$QIO [efn] ,chan ,func ,[iosb] ,[astadr] ,[astprm] ,[p1] ,[p2] ,[p3] ,[p4] ,[p5] ,[p6]
!
funct_bits_recv = IO$_READVBLK
!
print "-i- calling sys$qio (read "+str$(count_r%) +")"
rc% = sys$qio( qio_ef% by value, ! efn &
io_chan% by value, ! chan &
funct_bits_recv by value, ! func &
iosb_recv::quad_0 by ref, ! iosb &
, ! ast addr &
, ! ast param &
b256$ by ref, ! p1=buf addr &
b256_size by value, ! p2=buf size &
, ! p3=ignored &
, ! p4=cr spec &
, ! p5=N/A &
) ! p6=N/A
!
if (rc% and 7%) <> 1% then !
print "-e- sys$qio rc: ";str$(rc%) !
goto fini_rc ! adios...
else !
print "-i- sys$qio rc: ";str$(rc%) !
end if !
!
! since we didn't use $QIOW (on purpose), arm timer then wait for the one of the event flags
!
rc% = sys$bintim("0 00:00:02", DeltaQuad ) ! init delta time (2 sec from now)
print "-e- sys$bintim rc: "+ str$(rc%) if ((rc% and 1%) <> 1%) !
rc% = sys$setimr(timer_ef%, DeltaQuad by ref,,,) ! now use it to schedule a wake up
print "-e- sys$setimr rc: "+ str$(rc%) if ((rc% and 1%) <> 1%) !
!
! note: for the SYS$WFLOR call to work, both event flags must be in the same event flag cluster.
! The first parameter is only used to determine which event flag cluster to test.
! The second parameter (mask) contains bits representing event flags within that cluster
!
mask% = get_timer_bit_vector( qio_ef%) ! insert vector 1 into mask
mask% = mask% or get_timer_bit_vector(timer_ef%) ! insert vector 2 into mask
!
! <<< wait for either the 'QIO event flag' or the 'TIMER event flag' to change state >>>
!
junk$ = wcsm_dt_stamp ! get snap shot of current time
print "-i- waiting for flag ";qio_ef%;" or flag ";timer_ef%;" time: ";left$(junk$,8)+"."+right$(junk$,9)
!
rc% = sys$wflor( qio_ef%, mask%) ! wait for a response from one of two flags
print "-e- sys$waitfr rc: "+ str$(rc%) if ((rc% and 1%) <> 1%) !
junk$ = wcsm_dt_stamp ! get snap shot of current time
print "-i- waking from event some flag at time: ";left$(junk$,8)+"."+right$(junk$,9)
!
! <<< cancel all timer requests (if any) >>>
!
print "-i- Calling $CanTim" !
rc% = sys$cantim(,) ! cancel all timer requests
print "-e- sys$cantim rc: "+ str$(rc%) if ((rc% and 1%) <> 1%) !
!
! which event flag is set? QIO or TIMER?
!
rc% = sys$readEF(qio_ef%, junk%) ! test QIO event flag
select rc% !
case SS$_WASCLR !
qio_ef_state% = 0 !
case SS$_WASSET !
qio_ef_state% = 1 !
case else !
print "-e- sys$readef-qio rc: "+ str$(rc%) !
end select !
print "-i- QIO-EF-State: ";str$(qio_ef_state%);" "; ! first line half (no <cr>)
!
rc% = sys$readEF(timer_ef%, junk%) ! test TIMER event flag
select rc%
case SS$_WASCLR
timer_ef_state% = 0
case SS$_WASSET
timer_ef_state% = 1
case else
print "-e- sys$readef-timer rc: "+ str$(rc%)
end select
print "-i- Timer-EF-State: ";str$(timer_ef_state%) ! second line half
!
! at this point either the QIO-EF or the TIMER-EF could be set
!
if (timer_ef_state% = 1) and ! if the TIMER-EF expired &
( qio_ef_state% = 0) ! and the QIO-EF didn't...
then ! then the I/O didn't finish
print "-w- oops, the qio seems hung (2)" !
junk% = sys$cancel(io_chan%) !
goto fini !
else ! we've got data so fall thru
if (iosb_recv::rc and 7%) <> 1 then !
print "-e- the qio failed with status code: "+ str$(iosb_recv::rc) +" ("+ str$(iosb_recv::rc and 7%) +")"
else !
print "-i- the qio completed properly" !
print "-i- RECV> "+ left$(b256$, iosb_recv::xfer_count) !
end if !
end if !
!
print "--------------------------------" ! end of send-recv pair
count_w% = count_w% + 1 !
if count_w% <= 5 then ! have we sent enough?
goto xmit_loop !
end if !
print "-i- enough messages sent, time to exit normally"
!
! don't corrupt rc% after this point
!
junk% = sys$cancel(io_chan%) !
junk% = sys$dassgn(io_chan%) !
!
goto fini ! adios
!
!=======================================================================
! Trap (BASIC error handler)
!
! this will go to sys$output (sys$error)
!=======================================================================
20000 trap:
print cr + lf + "Line = "+ str$(erl) + &
cr + lf + "Error= "+ str$(err) + &
cr + lf + "Text = "+ ert$(err)
resume fini ! fix stack + exit
!=======================================================================
! adios
!=======================================================================
Fini:
rc% = 1 ! VMS-S-
goto final_exit
!
! rc% must be set up b4 this point
!
fini_rc:
!
final_exit:
32000 END program rc% !
!
!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
!
! inline external functions and sub programs
!
!======================================================================
! get timer bit vector
! (see OpenVMS system systevices documentation for "sys$wflor")
!
! notes: cluster event flags
! 0 00- 31
! 1 32- 63
! 2 64- 95
! 3 96-127
!======================================================================
32100 function long get_timer_bit_vector(long event_flag)
option type = explicit
declare long temp
!
select event_flag
case <= 31
temp = event_flag
case <= 63
temp = event_flag - 32
case <= 95
temp = event_flag - 64
case else
temp = event_flag -96
end select
!
select temp ! this code will avoid an integer overflow
case 31 ! need to set bit #31
! 33222222222211111111110000000000
! 10987654321098765432109876543210
get_timer_bit_vector = B"10000000000000000000000000000000"L ! so return this
case else !
get_timer_bit_vector = (2% ^ temp) ! else return this
end select
!
end function ! get_timer_bit_vector
!
32110 function string Wcsm_DT_Stamp
!===================================================================================================================
! Title : Wcsm_DT_Stamp_100?.inc
! Author : Neil S. Rieck
! Purpose: an external function to return a y2k compliant system time in the form ccyymmddhhmmss (14 chars)
! Notes : all our programs call this function so optimizations here will speed up the whole system
! History:
! 100a NSR 911229 1. original work
! NSR 940423 2. changed 'ON ERROR' to 'WHEN ERROR'
! 100b NSR 961108 1. cleaned up
! 100c NSR 961108 1. optimized
! 100d NSR ?????? 1. optimized
! 100e NSR 980618 1. optimized
! 2. added XX to month names so adding a skew wouldn't be necessary
! 3. replaced left hand mid$ with tens mapping
! 100f NSR 980619 1. optimized
! 2. added some code so I could remove the call to RSET (this may increase the size of both $PDATA
! and $CODE but might reduce execution time by avoiding one call to the BASIC RTL. Only
! benchmarking will determine wether this change is better or worse)
! NSR 101007 3. now use definitions from starlet
! 4. renamed the maps just incase
!===================================================================================================================
option type=explicit ! cuz tricks are for kids...
!
%include "starlet" %from %library "sys$library:basic$starlet" !
!
declare long sys_status
!
! this map is required for the call to sys$asctim (format: 19-JUN-1998 23:59:59.1)
!
map (WcsmDTStamp0) string Sys_buf_22 = 22
map (WcsmDTStamp0) string Sys_day = 2, ! &
Sys_dash1 = 1, !- &
Sys_month = 3, ! &
Sys_dash2 = 1, !- &
Sys_year = 4, ! &
Sys_space = 1, ! &
Sys_Hour = 2, ! &
Sys_colon1 = 1, !: &
Sys_Minute = 2, ! &
Sys_colon2 = 1, !: &
Sys_Second = 2, ! &
Sys_period = 1, !. &
Sys_Tenth = 1 !
!
! map for Wcsm date (output)
!
map (WcsmDTStamp1) string Wcsm_buf_14 = 14 !
map (WcsmDTStamp1) string Wcsm_year = 4, ! &
Wcsm_month = 2, ! &
Wcsm_day = 2, ! &
Wcsm_Hour = 2, ! &
Wcsm_Minute = 2, ! &
Wcsm_Second = 2
map (WcsmDTStamp1) string Wcsm_year = 4, ! &
Wcsm_month_tens = 1, ! &
Wcsm_month_ones = 1, ! &
Wcsm_day_tens = 1, ! &
Wcsm_day_ones = 1, ! &
Wcsm_Hour = 2, ! &
Wcsm_Minute = 2, ! &
Wcsm_Second = 2
!
! string constants
! 00000000011111111112222222222333333333
! 12345678901234567890123456789012345678
declare string constant k_month_names$ = "XXJANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"
! ||
! ++-- so I don't have to provide an offset in pos()
declare string constant my_space = '32'C
!
! <<< function 'code' starts here >>>
!
when error in
!
sys_status = sys$asctim(,Sys_buf_22,,) ! get ASCII time into sys_buf_22
!~~~ if (sys_status and 7%) <> 1% then cause error 11 x not required - call will never fail
!
! transfer data from one map to the other
!
Wcsm_year = Sys_year !
!~~~ rset Wcsm_month = str$( pos(k_month_names$,Sys_Month,1%) / 3%) x bf_100f
Wcsm_day = Sys_day !
Wcsm_hour = Sys_hour !
Wcsm_minute = Sys_minute !
Wcsm_second = Sys_second !
!
declare long temp% ! bf_100f
temp% = pos(k_month_names$,Sys_Month,1%) / 3% ! compute month number bf_100f
if temp% < 10% then ! if less than 10... bf_100f
Wcsm_month_ones = str$(temp%) ! ...then this goes into ONES bf_100f
Wcsm_month_tens = "0" ! ...and this goes into TENS bf_100f
else ! else >= 10 bf_100f
Wcsm_month = str$(temp%) ! bf_100f
end if
!
! make sure there are no spaces in the TENS area of our mapped variables (pad with '0' if necessary)
!
!~~~ Wcsm_month_tens = "0" if Wcsm_month_tens = my_space x disabled - see above code bf_100f
Wcsm_day_tens = "0" if Wcsm_day_tens = my_space !
!
! now pass result back to caller
!
Wcsm_DT_Stamp = Wcsm_Buf_14 ! this is it folks
use
Wcsm_DT_Stamp = "" ! error so return blank
end when
!
END Function