Hi Scott,

Thanks for your long and detailed e-mailed.

I didn't have any chance to go back to the program. Hopefully I will do soon.

Once again thanks for your reply.

Emmanuel

-----Original Message-----
From: midrange-l-bounces@xxxxxxxxxxxx
[mailto:midrange-l-bounces@xxxxxxxxxxxx]On Behalf Of Scott Klement
Sent: 31 January 2008 6:10 PM
To: Midrange Systems Technical Discussion
Subject: Re: FW: lseek


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


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.