MIDRANGE dot COM Mailing List Archive



Home » MIDRANGE-L » June 2008

Re: Question about iconv() function



fixed

Hi Diego,

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.


READABIITY/MAINTAINABILITY

a) I'd put your iconv-related stuff into a copy book so you can easily re-use it.

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

ACTUAL ERRORS

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

h) Which brings me to: your code doesn't even attempt to deallocate the buffer.

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!

Whew.


diego acevedo wrote:
Hi everybody:
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!
Diego





Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2014 by MIDRANGE dot 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 here. If you have questions about this, please contact