× 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.



Hello Emmanuel,

I am trying to update an ifs file by using the c function lseek() for
positioning and then write() to update the ifs file. I had no success
so far.

That's because your prototype for lseek() is wrong. The first parameter to lseek is a file descriptor -- NOT A FILE NAME. In RPG, that means a 10I 0 field passed by VALUE. You did this correctly on the read(), write() and close() APIs. On lseek(), however, you passed a pointer instead of an integer, and in your code you're passing the address of the filename instead of passing the descriptor that was returned by the open() API. Please change that.

Another major problem with your code is that you're calling open() twice, once to create the file and set it's attributes, and again to enable translation. Nothing wrong with that -- except that you only close it the 2nd time. Please understand that each call to open() opens a NEW INSTANCE of the file -- and each call to open() must therefore be closed separately. As it stands, your program will leave the file open, even after it ends. Consider adding a call to close() to the Pr_SetFile() routine.

Also, please be advised that the first byte in a stream file is byte #0. Your code currently says lseek(xxx: 1: SEEK_SET) Since you've passed a 1 in the 2nd parameter, it'll actually position to the 2nd byte of the file. If you want the firist byte, it should be lseek(xxx: 0: SEEK_SET) since 0 identifies the first byte.

There are a few things about your code that will work, but I consider them to be bad practices. I'll point them out and let you decide what to do about them:

a) The first parameter to the open() API ("filename") should have options(*string) on the prototype. options(*String) will AUTOMATICALLY add the Null to the end of the filename for you, and it'll eliminate the need to use %ADDR() in your code.

So instead of coding this:

Filename = %Trim(FileName) + Null;
Err_Flag = Open(%Addr(Filename) : Oflag);

You simply do this:

Err_Flag = open(%trim(FileName): Oflag);

The system automatically adds the null to the end so you don't have to. Much nicer.

b) I find the name 'Err_Flag' to be confusing. Keep in mind that open() actually returns a file descriptor that identifies the open file to the other APIs -- the return value is far more than an error flag.

c) Your prototype for open() and the constants that go with it are missing the CCSID and text create capabilities that were added to the IFS APIs in V5R1 and V5R2.

d) You have your O_ and S_ constants coded not as constants, but as variables. That's confusing! There's no reason to code these as variables that someone can change the value of! Literally, O_CREAT should be the same thing as the number 8 -- it should not just be a variable that starts at the number 8 and can be changed.

Instead of coding them like this:

D O_CREAT S 10I 0 Inz(8)

code them like this:

D O_CREAT C Const(8)

That way, the next guy knows that O_CREAT is always 8, it's just a symbolic name for 8... instead of a variable that starts at 8.

e) You have all of your prototypes and constants stored in the actual source member instead of a copy book. This makes your code harder to read, since it's cluttered up with all of these definitions. It also makes it harder to use the IFS APIs in other code, because you now have to repeat the same code in every program instead of just coding a /COPY or /INCLUDE. Furthermore, it makes it difficult to add new features as the IFS APIs change from release to release. Now, if you want to support the features of the new release, you have to go and change every single program that uses the APIs, instead of changing one copy book.

(Which is probably why you're missing all of the features like options(*string), O_TEXT_CREAT and O_CCSID -- whomever you copied your code from had created a maintenance nightmare that was too difficult to change when the new features became available.)

Please consider moving your definitions to a copybook.

f) You use O_CODEPAGE when creating the file, and O_TEXTDATA when re-opening the file -- which works okay, but limits you to using code pages and not full CCSIDs. If you ever need to work with a double-byte or mixed-byte character set, you'll want to use CCSIDs instead.

To do that, change your open() that creates the file to specify O_CCSID, like this:

fd = open( %trimr(filename)
: O_CREAT + O_CCSID + O_WRONLY
: Omode
: 1208 );
callp close(fd);

Then, when you re-open the file specify O_CCSID again, but this time specify a CCSID of zero. (If you don't specify O_CCSID, the system defaults to using a codepage of 0 -- but you want a CCSID of zero to enable full CCSID processing instead of being stuck with code pages)

fd = open( %trimr(filename)
: O_RDWR + O_TEXTDATA + O_CCSID
: 0: 0);

This way, you can do translation using CCSIDs.

Note that starting in V5R2, you can use O_TEXT_CREAT to enable full translation in a single call to open(), eliminating the need to have separate calls to set the attributes and to re-open in text mode.

fd = open( %trimr(filename)
: O_RDWR + O_CREAT
+ O_TEXTDATA + O_CCSID + O_TEXT_CREAT
: OMode
: 1208
: 0 );

Though, I'm so used to using two opens that I tend to keep doing it, even though I'm coding for V5R4 :)

f) Please consider adding code to your program to do proper error handling. The way your program is written, if anything fails the program simply ends without giving any feedback to the user. That makes it much, much more difficult to troubleshoot problems, since there are thousands of things that can potentially go wrong, and the user has to try to guess at which one happened.

g) Also, if an error occcurs in your PR_ReadFile() routine, you call the PSSR to ened the program WITHOUT closing the file -- that means the file will be left open, even after your program ends. Not good.

h) IF it saves you time & effort, you can download my copy books for the IFS APIs and error handling from the following link. Then you don't have to invest time in getting your prototypes and constants for the APIs to be correct.

http://www.scottklement.com/presentations/IfsSources.zip


Sorry for providing a whole laundry list of flaws in your code -- but in my opinion, you're making a lot of "beginners mistakes", and having this stuff pointed out while you're just getting started is a whole lot better than finding out after you have 500 programs in production.

Good luck!

As an Amazon Associate we earn from qualifying purchases.

This thread ...

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.