ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

Passing in variables smaller than sub-procedure definition

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Passing in variables smaller than sub-procedure definition

    Hi,

    I was capitalising the first letter of each word multiple times and decided to stick it in a basic sub-procedure, which I don't usually use but I can't figure out how to correctly handle variables that are smaller than the sub-procedure's input variable.

    The below gets stuck in a loop due to %trim() failing as "lowerText" has the day text followed by a load of jumbled characters - clearly this is memory allocated elsewhere which I shouldn't be looking at. I'm therefore wondering what's the best way to handle this? A second "data length" variable? A better way of defining capitalise? I'd rather not use a 30a workfield to do it, i.e. alpha30 = daytext; daytext = %trim(capitalise(alpha30));

    Example;

    Code:
    h dftactgrp(*no)                                           
    
    d capitalise      pr            30a   extproc('capitalise')
    d   lowerText                   30a   options(*varsize)    
    
    d dayText         s              3a                          
    
     /free                                                     
    
       dayText = 'sun';                                        
       dayText = capitalise(dayText);                          
       dsply dayText;                                          
    
       *inlr = *on;                                            
       return;                                                        
    
     /end-free                                                        
    
    p capitalise      b                                               
    
    d capitalise      pi            30a                               
    d   lowerText                   30a   options(*varsize)           
    
    d char            s              1a   inz(*off)                   
    d forever         s               n   inz(*off)                   
    d startPos        s              2p 0                             
    d lo              c                   'abcdefghijklmnopqrstuvwxyz'
    d up              c                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    
     /free                                                            
    
       startPos = 0;                                                  
    
       dou forever;                                                   
    
         startPos += 1;                                      
    
         %subst(lowerText : startPos : 1) =                  
         %xlate(lo:up:%subst(lowerText : startPos : 1));     
    
         startpos = %scan(' ' : %trim(lowerText) : startPos);
    
         if startPos = 0;                                    
           leave;                                            
    
         endif;                                              
    
       enddo;                                                
    
       return lowerText;                                     
    
     /end-free                                               
    p capitalise      e

  • #2
    Three main approaches.

    1) Use the IBM API approach and pass a separate length field to control the process. You would then set that parm using %Len(... or possibly %Len(%TrimR( ...

    2) Use the CEE APIs within the subprocedure to determine the length of the field passed.

    For both 1 and 2 you would need Options(*Varsize) on the prototype.

    3) Make the input parm a VARCHAR and add the Const (or Value) keyword to the prototype. Your procedure will RETURN the resulting field.

    Any of these will work. Personally I would tend to use the 3rd option but irt depends on how big the biggest field you will handle might be. If it is going to be over 1,000 bytes (say) I might use the different approach

    Comment


    • #3
      The legendary JonBoy here to save the day again, thanks a lot. I have changed it as per your preferred method (#3), as the max size I'll be passing in is 30a, I take it the 1000 bytes consideration is on the basis const makes the program take a copy of the variable so could end up using a lot of memory?

      Altered code below, per your suggestion, just wanting to check the definitions are correct? I read somewhere, can't seem to find the article now, that VARYING adds 2 bytes onto the start of the field to determine the length of the data - do I need to worry about that at all?

      Cheers,
      Ryan

      Code:
      h dftactgrp(*no)                                           
      
      d capitalise      pr            30a   extproc('capitalise')
      d   inputText                   30a   varying const        
      
      d dayText         s              3a                        
      d alpha30         s             30a                        
      
       /free                                                     
      
         alpha30 = 'a text string';                              
         alpha30 = capitalise(alpha30);                          
         dsply alpha30;                                          
      
         dayText = 'sun';                                        
         dayText = capitalise(dayText);                          
         dsply dayText;                                          
      
         *inlr = *on;                                            
         return;                                                        
      
       /end-free                                                        
      
      p capitalise      b                                               
      
      d capitalise      pi            30a                               
      d   inputText                   30a   varying const               
      
      d outputText      s             30a                               
      d char            s              1a   inz(*off)                   
      d forever         s               n   inz(*off)                   
      d startPos        s              2p 0                             
      d lo              c                   'abcdefghijklmnopqrstuvwxyz'
      d up              c                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
      
       /free                                                            
      
        outputText = inputText;                                         
      
         startPos = 0;                                          
      
         dou forever;                                           
      
           startPos += 1;                                       
      
           %subst(outputText : startPos : 1) =                  
           %xlate(lo:up:%subst(outputText : startPos : 1));     
      
           startpos = %scan(' ' : %trim(outputText) : startPos);
      
           if startPos = 0;                                     
             leave;                                             
      
           endif;                                               
      
         enddo;                                                 
      
         return outputText;                                     
      
       /end-free          
      p capitalise      e

      Comment


      • #4
        First thought is - why the loop? %Xlate can operate against a whole field - doesn't need to be a char at a time. Sorry didn't really look at your original code - just proposed options to the stared problem.

        You are correct about the extra 2 (or 4 for large varchar fields) but they do not need to concern you. When used in this fashion RPG will set the length of the varchar to the length of the passed variable. Processing of any varchar field is always as if it were a fixed length field of the length specified by the current length. That makes sense if you read it slowly (probably at least twice).

        The alternative approach comes not just from the copying on input but rather the copying of the return value. When you do myVar = MyProc(myParm) the result is coped onto the stack and then again into myVar so 2 x copying. No biggie on smaller fields but a 1Mb field or a 16Mb DS - that's a lot of copying.

        Comment


        • #5
          No worries re: checking code, I was just after how to define it anyway so you replied with what I needed.

          I'm only capitalising the first character of each word, i.e; 'a text string' = 'A Text String' rather than the entire string, so that's why I'm looping.

          Ah I see, that's a lot of copying indeed.

          Thanks,
          Ryan

          Comment


          • JonBoy
            JonBoy commented
            Editing a comment
            Boy I really must look more at the code!

          • RDKells
            RDKells commented
            Editing a comment
            Haha, it's fine, was just a crappy example to demonstrate what I was asking for.

            Thanks again.
        Working...
        X