Skip to content

Instantly share code, notes, and snippets.

@kadler
Created March 1, 2017 04:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kadler/a29f81de28b0719bef63f8cead2e7c38 to your computer and use it in GitHub Desktop.
Save kadler/a29f81de28b0719bef63f8cead2e7c38 to your computer and use it in GitHub Desktop.
Converting PASE structures to RPG structures with padding and alignment using Python CFFI
#
# The MIT License (MIT)
#
# Copyright (c) 2017 IBM Corp.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
from cffi import FFI
import sys
# configurables:
#
# treat single chars as bytes (ints)
CHAR_MAP = 'INT'
STRUCT_DEFINITION = """
typedef struct {
char a;
short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
char c[13];
long long ll;
char j;
unsigned long long ull;
float f;
double d;
char* v;
} my_struct_t;
"""
STRUCT_NAME = 'my_struct_t'
# end configurables
mapping = {
'char': 'CHAR',
'unsigned char': 'CHAR',
'short': 'INT',
'unsigned short': 'UNS',
'int': 'INT',
'unsigned int': 'UNS',
'long': 'INT',
'unsigned long': 'UNS',
'long long': 'INT',
'unsigned long long': 'UNS',
'float': 'FLOAT',
'double': 'FLOAT',
}
IS_64BIT = sys.maxsize > 2**32
# For some goofy reason, AIX decided that for
# 64-bit code wchar_t would be 4-bytes and UTF-32
# while older 32-bit code uses 2-byte wchar_t. PASE
# of course follows suit. So there's no easy mapping
# between 64-bit wchar_t and RPG and gets treated as
# a "binary" char array. Another option is mapping it
# to an UNS(10)
# Note that the zh_TW locale does not use Unicode for
# the wchar_t encoding, but I don't think that locale is
# supported in PASE
# http://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.nlsgdrf/wide_char_data_rep.htm
if not IS_64BIT:
mapping['wchar_t'] = 'UCS-2'
INT_DIGIT_MAPPING = { 1: 3, 2: 5, 4: 10, 8: 20 }
class RpgType:
def __init__(self, type):
type_name = type.cname
self.base_type = type_name
self.rpg_type = None
self.elements = 0
self.comment_ = None
self.size = 0
self.kind = type.kind
if self.kind == 'pointer':
self.kind = 'primitive'
self.rpg_type = 'UNS'
self.base_type = 'long'
self.size = 8 if IS_64BIT else 4
self.comment_ = '%d-bit PASE %s' % (self.size*8, type_name)
elif self.kind == 'array':
if type.item.kind == 'array':
raise Exception('multidimension arrays not yet supported')
self.elements = type.length
self.base_type = type.item.cname
self.rpg_type = mapping.get(self.base_type)
if not self.rpg_type:
# For unmapped types, treat as "binary" char arrays
self.rpg_type = 'CHAR'
self.comment_ = type_name
self.size = 0
self.elements *= ffi.sizeof(self.base_type)
else:
# For unmapped types, treat as "binary" char arrays
self.rpg_type = mapping.get(type_name)
if not self.rpg_type:
self.rpg_type = 'CHAR'
self.comment_ = type_name
elif self.rpg_type == 'CHAR':
self.rpg_type = CHAR_MAP
self.size = self.size or ffi.sizeof(self.base_type)
if self.rpg_type == 'INT' or self.rpg_type == 'UNS':
# convert from bytes to digits
self.size = INT_DIGIT_MAPPING[self.size]
if self.rpg_type == 'CHAR' or self.rpg_type == 'UCS-2':
# treat char type "arrays" as special (no DIM)
self.size = self.elements or 1
self.elements = 0
def comment(self):
return self.comment_
def __str__(self):
s = ""
if self.kind == 'pointer':
s = "%s" % (self.rpg_type)
elif self.size:
s = "%s(%d)" % (self.rpg_type, self.size)
else:
s = "%s" % (self.rpg_type, )
if self.elements:
s += (' DIM(%s)' % str(self.elements))
return s
ffi = FFI()
ffi.cdef(STRUCT_DEFINITION)
my_type = ffi.typeof(STRUCT_NAME)
if my_type.kind == 'struct':
expected_offset = 0
pad_num = 1
print("DCL-DS %s;" %(my_type.cname, ))
for f in my_type.fields:
name, field = f
if expected_offset != field.offset:
print(" %s_pad%d CHAR(%d);" % (my_type.cname, pad_num, field.offset-expected_offset))
pad_num += 1
r = RpgType(field.type)
if r.comment():
print(" %s %s; // %s" % (name, str(r), r.comment()))
else:
print(" %s %s;" % (name, str(r)))
expected_offset = field.offset + ffi.sizeof(field.type)
print("END-DS;")
else:
name = "name"
r = RpgType(my_type)
if r.comment():
print("DCL-S %s %s; // %s" % (name, str(r), r.comment()))
else:
print("DCL-S %s %s;" % (name, str(r)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment