Edit

thodg/libiconv/src/zos-tag.h

Branch :

  • Show log

    Commit

  • Author : Mike Fulton
    Date : 2023-05-12 22:41:08
    Hash : 153d4079
    Message : On z/OS, set a charset tag on iconv's output file. For the concept of charset tags as external metadata on z/OS files, see <https://lists.gnu.org/archive/html/bug-gnu-libiconv/2023-04/msg00021.html>. * src/zos-tag.h: New file. * src/iconv.c: Include zos-tag.h. (convert): Add a 'tocode' parameter. On z/OS, turn off auto-conversion and tag the output file. (main): Update callers. * tests/check-ebcdic: On z/OS, make all test files initially untagged. * tests/check-tag: New file. * tests/Makefile.in (check): Pass the host_os to check-ebcdic. Invoke check-tag.

  • src/zos-tag.h
  • /* Copyright (C) 2023 Free Software Foundation, Inc.
       This file is part of the GNU LIBICONV Library.
    
       This program is free software: you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation; either version 3 of the License, or
       (at your option) any later version.
    
       This program is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.
    
       You should have received a copy of the GNU General Public License
       along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
    
    /* Written by Mike Fulton.  */
    
    #ifndef __ZOS_TAG__
    #define __ZOS_TAG__ 1
    
    #include <_Ccsid.h>
    
    #ifdef __MVS__
    /* See: https://www.ibm.com/docs/en/zos/latest?topic=lf-toccsid-convert-codeset-name-coded-character-set-id */
    
    static void chgpfx (char* encoding, size_t enclen, size_t pfxlen, const char* normpfx, size_t normpfxlen)
    {
      /* assertion: enclen >= pfxlen >= normpfxlen */
      if (normpfxlen > 0) {
        memcpy(encoding, normpfx, normpfxlen);
      }
      memcpy(&encoding[normpfxlen], &encoding[pfxlen], enclen-pfxlen+1);
    }
    
    static __ccsid_t map_encoding_to_ccsid (const char* encoding)
    {
      size_t enclen = strlen(encoding);
      char* updtenc = (char*) xmalloc(enclen+1);
      memcpy(updtenc, encoding, enclen+1);
    
      /*
       * Some strings are known to gnu iconv but not z/OS __toCcsid.
       * Examples are ISO-8859-1, ISO_8859-2, CP819 (which map to ISO8859-1, ISO8859-2, 819)
       *
       * The following are supported encodings and corresponding output CCSIDs
       *
       * CCSID Encoding
       * 819  ISO8859-1
       * 912  ISO8859-2
       * 914  ISO8859-4
       * 915  ISO8859-5
       * 1089 ISO8859-6
       * 813  ISO8859-7
       * 916  ISO8859-8
       * 920  ISO8859-9
       * 921  ISO8859-13
       * 923  ISO8859-15
       */
      #define ISO8859      "ISO8859"
      #define ISO8859_LEN (sizeof(ISO8859)-1)
      #define ISO8859_DASH "ISO-8859"
      #define ISO8859_DASH_LEN (sizeof(ISO8859_DASH)-1)
      #define ISO8859_UL "ISO_8859"
      #define ISO8859_UL_LEN (sizeof(ISO8859_UL)-1)
      #define CP "CP"
      #define CP_LEN (sizeof(CP)-1)
      #define NO_PFX ""
      #define NO_PFX_LEN (0)
    
      if (enclen > ISO8859_DASH_LEN && !memcmp(ISO8859_DASH, encoding, ISO8859_DASH_LEN)) {
        chgpfx(updtenc, enclen, ISO8859_DASH_LEN, ISO8859, ISO8859_LEN);
      } else if (enclen > ISO8859_UL_LEN && !memcmp(ISO8859_UL, encoding, ISO8859_UL_LEN)) {
        chgpfx(updtenc, enclen, ISO8859_UL_LEN, ISO8859, ISO8859_LEN);
      } else if (enclen > CP_LEN && !memcmp(CP, encoding, CP_LEN)) {
        chgpfx(updtenc, enclen, CP_LEN, NO_PFX, NO_PFX_LEN);
      }
      return __toCcsid(updtenc);
    }
    
    static int tagfile(int filedes, const char* tocode)
    {
      int status = 0;
    
      __ccsid_t newccsid = map_encoding_to_ccsid(tocode);
      if (newccsid) {
        attrib_t attr = {0};
        attr.att_filetagchg = 1;
        attr.att_filetag.ft_ccsid = newccsid;
        attr.att_filetag.ft_txtflag = 1;
        status = __fchattr(filedes, &attr, sizeof(attr));
      }
      return status;
    }
    #endif
    #endif