Is z/OS ASCII or EBCDIC? Yes! – Making Developers Lives Better

Is z/OS ASCII or EBCDIC? Yes! – Making Developers Lives Better

Foto oleh Penulis

TL;DR : pergi ke ringkasan di akhir posting.

Salah satu kelebihan z/OS adalah mendukung aplikasi tradisional dan modern, bahasa pemrograman, dan bahkan data secara bersamaan. Saya dapat membuat kode dalam assembler, C, COBOL, Java, Python, Node.js atau Golang di z/OS. Dengan kekuatan ini muncul beberapa kerumitan, terutama seputar cara file Anda dikodekan.

Ada banyak cara untuk mengkodekan data. Untuk diskusi ini, saya akan mengesampingkan pengkodean multi-byte seperti DBCS dan Unicode dan fokus pada pengkodean byte tunggal. Ada banyak cara berbeda untuk menyandikan file, tetapi dua kategori pengkodean besar adalah penyandian ASCII dan penyandian EBCDIC, di mana karakter sesuai dengan satu byte, dan satu byte adalah 8 bit. Jika Anda bekerja secara eksklusif di Windows, Linux, atau Mac, Anda mungkin akrab dengan ASCII. Di sisi lain, jika Anda bekerja secara eksklusif dengan IBM i atau z/OS, Anda mungkin akrab dengan EBCDIC.

Tetapi banyak hal telah berubah pada z/OS. Banyak aplikasi bekerja di ASCII. Data input atau output mungkin dalam ASCII, baik karena aplikasi mengharapkannya, atau karena data tersebut berasal dari sistem lain. Aplikasi yang awalnya dikembangkan pada sistem ASCII mungkin memiliki dependensi tersembunyi pada ASCII. Contoh umum ketergantungan ASCII tersembunyi mengharapkan semua huruf dari A hingga Z berdekatan, sehingga Anda dapat menulis:

if (x >= ‘A’ && x <= 'Z') { /* x harus huruf besar alfabet */ }

Sayangnya, jika x dikodekan sebagai EBCDIC, kode sebelumnya salah. Demikian pula, asumsi bahwa a sampai z bersebelahan adalah salah. Mungkin yang lebih buruk adalah 0 hingga 9 bersebelahan di ASCII dan EBCDIC, memberikan harapan yang salah ?.

Selamat datang di dunia Bimodal z/OS

z/OS mengaktifkan kode C untuk bekerja di ASCII atau EBCDIC sejak lama, tetapi dengan munculnya bahasa seperti Python, Golang, dan Node.js yang secara inheren bekerja di dunia UTF-8, di mana ASCII 7-bit sesuai 1 ke 1 dengan UTF-8, pengembang harus memiliki z/OS yang berfungsi. Dengan beberapa opsi yang dipikirkan dengan matang, Lingkungan Bahasa z/OS, sistem file, dan kompiler C menarik dukungan untuk ASCII 7-bit, dan juga untuk UTF-8 secara umum (tapi itu untuk posting lain).

Mari kita kembangkan contoh sebelumnya menjadi program C runnable yang kita kompilasi menjadi prc (untuk karakter cetak):

int main() { int c = getchar(); if (c >= ‘A’ && c <= 'Z') { printf("%c adalah huruf besar dalam A sampai Zn", c); } else { printf("0x%X bukan huruf besar dari A sampai Zn", c); } kembalikan 0; }

Tanpa opsi khusus, file sumber akan menjadi EBCDIC dan prc akan dijalankan sebagai program EBCDIC. Berlari:

echo “A”https://makingdeveloperslivesbetter.wordpress.com/2022/01/07/is-z-os-ascii-or-ebcdic-yes/” ./prc

cetakan:

Huruf A adalah huruf besar dalam A sampai Z echo “}”https://makingdeveloperslivesbetter.wordpress.com/2022/01/07/is-z-os-ascii-or-ebcdic-yes/” ./prc

cetakan:

Huruf } adalah huruf besar di A sampai Z

ups…

Cara portabel untuk menulis kode C adalah dengan menggunakan isupper() dan metode lain untuk mengklasifikasikan karakter, tetapi keduanya juga peka terhadap lokal, yang mungkin bukan yang Anda inginkan. Singkatnya, ini sedikit berantakan. Belum lagi bahwa kode ini mungkin pihak ke-3 dan banyak pekerjaan untuk menemukan semua metode pengkodean dugaan ASCII ini, yang mungkin tidak sejelas contoh di atas.

Jadi – bagaimana kita bisa membuat kode ini bekerja seperti pada sistem berbasis ASCII? Pertama, kita harus mengkodekan file sumber sebagai ASCII dan kemudian menandainya. Jika Anda menggunakan git sebagai SCM Anda, maka file tersebut akan berada dalam format UTF-8, yang dalam hal ini setara dengan ASCII (ISO8859-1). Jika file sudah dalam EBCDIC pada z/OS, Anda dapat mengonversinya ke ASCII (ISO8859-1). Untuk mengonversi file dari satu penyandian ke penyandian lainnya, gunakan iconv, yang ditunjukkan pada contoh berikut, yang mengasumsikan kode sumber ada di halaman kode 1047. Jika Anda tinggal di luar Amerika Utara, Anda mungkin menggunakan halaman kode yang berbeda. Jika Anda berada di Amerika Utara dan menulis kode C, saya akan mendorong Anda untuk menggunakan halaman kode IBM-1047 dan bukan halaman kode 37.

iconv -f IBM-1047 -t ISO8859-1 prcascii.c

Setelah file berada di ASCII, Anda harus menandainya. Jika memungkinkan, beri tag file teks Anda di z/OS sebagai ISO8859-1 atau IBM-1047. Inilah cara Anda menandai file sebagai ASCII:

chtag -t -c ISO8859-1 prcascii.c

Dan inilah cara Anda menandai file sebagai EBCDIC (Amerika Utara):

chtag -t -c IBM-1047 prc.c

Kompiler C mengharapkan kode sumber berada dalam EBCDIC, bahkan ketika opsi –qascii ditentukan. Kita perlu memberi tahu Lingkungan Bahasa untuk secara otomatis mengonversi file yang ditandai sebagai ASCII saat dibaca ke dalam aplikasi yang mengharapkan EBCDIC. Ini dicapai dengan menentukan:

ekspor _BPXK_AUTOCVT=”ON”

Dengan kode sumber yang ditandai dengan benar, kita sekarang dapat mengkompilasi kode. Kompiler perlu memproses kode sebagai ASCII, dan untuk itu kami menggunakan opsi -qascii. Namun, kode sebelumnya memiliki masalah lain: fungsinya tidak dibuat prototipe, karena header sistem tidak disertakan. Di dunia khusus EBCDIC, ini akan menjadi praktik yang buruk. Di dunia bimodal kami, ini menghasilkan kesalahan karena kompiler akan memperlakukan karakter dan string literal sebagai ASCII, tetapi akan menghasilkan kode untuk memanggil fungsi yang mengharapkan data EBCDIC.

Jika Anda mengkompilasi dan menjalankan program tanpa menyertakan file header, Anda akan mendapatkan hasil yang aneh ini:

echo “A”https://makingdeveloperslivesbetter.wordpress.com/2022/01/07/is-z-os-ascii-or-ebcdic-yes/” ./prc 0x%X bukan huruf besar dalam A ke Z

Apa yang terjadi dengan el dalam surat? Jawabannya adalah bahwa titik kode untuk ASCII l adalah 0x6C. Itu kebetulan EBCDIC%. Fungsi printf EBCDIC dipanggil dengan teks ASCII dan oleh karena itu diproses sebagai EBCDIC. Sebagian besar karakter tidak ditafsirkan dengan cara khusus apa pun, tetapi 0x6C diproses sebagai %, yang mengharapkan karakter berikutnya untuk melengkapi penentu format yang valid. Karena karakter berikutnya tidak melengkapi penentu format yang valid, % dibuang. Setelah fungsi printf memproses karakter, konversi otomatis dilakukan, mengubah aliran ASCII ke EBCDIC (dikurangi l). Misteri terpecahkan.

Singkatnya, pastikan Anda menyertakan file header sistem untuk fungsi sistem yang Anda panggil, terutama saat Anda mengompilasi dengan -qascii.

Kompiler C dan Lingkungan Bahasa bekerja sama untuk memproses aplikasi ASCII. Ketika Anda mengkompilasi dengan opsi –qascii, kompilator mendefinisikan __CHARSET_LIB menjadi 1. File header memetakan panggilan fungsi untuk panggilan fungsi ASCII dan EBCDIC.

Khususnya, untuk printf, di Anda akan melihat:

#ifndef __ASCII #define __ASCII 1 #endif … #if didefinisikan(__XPLINK__) && __CHARSET_LIB == __ASCII #define __NATIVE_ASCII_F #endif

dan di Anda akan melihat:

#ifdef __NATIVE_ASCII_F #pragma map (printf, “174174A00118”)

Setelah memasukkan , kami mengkompilasi ulang dengan –qascii dan menjalankan lagi, dan sayangnya, itu masih tidak berhasil!

echo “A”https://makingdeveloperslivesbetter.wordpress.com/2022/01/07/is-z-os-ascii-or-ebcdic-yes/” ./prc 0xC1 bukan huruf besar dalam A sampai Z

Mencari 0xC1 di halaman kode EBCDIC, kita melihat bahwa EBCDIC A sedang diteruskan ke program. Apa yang sebenarnya kita inginkan adalah sebuah ASCII A untuk dilewatkan. Masalahnya adalah bahwa program echo adalah program EBCDIC dan karenanya mengirimkan data EBCDIC yang tidak ditandai melalui pipa. Kita perlu menginstruksikan Language Environment untuk menandai data sehingga konversi data akan dilakukan. Ingat, konversi data diaktifkan dengan variabel lingkungan _BPX_AUTOCVT=ON. Untuk menandai pipa, kami menentukan:

ekspor _TAG_REDIR_OUT=txt

dan kami sekarang mendapatkan hasil yang kami harapkan:

echo “A”https://makingdeveloperslivesbetter.wordpress.com/2022/01/07/is-z-os-ascii-or-ebcdic-yes/” ./prc A adalah huruf besar dalam A sampai Z

dan juga:

echo “}”https://makingdeveloperslivesbetter.wordpress.com/2022/01/07/is-z-os-ascii-or-ebcdic-yes/” ./prc 0x7D bukan huruf besar dalam A sampai Z

Luar biasa! Anda juga ingin menandai pipa stderr dan stdin:

ekspor _TAG_REDIR_ERR=txt ekspor _TAG_REDIR_IN=txt

Sejauh ini kita telah membahas cara menandai kode sumber dan mengkompilasi kode. Kami juga telah membahas cara memastikan bahwa aliran input dan output beroperasi dengan benar dengan program lain yang mungkin berupa ASCII atau EBCDIC, seperti echo. Bagaimana dengan aplikasi itu sendiri yang membaca dan menulis ke file teks? Mari kita sedikit memodifikasi program untuk menulis output ke file alih-alih stdout:

#include int main() { FILE* ofp = fopen(“/tmp/prc.out”, “w”); int c = getchar(); if (c >= ‘A’ && c <= 'Z') { fprintf(ofp, "%c adalah huruf besar dalam A sampai Zn", c); } else { fprintf(ofp, "0x%X bukan huruf besar di A sampai Zn", c); } kembalikan 0; }

Ketika kami menjalankan ini, itu berfungsi, tetapi tidak melakukan apa yang kami inginkan. Ini menghasilkan file teks ASCII, tetapi file teks ASCII itu tidak diberi tag. Jauh di awal artikel ini saya menyebutkan bahwa file teks yang tidak ditandai bukanlah hal yang baik. File teks yang tidak ditandai menyebabkan kesedihan karena alat lain tidak akan tahu bagaimana file tersebut dikodekan. Untungnya, ada variabel lingkungan yang memberi tahu Lingkungan Bahasa untuk mengonversi otomatis dan memberi tag otomatis pada file untuk Anda.

ekspor _CEE_RUNOPTS=”FILETAG(AUTOCVT,AUTOTAG)”

Hapus file /tmp/prc.out lalu jalankan kembali program, lalu print tag file tersebut:

chtag -p /tmp/prc.out

File ditandai dengan benar sebagai ISO8859-1 (ASCII). Bonus bagus: program vi dapat mengedit file teks dengan baik, meskipun dalam ASCII, karena diberi tag dengan benar.

Ringkasan

Untuk membangun aplikasi ASCII C:

Pastikan kode sumber Anda dikodekan dengan benar dan diberi tag sebagai ASCII menggunakan iconv dan chtag. Siapkan variabel lingkungan Anda sebagai berikut:export _BPXK_AUTOCVT=”ON” export _CEE_RUNOPTS=”FILETAG(AUTOCVT,AUTOTAG)” export _TAG_REDIR_ERR=”txt” export _TAG_REDIR_IN= “txt” export _TAG_REDIR_OUT=”txt” Pastikan Anda telah menyertakan header sistem untuk semua fungsi sistemKompilasi kode Anda dengan -qascii

Seperti ini:

Seperti Memuat…

Author: Douglas Hernandez