× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.




I tried this, but it wasn't clear to me what size to specify on the
options(*varsize) argument. I wanted it to be variable size, so why was I
having to specify a size?

All options(*varsize) does is disable the validity checking of the length of the variable.

Consider the following C code:

   char foo[150];

   BadIdea(foo);
   .
   .
   void BadIdea(char *foo) {
      memset(foo, ' ', 200);
   }

I'm sure you can see why this is a bad idea... it will not only fill "foo" with blanks, but it'll store 50 extra blanks in the space in memory that comes after foo. You know this already, C programmers are used to it.

In RPG, they decided to protect you against doing the same thing. The following code does the exact same thing as the above C code, except that it won't work:

     D foo             s            150A
     c                   callp     Badidea(foo)
      .
      .
     P BadIdea         B
     D BadIdea         PI
     D   foo                        200A
     c                   eval      foo = *Blanks
     P                 E

You'll note that in the RPG sample above, I did "eval foo = *blanks". How did the compiler know how many blanks to put in foo? It went by the variable size. Since the only thing passed to the subprocedure was a pointer (under the covers, at any rate) the system didn't know that the caller's variable was 150. It took the 200 from the parameter definition, and so it wrote 200 blanks to the variable. Overwriting 50 extra bytes!

However, compiler won't compile the above code. It'll stop you and say parameter 1 is not the same length as the prototype. You can't pass a 150 byte parameter when the subprocedure expects a 200 byte parameter. It prevents you from overwriting 50 bytes of memory.

There's a problem with that restriction, however. As a C programmer, you know that the fix to the problem is simple. You just do the following (or some variation on it):

#define FOO_SIZE 150
char foo[FOO_SIZE];

GoodIdea(foo, FOO_SIZE);

void GoodIdea(char *foo, int len) {
    memset(foo, ' ', len);
}

This has a big advantage over the previous version because it can take character variables of ANY length. You don't have to worry about it being exactly 150 or exactly 200 or whatever.

Options(*VARSIZE) is how you do the same thing in RPG... and it has the same drawback. YOUR CODE becomes responsible for making sure it doesn't overwrite memory that it doesn't have permission to.

     D foo             s            150A

     c                   callp     GoodIdea(foo:%size(foo))
      .
      .

     P GoodIdea        B
     D GoodIdea        PI
     D   foo                        200A   options(*varsize)
     D   len                         10I 0 value
     c                   eval      %subst(foo:1:len) = *Blanks
     P                 E

Just like in the C code, I have to carefully make sure that I don't overwrite memory that doesn't belong to me. *VARSIZE disabled the protection that the compiler provided...

Why do you have to specify a length anyway? So that the various RPG opcodes know how big the string is. The "eval foo = *blanks" was one example where the length specified on the prototype was used to assign blanks to the string.

The %xlate() BIF is another example. It'll translate everything up to the length of the string (unless you tell it otherwise)

The %scan() BIF is another example, it searches data in the entire string (unless you tell it otherwise) for a given substring. (it's like strstr in C)

Many of RPG's opcodes and BIFs work on the declared length of the data. When that data is declared with options(*varsize) or is BASED on a pointer... in either case, it's up to you to put restrictions on RPG so that it doesn't access memory that it's not supposed to.

Make sense?

When I specified 1 for the size, it seemed as though (in the debugger) that the data passed in was 1 character long. When I specified 32K - 1 as the size, the variable appeared as though it was 32K, filled with junk from memoryland, and neither %size nor %length (used within the called procedure) was returning the actual intended size of the data.

That's because %size() and %len() only see the length that you declared in the subprocedure. All that the calling routine passed to the subprocedure was a memory address. The calling routine didn't tell the subprocedure what the string's length was.

That's why you want to pass that length in a separate parameter.

Or, alternately, pass an operational descriptor, and use the operational descriptor APIs to find out how long the strings are. (Personally, I don't use opdescs, they're more work than they're worth, and I've had problems with them in the past. Simply passng the length as a parameter works very nicely.)

I think %size thought it was 32K. I can't remember what %length thought.

%len() would've also thought it was 32k, (unless it was also declared as VARYING, which is a whole different subject altogether). Like the RPG opcodes, the debugger uses the length you gave it on the procedure inteface (PI).

For what you're doing, you want to declare it as 32k with options(*varsize) because the RPG opcodes (if you make any mistake) will then restrict you to that 32k of memory... which is a lot safer than the C method (which wouldn't restrict you at ALL) but less restrictive than RPG's default (i.e. without *varsize) which would restrict you to a specific length.

Bah.. I don't feel like I'm explaining this well. Tell me if you understand.

As an Amazon Associate we earn from qualifying purchases.

This thread ...

Follow-Ups:
Replies:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.