Archive

Posts Tagged ‘REXX’

Using the SDSF REXX interface – Part 2

October 12, 2013 Leave a comment

Here’s another REXX exec using the SDSF REXX interface. This one will issue a command to the local system.

/**REXX**************************************************************/   
/*                                                                  */   
/* ISSUCMD - Issue a command.                                       */   
/*                                                                  */   
/* Input args:                                                      */   
/*                                                                  */   
/*  Delay   - # secs to wait for command completion                 */   
/*  Command - Command to issue (do not need leading /)              */   
/*                                                                  */   
/* Output: return code from the command.                            */   
/*                                                                  */   
/********************************************************************/   

parse arg delay, command                                                 

Address 'TSO'                                                           

IsfRC = isfcalls( "ON" )                                                 

saved_delay=ISFDELAY            /* save curr delay */                   
ISFDELAY=delay                  /* Set delay time  */                   

address SDSF "ISFEXEC '/"command"'"                                     
saverc=rc                                                               

ISFDELAY=saved_delay            /* restore delay   */                   

IsfRC = isfcalls( "OFF" )                                               

return saverc

Using the above command to start a started task on the local system:

/* REXX */
rc=ISSUCMD(2,"S CICS1")
return 0
Categories: Mainframe, REXX Tags: ,

Using the SDSF REXX interface – Part 1

September 24, 2013 Leave a comment

I thought I’d post some of the REXX execs I have written that use the SDSF REXX interface. This first one determines if a job is executing, either on the specified lpar if passed in or anywhere in the sysplex if not (subject to shared JES spool limits). It returns a return code and, if executing, the lpar the job (or stc) is executing on separated by a space which you can then parse out.

/**REXX**************************************************************/   
/*                                                                  */      
/* JOBSTAT - Determine if a job is executing or not                 */   
/*                                                                  */   
/* Input args:                                                      */   
/*                                                                  */   
/*  Jobname - Required.                                             */   
/*  sysname - Optional. If specified will only look for job on that */   
/*                      system.                                     */   
/*                                                                  */   
/* Output:                                                          */   
/*  0 - Job is not executing (on requested system if specified)     */   
/*  1 - Job is executing + sysname of system job is running on      */   
/*                                                                  */   
/********************************************************************/   

parse arg jobn , sysname                                                 
upper jobn                                                               
upper sysname                                                           

Address 'TSO'                                                           

IsfRC = isfcalls( "ON" )                                                 

saved_delay=ISFDELAY                                                     
ISFDELAY=0                                                               

executing=0                                                             
executing_on=""                                                         

address SDSF "ISFEXEC ST "jobn                                           

if sysname <> "" then do                                                 
   do i = 1 to jname.0                                                   
      if queue.i = "EXECUTION" & actsys.i = sysname then do             
         executing=1                                                     
         executing_on=actsys.i                                           
         end                               
      end                                 
   end                                     
else do                                   
   do i = 1 to jname.0                     
      if queue.i = "EXECUTION" then do     
         executing=1                       
         executing_on=actsys.i             
         end                               
      end                                 
   end                                     

ISFDELAY=saved_delay                       

IsfRC = isfcalls( "OFF" )                 

return executing" "executing_on

Using the above exec to determine if a job is executing on the local lpar:

/**REXX**************************************************************/   
/*                                                                  */  
/* Call jobstat to see if job is running in the local system        */
/*                                                                  */   
/********************************************************************/  

sysname=MVSVAR('SYSNAME')   /* local sysname */

parse value jobstat("MYJOB",sysname) with executing lpar 
if executing then do                               
   /* do 'executing' stuff here */ 
   say 'Job is executing'         
   end                                             
else do                                           
   /* Do 'Not executing' stuff here */  
   say 'Job is not executing'                                 
   end 

return 0

Using the above exec to determine if a job is executing in the sysplex and on which lpar:

/**REXX**************************************************************/   
/*                                                                  */  
/* Call jobstat to see if job is running anywhere in the sysplex    */
/*                                                                  */   
/********************************************************************/  

parse value jobstat("MYJOB") with executing lpar 
if executing then do                               
   /* do 'executing' stuff here */ 
   say 'Job is executing on '||lpar         
   end                                             
else do                                           
   /* Do 'Not executing' stuff here */  
   say 'Job is not executing'                                 
   end  

return 0
Categories: Mainframe, REXX Tags: ,

Anonymous functions in REXX

June 19, 2013 Leave a comment

In this blog post https://www.ibm.com/developerworks/community/blogs/MartinPacker/entry/dragging_rexx_into_the_21st_century?lang=en Martin Packer was experimenting with modernizing REXX on the mainframe. One topic he mentioned but did not resolve was the use of anonymous functions in REXX.

An anonymous function is a block of code that is not associated with an identifier like a function name. It’s just a block of code you can pass to something else (another function) to run. It’s used a lot in things like jQuery to implement ‘callbacks’ from the invoked function back into your own code.

So I got to thinking about this and did a little experimenting. The following is ‘close’ in that I can pass a block of code into a called function and have it execute there. It could implement some sort of ‘callback’ by for example returning data to the original caller on the stack or via an external data set but I did not go that far. I just wanted to see how hard it would be to run some code passed in by the caller. So here’s my solution:

This first program is the caller of some function that will use the anonymous function code block I pass to it. I define the anonymous function in a comment block in the program (makes it easier to write anything longer than a couple of lines) and load it into a variable using sourceline. Notice that each line of the anonymous function has to end with a semicolon since all the lines get concatenated together into one big string.

/* rexx */                                                             

func=loadfunc('MYANONFUNC')                                                                                                               
rc=z67('parm for z67',func,'This is a message')                        
return 0                                                               

/*-------------------------------------------------------------*/      
loadfunc: procedure                                                    
parse arg reqdname                                                     

code=''                                                                

indata=0                                                               
do i = 1 to sourceline()                                               
   line = sourceline(i)                                                
   select                                                              
      when substr(line,1,11)='/*FUNCTION ' then do                      
         parse var line . name .                                       
         if name=reqdname then do                                      
            indata=1                                                   
            end                                                        
         end                                                           
      when substr(line,1,2)='*/' & indata=1 then leave                 
      otherwise do                                                     
         if indata then code = code||line                              
         end                                                           
      end /* select */                                                 
   end /* do i=1 to sourceline() */                                    

return code   
/*-------------------------------------------------------------*/      

/*FUNCTION MYANONFUNC                                                      
trace "I";                                                             
parse arg msg;          
say msg;   
trace "O";              
return 0;                
*/

The following code is the called function (called z67 in this case), It accepts a parameter for its own use (myparm) which is just displays to demo the ability, the function string itself (func) and any data (funcdata) to be passed to the anonymous function from the caller.

/* rexx */                           
parse arg myparm, func, funcdata     
say "myparm is ("myparm")"           
rc=x(funcdata)                       
return rc                            

x: procedure expose func             
interpret func                       
return 0

The code above parses out the three arguments passed in, displays the first one and then calls an internal function (x) passing it the function data for the anonymous function (funcdata). That allows the passed code to parse any arguments passed to it by the original caller. The 'x' routine gets to the function code itself by exposing the 'func' variable and just executes it using interpret.

Notice that the anonymous function code can also accept arguments from the original caller and do things like turn on trace. It would be quite easy to modify this code so that a variable number of parameters could be passed to the invoked passed function.

Categories: Coding, Mainframe, REXX Tags:

The case of the wrong case…

September 18, 2011 Leave a comment

This has been a bit of a detective story so I thought I’d mention it here in case it helps anyone.

As part of my efforts to move my web based ISPF interface to the stand alone IBM HTTP server I needed to run the REXX execs under USS. Now to be honest I rarely ever touch USS on z/OS but that’s where I needed to be so that’s where I am.

I typically write my REXX execs in lower case so I might end up with one exec invoking another with something like this:

data=myfunc(parm1,parm2,etc)

Where myfunc is another REXX exec in the standard search order (SYSPROC and SYSEXEC typically). This works fine because even though the function name is written in lower case, REXX converts it to upper case and that matches the member name in the library just fine. Everything works great.

BUT! Move over to USS land and things are not so simple. REXX in USS land is case sensitive. Using the example above, I had created the 'myfunc' exec file  in USS with a lower case file name and was surprised when the calling exec could not find it.

Eventually (after two days) I found that by default, REXX makes function names coded like this into UPPER CASE before searching for them (I knew this, I had just forgotten about it) so REXX was searching for a file called 'MYFUNC' whilst the file I had created was called 'myfunc'. Not the same animal in a case sensitive environment.

I could make all my exec file names upper case to address this, but in the event you need to call a lower case function name you can code it like this:

data='myfunc'(parm1,parm2,etc)

And amazingly it will now find the lower case exec file.

Still learning afte all these years…

April 20, 2010 Leave a comment

Since the job submission part of my ISPF on the web app is on the brink of working I decided it’d be nice if it could also monitor the status of the jobs in the background, automatically notify you when a job ends and even display the output.

Turns out (and I never knew this because I’d never had to look at it before) that you can run SDSF in REXX.

This just keeps getting better and better.

Categories: Coding, ISPF, REXX Tags: ,

ISPF via the web

March 18, 2010 4 comments

Many (many) moons ago, way before I’d even heard of AJAX and JQuery and such tools, I wrote (as a proof of concept) a REXX based web server using REXX sockets and a ‘framework’ address space I’d developed some time previously that provided several facilities like multi-tasking and console access.

Recently I was looking at one of our ISPF based applications and wondering how the heck you could give it a web interface. There’s an ISPF GUI client but really, it just brings a 3270 interface onto the desktop and you still need a real 3270 session going (usually via an emulator) to use it. All pretty pointless in my opinion.

But then I thought (as you do), hang on, what if I could run my REXX web server INSIDE my ISPF session? Since it would be running under ISPF it would have access to all the ISPF facilities and yet it could do it’s own thing as far as the UI in the browser was concerned.

As it would be running inside my TSO/ISPF session, it would only need to be a single user server so I would not need the multi-tasking facilities of the framework address space I’d used before and as it was running inside my session, it would be subject exactly the same security rules as if I were on the ISPF session itself (since I am really).

It only took a couple of hours to merge the old client code with the main server code to give me a workable single user web server.

So far it only delivers simple fixed web pages and css style sheets. I’m still trying to figure out how best to support images and javascript (thinking JQuery and other tools minimized packages here which can have looooong lines) but so far it works really well.

The following image is taken from the web page served right out of my TSO/ISPF session:

See, I’ve even made it look like a 3270 screen!

Follow

Get every new post delivered to your Inbox.