There are problems with your code -- some are actual bugs that are
causing the program to fail, and others are just things I do differently
for the sake of readability or maintainability.
a) I'd put your iconv-related stuff into a copy book so you can easily
b) Instead of repeating the structure in the toCde and frmCde data
structures, and coding the name of the structure in every subfield, I'd
create one QUALIFIED data structure named QtqCode_t (since that's what
IBM calls it) and use LIKEDS to create toCde and frmCde.
c) Instead of passing pointers to QtqIconvOpen(), I'd simply pass the
LIKEDS data structures to it. These can be CONST.
d) You're actually calling the QtqIconvOpen() API, but you've renamed
your prototype (via extproc) to be called iconv_open() which is the name
of a different API on the system with a different syntax. This is
a) You're passing the pInBuf, inBytesLft, pOutBuf and outBytesLft
parameters to iconv() has CONST. This is wrong -- the API is expected
to change all of these variables.
b) You've put a variant character at the beginning of your __errno()
prototype. I used to make the same mistake! This causes problems any
time you try to send your code to someone who uses a different character
set than you do. For example, when you send your code to me, there's a
garbage character at the beginning of the prototype, thus making it
unusable. Nowadays, I use the name 'sys_errno' instead of '@__errno' so
that the code has no translation problems.
c) You aren't checking the return value from iconv(). You should only
check the value of errno if it tells you that it failed.
d) You also aren't checking that QtqIconvOpen() was successful, but are
proceeding to do translations... that'll make it awfully difficult to
tell what the error is if QtqIconvOpen() fails.
e) You are passing %addr() and %size() to iconv(). iconv() wants to be
able to change those values -- it can't change %addr() or %size()
(actually -- it can, and it will -- becuase RPG will put the results of
those functions in temporary memory locations -- but you'll be unable to
read the changes it makes)
f) You are passing the same pointer and length for both the input and
output buffer. This will be problematic if you ever need to work with
character sets that aren't purely single-byte (such as Unicode)
g) Iconv() will translate one character at a time from your buffer.
Each time it succeeds in translating a character, it changes the input
buffer pointer to be one higher (moving to th enext character). It also
changes the output buffer pointer to be one higher (moving to th enext
character). It also decreases the lengths of the two buffers, showing
how much space is left after the translation. The problem here is that
you're passing pData directly to iconv() -- whcih changes the pointer
that you called %alloc() with. Becuase of this, there will be no way to
deallocate the memory you got with %alloc since the pointer has changed.
You need to save the original pointer from %Alloc() in order to
h) Which brings me to: your code doesn't even attempt to deallocate
i) The iconv() API (for the reasons explained in g, above) wants a
pointer to pointer for each buffer. The idea is that it needs a
pointer to your pointer in order to change it. Unfortunately, you're
going one step further and passing a pointer to a pointer to a pointer.
A pointer is a variable that stores the address of data. So if you were
trying to translate a variable, you'd do %addr(var) because that gives
you the address of the variable. However, you don't want to do
%addr(pointer) because that doesn't give you the address of the data
it's pointing to -- it gives you the address of the pointer itself. You
don't want to translate the MEMORY ADDRESS to ASCII -- you want to
translate the data that it points to to ASCII!
diego acevedo wrote:
I'm writing a program that needs to convert a huge set of data (more than 64k) using RPGLE.
As you know, the maximun size allowed to declared a character field in this language is 65535 bytes (aka: 64k), but in this case, the data to send is more large (about 128k) Since the QDCXLATE can't be perform conversions above 32k's, I decided to use the iconv() API passing, as buffer, a pointer instead of a character field.
The problem is that, when I pass a character field (no matter size) the funcion works wonderfully but, if I use a pointer (or pointer to pointer as the prototype says) no conversion is performed and the error returned is EBADF ("Descriptor not valid")
Could anybody help me to solve this problem?
Thank you very much!