Unconfigured Ad Widget

Collapse

Announcement

Collapse
No announcement yet.

Determining and Providing the Appropriate CCSID for an API, External System, or Language

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Determining and Providing the Appropriate CCSID for an API, External System, or Language

    ** This thread discusses the article: Determining and Providing the Appropriate CCSID for an API, External System, or Language **
    ** This thread discusses the Content article: Determining and Providing the Appropriate CCSID for an API, External System, or Language0

  • #2
    Reetermining and Providing the Appropriate CCSID for an API, External System, or Language

    ** This thread discusses the article: Determining and Providing the Appropriate CCSID for an API, External System, or Language **
    Hello Hans, Excellent Comments! I have never had any problems using this functionality because I always %trim() the results before using them, which would remove the EBCDIC spaces. But, you're absolutely correct, there are EBCDIC blanks in the output of this example. As I thought about this answer, I realized that converting an @ symbol from EBCDIC to ASCII would also result in a X'40'. And if this character were at the beginning or end of the conversion string, would be trimmed off of the converted characters. So, I made some modifications to resolve these issues: - In Converter_convert, Determine length using %len of varying, versus %trimr() which would trim off @ symbol during ASCII->EBCDIC conversion. - Previously relied on %trim() on results so I didn't care about the size of the output buffer, but now that I will be using the varying results I calculated the output buffer bytes converted by subtracting the bytes left in the output buffer from the total size. I couldn't just use the incoming size because mixed byte lengths are supported. After all of these changes have been made, here are the new results of EVAL asciiString:x 00084041 532F3430 30400000 Note that varying variables use the first two bytes to store the length of the variable. Excellent Comment, Thank You! Here is the new code:
    Code:
     D********************************************************************** D CCSID_EBCDIC C CONST(00037) D CCSID_ASCII C CONST(00367) D CCSID_ISO8859 C CONST(00819) D CCSID_UTF_8 C CONST(01208) D********************************************************************** Diconv_t DS D ICORV 1 4B 0 D ICOC 5 52B 0 DIM(00012) D********************************************************************** DQtqCode_t DS D QTQCCSID 1 4B 0 D QTQCA 5 8B 0 D QTQSA 9 12B 0 D QTQSA00 13 16B 0 D QTQLO 17 20B 0 D QTQMEO 21 24B 0 D QTQERVED02 25 32 D******************************************************************** D* Open the Conversion Descriptor D QtqIconvOpen PR ExtProc('QtqIconvOpen') D like(iconv_t) D argToCCSID like(QtqCode_t) const D argFromCCSID like(QtqCode_t) const D* Convert CCSID from Input Buffer to Output Buffer D Iconv PR ExtProc('iconv') D argConvDesc like(iconv_t) value D argInBuffer * D argInBytes 10I 0 D argOutBuffer * D argOutBytes 10I 0 D* Close the Conversion Descriptor D Iconv_close PR 10I 0 ExtProc('iconv_close') D argConvDesc like(iconv_t) VALUE D* Custom Procedure to simplify Iconv_open D Converter_open... D PR likeDs(iconv_t) D argToCCSID 10I 0 D argFromCCSID 10I 0 options(*nopass) D* Custom Procedure to simplify Iconv D Converter_convert... D PR 65535A varying D argCd likeDs(iconv_t) D argInString 65535A const varying D* Custom Procedure to simplify Iconv_close D Converter_close... D PR D argCd likeDs(iconv_t) D******************************************************************** D to DS likeDs(QtqCode_t) D from DS likeDs(QtqCode_t) D cd DS likeDs(iconv_t) D displayString S 52A varying D ebcdicString S 10A varying D asciiString S 10A varying D toCCSID S 10I 0 D********************************************************************** /free toCCSID = 1208; ebcdicString = '@AS/400@'; cd = Converter_open(toCCSID); asciiString = Converter_convert(cd: ebcdicString); Converter_close(cd); //---------------------------------------------------------- // Display the results //---------------------------------------------------------- displayString = 'EBCDIC: ' + ebcdicString; DSPLY displayString; displayString = 'ASCII: ' + asciiString; DSPLY displayString; *inLr = *ON; /end-free *----------------------------------------------------------------- * Converter_open: Opens the Conversion Descriptor for iconv *----------------------------------------------------------------- P Converter_open... P B export D Converter_open... D PI likeDs(iconv_t) D argToCCSID 10I 0 D argFromCCSID 10I 0 options(*nopass) D* Local Variables D from DS likeDs(QtqCode_t) D to DS likeDs(QtqCode_t) D cd DS likeDs(iconv_t) D******************************************************************** /free // Set the target CCSID to = *ALLx'00'; to.QTQCCSID = argToCCSID; to.QTQSA00 = 1; // If Specified, Set the From CCSID from = *ALLx'00'; if %PARMS < 2; from.QTQCCSID = 0; else; from.QTQCCSID = argFromCCSID; endif; from.QTQSA00 = 1; // If Specified, Set the From CCSID cd = QtqIconvOpen(to: from); if (cd.ICORV < *zeros); // FAILURE else; // SUCCESS endif; return cd; /end-free P E *----------------------------------------------------------------- * Converter_convert: Converts the CCSIDs of Conversion Descriptor *----------------------------------------------------------------- P Converter_convert... P B EXPORT D Converter_convert... D PI 65535A varying D argCd likeDs(iconv_t) D argInString 65535A const varying D******************************************************************** D inBuf S 65535A D inBufPtr S * D inBufBytes S 10I 0 D outBuf S 65535A D outBufPtr S * D outBufBytes S 10I 0 D bytesIn S 10I 0 D bytesOut S 10I 0 D outReturn S 65535A varying D******************************************************************** /free inBuf = argInString; inBufPtr = %addr(inBuf); // Set to Hex Zeros or will initialize to Ebcdic Spaces outBuf = *ALLx'00'; outBufPtr = %addr(outBuf); // Do not trimr, use Varying and %len() inBufBytes = %len(argInString); outBufBytes = %size(outBuf); bytesIn = outBufBytes; iconv(argCd: inBufPtr: inBufBytes: outBufPtr: outBufBytes); bytesOut = bytesIn - outBufBytes; outReturn = %subst(outBuf:1:bytesOut); return outReturn; /end-free P E *----------------------------------------------------------------- * Converter_close: Closes the Conversion Descriptor *----------------------------------------------------------------- P Converter_close... P B EXPORT D Converter_close... D PI D argCd likeDs(iconv_t) D******************************************************************** /free iconv_close(argCd); /end-free P E

    Comment


    • #3
      Reetermining and Providing the Appropriate CCSID for an API, External System, or Language

      ** This thread discusses the article: Determining and Providing the Appropriate CCSID for an API, External System, or Language **
      Could you be more specific with the performance issues? Perhaps I already took care of this concern with the varying return. I have made the parameters const varying 65535 because this is intended to be used as a generic service program function on character bytes and I wanted to open it up to the largest possible size with flexibility on the arguments. In our shop, converting between CCSIDs is usually not performed in large amounts of repetition. So, any performance issues are not noticed.

      Comment


      • #4
        Reetermining and Providing the Appropriate CCSID for an API, External System, or Language

        ** This thread discusses the article: Determining and Providing the Appropriate CCSID for an API, External System, or Language **
        T: Hmmm, with a bit more work, perhaps we can get your code ready for publication! First, regarding the performance issue, 65535A return values are a known performance hog. What happens internally is that 65535 bytes always get copied, twice in fact. And that happens whether or not VARYING is coded since the underlying W-Code doesn't directly recognize the VARYING type. Many RPG programmers avoid 65535A return values for this very reason. Second, to your revised code. Consider the fragment:
        Code:
         bytesIn = outBufBytes; iconv(argCd: inBufPtr: inBufBytes: outBufPtr: outBufBytes); bytesOut = bytesIn - outBufBytes; outReturn = %subst(outBuf:1:bytesOut); return outReturn;
        Does anything look strange about that to you? Look at the 1st and 3rd statements. Clearly, after the 1st assignment, bytesIn==outBufBytes. Therefore, in the 3rd statement, bytesOut should get assigned the value of 0, result in a return value of ''! But let's assume this procedure does what it advertises. Consider the call
        Code:
         A20 = Converter_convert(cd: A10);
        where A20 and A10 are 20 and 10 character variables respectively. Now then, you might expect A20 to contain a string of ascii characters. But it would still be padded with ebcdic blanks on the right, making the conversion a little less useful than you might hope for.

        Comment


        • #5
          Reetermining and Providing the Appropriate CCSID for an API, External System, or Language

          ** This thread discusses the article: Determining and Providing the Appropriate CCSID for an API, External System, or Language **
          The bytesIn variable contains the number of bytes left in the output buffer before iconv. This value is the total size of the output buffer on the way into iconv. When iconv is complete, the outBufBytes value will change to reflect the number of bytes left in the output buffer after some bytes were used to store the converted results. So, to determine the size of the converted output buffer results you would need to the number of bytes left going IN (all of them) and the number of bytes left coming OUT (total - converted). So, the relevant number of bytes converted that are coming out of iconv, which I call bytesOut, equals the total number of bytes going in minus the amount remaining. bytesOut = bytesIn - outBufBytes; Or written in English: bytesOut: Number of Converted Bytes Out of iconv bytesIn: Number of Total Bytes going into iconv outBufBytes: Number of Bytes left in output buffer after some bytes were consumed to contain the results of the conversion. The naming conventions associated with the buffers start with "inBufXxx" and "outBufXxx". The generic "byteXxx" references are pertaining to the relevant bytes of the results. With the varying variable, you would no longer have padding.

          Comment


          • #6
            Reetermining and Providing the Appropriate CCSID for an API, External System, or Language

            ** This thread discusses the article: Determining and Providing the Appropriate CCSID for an API, External System, or Language **
            These examples are provided as educational code segments. It is actually common practice for generic service program arguments to be defined in a way to explore the limits and encourage flexibility. Simplicity is also another factor in providing code samples that target an objective in learning which would also be illustrated by the lack of exception handling to keep the sample code as minimal as possible to focus on the objective. I am unsure if you have ever read the ILE RPG Programmer's Guide provided by IBM. But, there are several such examples provided in that publication that use these parameter definitions and I was extremely happy to actually see that there is an example of a procedure in the programmer's guide that performs a less flexible version of this tip with a procedure called "cvtToAscii" using the QDCXLATE API with the exact same parameters as defined in this code sample. So, I would think that if IBM was demonstrating code functionality with the same exact definitions, then it should be an adequate solution. But, there is always the balance of simplicity, performance and flexibility. So, depending upon the situation there could be different solutions.

            Comment

            Working...
            X