Understanding using USRSPACE
Last Post 27 Nov 2012 12:17 PM by Lynne Noll. 12 Replies.
AddThis - Bookmarking and Sharing Button Printer Friendly
  •  
  •  
  •  
  •  
  •  
Sort:
PrevPrev NextNext
You are not authorized to post a reply.
Author Messages
gregwga50
Advanced Member
Advanced Member
Posts:472

--
16 Nov 2012 03:03 PM

I am trying to understand how to load a userspace with data so I have a test program to read a record from a file and populate it to a user space.  I have the following code, please help me understand why it is not populating the user space TESTUSRSPC I created in QTEMP, Assuming that the DSPUSRSPC in TAATOOLS works ok

H  BndDir('QC2LE'    ) DftActGrp(*NO)                           
FPRJDTL    IF   E             DISK                              
                                                                
D SpacePtr        s               *                             
D Dspoint         s               *                             
d UserSpace       s             20    inz('TESTUSRSPCQTEMP')    
 * Standard Error Code data structure                           
dQUSEC            DS           116                              
d QUSBPRV                 1      4B 0          inz(116)         
d QUSBAVL                 5      8B 0                           
                                                                
D TheDta          DS                                            
D                                     qualified                 
D  xPrdnbr                       7S 0                           
D  xPrdmbr                      10                              
D  xPrddesc                     40                              
D  xPrdsrcf                     10                              
D  xPRdsrcl                     10                              
                                                                
D  CrtUsrSpc      PR              *                             
D   CrtSpcName                  20    const          

  /free                                                           
   SpacePtr = CrtUsrSpc(UserSpace);                               
      Read Prjdtl;                                                
       Thedta.xPrdnbr  =  Prdnbr  ;                               
       Thedta.xPrdmbr  =  Prdmbr  ;                               
       Thedta.xPrddesc =  Prddesc ;                               
       Thedta.xPrdsrcf =  Prdsrcf ;                               
       Thedta.xPRdsrcl =  PRdsrcl ;                               
                                                                  
    Dspoint = %Addr(Thedta);                                      
    SpacePtr= Dspoint;                                           
      *INLR = '1';                                                
  /end-free

 

I didn't post the CrtUsrSpc procedure but trust me it works and succesfully creates the user space in QTEMP. It just doesn't populate the user space with the fields. I put the program in debug and data structure Thedta contain valid values. Once I understand how to populate the userspace, I plan to use the theory in a larger project.                                                         

davesmith
Veteran Member
Veteran Member
Posts:1257
Avatar

--
17 Nov 2012 06:55 PM
Looks like you havent quite understood pointers. You need to "base" your variable on the storage referred to by the pointer, and you have to set the pointer before the variable "based" on it is changed. One way might be like this (untested):
H dftactgrp( *no )
FPRJDTL    if   e             disk
D CrtUsrSpc       pr              *
D  UsrSpcName                   20a   const
D UserSpace       s             20a   inz('TESTUSRSPCQTEMP')
D SpacePtr        s               *
D RcdCount        s              5u 0
D TheDta          ds                  qualified based( SpacePtr )
D                                     dim( 1234 )
D  Prdnbr                        7s 0
D  Prdmbr                       10a
D  Prddesc                      40a
D  Prdsrcf                      10a
D  PRdsrcl                      10a
/free
SpacePtr = CrtUsrSpc( UserSpace );
clear RcdCount;
Read PRJDTL;
dow not %eof and RcdCount < %elem( TheDta );
RcdCount += 1;
TheDta( RcdCount ).Prdnbr  = Prdnbr;
TheDta( RcdCount ).Prdmbr  = Prdmbr;
TheDta( RcdCount ).Prddesc = Prddesc;
TheDta( RcdCount ).Prdsrcf = Prdsrcf;
TheDta( RcdCount ).PRdsrcl = PRdsrcl;
Read PRJDTL;
enddo;
return;
/end-free

Dave
davesmith
Veteran Member
Veteran Member
Posts:1257
Avatar

--
17 Nov 2012 07:04 PM
... however, if this is for sorting a subfile as you mention elsewhere, you dont need to use a a user space at all. You can just use memory instead. eg.
H dftactgrp( *no )                           
FPRJDTL    if   e             disk                              
D RcdCount        s              5u 0                           
D TheDta          ds                  qualified
D                                     dim( 1234 )
D  Prdnbr                        7s 0                           
D  Prdmbr                       10a                              
D  Prddesc                      40a                              
D  Prdsrcf                      10a                              
D  PRdsrcl                      10a                              
  /free                                                           
   clear RcdCount;                              
   Read PRJDTL;
   dow not %eof and RcdCount < %elem( TheDta );
     RcdCount += 1;
     TheDta( RcdCount ).Prdnbr  = Prdnbr;                               
     TheDta( RcdCount ).Prdmbr  = Prdmbr ;                               
     TheDta( RcdCount ).Prddesc = Prddesc;                               
     TheDta( RcdCount ).Prdsrcf = Prdsrcf;                               
     TheDta( RcdCount ).PRdsrcl = PRdsrcl;                               
     Read PRJDTL;
   enddo;
   return;                                                
  /end-free

Dave

gregwga50
Advanced Member
Advanced Member
Posts:472

--
19 Nov 2012 02:01 PM

Thanks for the info

If, for some reason you wanted to sort with PRDNBR in descending order, how would you do that. I don't have a need to, right n ow, just curious in case I run into that situation.

 

Lynne Noll
Senior Member
Senior Member
Posts:6567

--
19 Nov 2012 03:15 PM
Here are snippets from a program I have that sorts an array it returns.


d qsort           pr                  extproc(&#39;qsort&#39;)       
d   p_base                        *   value                  
 * number of entries in area to be sorted                    
d   p_Num                       10i 0 value                  
 * width of each entry                                       
d   p_Width                     10i 0 value                  
 * address of compare routine                                
d   p_Comparer                    *   procptr                
d                                     value                  
dprRtnCompare     pr            10i 0                        
d p_First                             likeds(dsRtn)          
d p_Second                            likeds(dsRtn)          

...
Begsr srSort;                                                     
   If sIndex>1; // number of rows in use                                                  
      monitor;                                                    
        qSort(%addr(dsRtn):Sindex:%size(dsRtn):%pAddr(prRtnCompare
      on-error;                                                   
      EndMon;                                                     
   Endif;                                                         
Endsr;       

...

0127.01 pprRtnCompare     b                                                 
0127.02 dprRtnCompare     pi            10i 0                               
0127.03 d p_First                             likeds(dsRtn)                 
0127.04 d p_Second                            likeds(dsRtn)                 
0127.05 d Com1            ds                  likeds(com)                   
0127.06                                                                     
0127.07 d Com2            ds                  likeds(com)                   
0127.08                                                                     
0127.09 d sReturn         s             10i 0                               
0127.10 c/free                                                              
0127.11    monitor;                                                         
0127.12       Eval-Corr Com1=p_First;                                       
0127.13       Eval-Corr Com2=p_Second;                                      
0127.14       If Com1<Com2;                                                 
0127.15          sReturn=-1;                                                
0127.16       Elseif Com1=Com2;                                             
0127.17          sReturn=0;    
      Else;                                                       
         SReturn=1;                                               
      Endif;                                                      
   on-error;                                                      
      SortFailed=*on;                                             
     If not Dumped;                                               
        dump(a);                                                  
        Dumped=*on;                                               
        SortMessage=&#39;Error &#39; + sdsexid + &#39; on line &#39; +            
        sdserrline + &#39; of &#39; + sdspgm;                             
     Endif;                                                       
     sReturn=0;                                                   
   EndMon;                                                        
   Return sReturn;                                                
 /end-free                                                        
p                 e                                                     
                                                                                            
 



The comparer has to be a procedure. It is passed to QSORT by procedure pointer. QSort passes it two entries in the array at a time; the comparer decides which should come first in the list. Basically, if you want a descending sort, either reverse the > and < operations, or reverse the bits with a bit operation in the fields you want to be descending, or just write code that will produce the result you want. Return -1 for first row comes first, 1 for second row comes first.

davesmith
Veteran Member
Veteran Member
Posts:1257
Avatar

--
22 Nov 2012 06:30 AM
There are of course many ways of sorting an array, but for something like this I would use qsort, as Lynne also suggests. It has the advantage of being able to handle composite keys, mixed ascending/descending sequences, "special" values...etc. In fact anything you can code. For example you could change the last bit of code I posted like this to do something simple like sorting by prdnbr:

H dftactgrp( *no )                            
H bnddir( 'QC2LE' )
FPRJDTL if e disk
D qsort pr extproc( 'qsort' )
D Array * value
D Elems 10u 0 value
D ElemSize 10u 0 value
D CompareLogic * value procptr
D SequenceByNbr...
D pr 10i 0 extproc( 'SequenceByNbr' )
D Element1 const likeds( TheDta )
D Element2 const likeds( TheDta )
D RcdCount s 5u 0
D TheDta ds qualified
D dim( 1234 )
D Prdnbr 7s 0
D Prdmbr 10a
D Prddesc 40a
D Prdsrcf 10a
D Prdsrcl 10a
/free
clear RcdCount;
Read PRJDTL;
dow not %eof and RcdCount < %elem( TheDta );
RcdCount += 1;
TheDta( RcdCount ).Prdnbr = Prdnbr;
TheDta( RcdCount ).Prdmbr = Prdmbr ;
TheDta( RcdCount ).Prddesc = Prddesc;
TheDta( RcdCount ).Prdsrcf = Prdsrcf;
TheDta( RcdCount ).PRdsrcl = Prdsrcl;
Read PRJDTL;
enddo;
qsort( %addr( TheDta )
: RcdCount
: %size( TheDta )
: %paddr( SequenceByNbr )
);
return;
/end-free

*---------------------------------------------------------------------
P SequenceByNbr...
P b
D pi 10i 0
D aElem1 const likeds( TheDta )
D aElem2 const likeds( TheDta )
D BEFORE c const( -1 )
D SAME c const( 0 )
D AFTER c const( 1 )
/free
select;
when aElem1.Prdnbr = aElem2.Prdnbr;
return SAME;
when aElem1.Prdnbr < aElem2.Prdnbr;
return BEFORE; // Elem1 should be BEFORE Elem2
when aElem1.Prdnbr > aElem2.Prdnbr;
return AFTER; // Elem1 should be AFTER Elem2
endsl;
/end-free
P e
*---------------------------------------------------------------------

Or if you wanted to do something a little more complicated, like sorting by prddesc, but say you want the blanks to appear at the end instead of the start, its almost the same:

H dftactgrp( *no )                            
H bnddir( 'QC2LE' )
FPRJDTL if e disk
D qsort pr extproc( 'qsort' )
D Array * value
D Elems 10u 0 value
D ElemSize 10u 0 value
D CompareLogic * value procptr
D SequenceByDesc...
D pr 10i 0 extproc( 'SequenceByDesc' )
D Element1 const likeds( TheDta )
D Element2 const likeds( TheDta )
D RcdCount s 5u 0
D TheDta ds qualified
D dim( 1234 )
D Prdnbr 7s 0
D Prdmbr 10a
D Prddesc 40a
D Prdsrcf 10a
D Prdsrcl 10a
/free
clear RcdCount;
Read PRJDTL;
dow not %eof and RcdCount < %elem( TheDta );
RcdCount += 1;
TheDta( RcdCount ).Prdnbr = Prdnbr;
TheDta( RcdCount ).Prdmbr = Prdmbr ;
TheDta( RcdCount ).Prddesc = Prddesc;
TheDta( RcdCount ).Prdsrcf = Prdsrcf;
TheDta( RcdCount ).PRdsrcl = Prdsrcl;
Read PRJDTL;
enddo;
qsort( %addr( TheDta )
: RcdCount
: %size( TheDta )
: %paddr( SequenceByDesc )
);
return;
/end-free
*---------------------------------------------------------------------
P SequenceByDesc...
P b
D pi 10i 0
D aElem1 const likeds( TheDta )
D aElem2 const likeds( TheDta )
D BEFORE c const( -1 )
D SAME c const( 0 )
D AFTER c const( 1 )
/free
select;
when aElem1.Prddesc = aElem2.Prddesc;
return SAME;
when aElem1.Prddesc = *blank and aElem2.Prddesc <> *blank;
return AFTER; // Elem1 should be AFTER Elem2
when aElem1.Prddesc <> *blank and aElem2.Prddesc = *blank;
return BEFORE; // Elem1 should be BEFORE Elem2
when aElem1.Prddesc < aElem2.Prddesc;
return BEFORE; // Elem1 should be BEFORE Elem2
when aElem1.Prddesc > aElem2.Prddesc;
return AFTER; // Elem1 should be AFTER Elem2
endsl;
/end-free
P e
*---------------------------------------------------------------------



Dave
Barbara Morris
Senior Member
Senior Member
Posts:5203

--
26 Nov 2012 12:34 PM
P SequenceByNbr...                                                           
P                 b                                                          
D                 pi            10i 0                                        
D  aElem1                             likeds( TheDta )                       
D  aElem2                             likeds( TheDta )   


The parameters for the compare procedures should always be defined as CONST, to prevent any inadvertent modification of the parameters.
davesmith
Veteran Member
Veteran Member
Posts:1257
Avatar

--
26 Nov 2012 12:59 PM
Quite right Barbara. Corrected in the code above,

Thanks
Dave
gregwga50
Advanced Member
Advanced Member
Posts:472

--
26 Nov 2012 01:27 PM

While everyone is responding to my questions about USRSPC, I have another question or 2.

  1. I've noticed in a lot of examples using *usrspc that certain information (like offset to the data et.al.) is stored at the beginning of the *usrspc. Is this arbitrary information or does the system put it there when the *usrspc is created.
  2. Can you start putting data anywhere in the *usrspc, including position 1 or do you have to start the data at an offset from the beginning of the *usrspc. If so, what is the offset value?
Tommy Holden
Senior Member
Senior Member
Posts:2833
Avatar

--
26 Nov 2012 01:36 PM
you can start putting data from position 1 on the usrspc. the info you're asking about on #1 is most often returned by an API call. the usrspc when created has absolutely no data in it same as a file/table.
gregwga50
Advanced Member
Advanced Member
Posts:472

--
26 Nov 2012 01:57 PM
Which API places info in the userspace. Isn't the creation of the userspace done via api?
Tommy Holden
Senior Member
Senior Member
Posts:2833
Avatar

--
26 Nov 2012 04:20 PM

yes it's created using an API. there's tons of APIs that dump data into user spaces. just check infocenter.

http://publib.boulder.ibm.com/infoc...ef/api.htm

Lynne Noll
Senior Member
Senior Member
Posts:6567

--
27 Nov 2012 12:17 PM
You can load data with an IBM system API if you want system data that fills a user space. But you can load your own user space with whatever you like. How you load it is up to you. You can specify the size somewhere in it (IBM uses a standard header format) but you don't have to. The creation allocates a chunk of contiguous space that you address via a pointer, with very little other support. The difference between a user space and program memory is small except you can save a user space and see it outside the program.


If you have a permanent user space, you have to worry about locking it when you maintain it, this is not done automatically. User spaces can be in permanent memory, which lets you save them just like files. If you have an array, you can then load it just by resolving the pointer to the user space. For permanent arrays, it makes sense to store the size of each entry and number of entries, but it is not required. None of this matters much with QTEMP user spaces.

A user space can be made self expanding (up to 16 meg) via its attributes, so if you need more than you first allocated, the system can get more. However, you need to access by dead reckoning (calculate the displacement to the area you want) so I like to know exactly what I am allocating to help in that reckoning.

You are not authorized to post a reply.

Acceptable Use Policy