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.