{ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
{ * * * J A P A N E S E   C O D E   C O N V E R S I O N   P R O G R A M * * * }
{ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }

{ This program was written by Ken R. Lunde, University of Wisconsin - Madison }

{ E-Mail: klunde@vms.macc.wisc.edu }

{ January 3, 1990 }

{ This program converts 7-bit Japanese (NEW-JIS, OLD-JIS, or NEC CODE) to 8- }
{ bit Japanese (SHIFT-JIS or EUC) and vice-versa.  The 7-bit and 8-bit codes }
{ generated by this program are machine independent, so its applications are }
{ unlimited. The user can use the menus to select the file name for both the }
{ input file and output file. Conversion from one 7-bit format to another 7- }
{ bit format is possible,  as is conversion from one 8-bit format to another }
{ 8-bit format. }

{ This program has been written to run on the VMS environment, and it should }
{ be compiled using Vax Pascal. }

program Japanese_Code_Converter (input,output,infile,outfile);

const
  NEW_KI = '$B';     { ASCII portion of NEW-JIS Kanji-In escape sequence }
  NEW_KO = '(J';     { ASCII portion of NEW-JIS Kanji-Out escape sequence }
  OLD_KI = '$@';     { ASCII portion of OLD-JIS Kanji-In escape sequence }
  OLD_KO = '(J';     { ASCII portion of OLD-JIS Kanji-Out escape sequence }
  NEC_KI = 'K';      { ASCII portion of NEC-CODE Kanji-In escape sequence }
  NEC_KO = 'H';      { ASCII portion of NEC-CODE Kanji-Out escape sequence }
  NUL = chr(0);      { nul character }
  LF = chr(10);      { line feed character }
  FF = chr(12);      { form feed character }
  CR = chr(13);      { carriage return character }
  ESC = chr(27);     { escape character }
  MAX_COLUMN = 78;   { maximum number of columns per line }
  MAX_FILE_LEN = 80; { maximum length of file name }

type
  filenametype = packed array [1..MAX_FILE_LEN] of char;
  two_char = packed array[1..2] of char;         { an array of 2 characters }
  code_type = (new,old,nec);                     { the 3 7-bit KANJI codes }
  kanji_code = record                            { record for esc sequences } 
    case code : code_type of                     { variant record }
      new,old : (ki,ko : two_char);
      nec : (kiS,koS : char);
  end; { record }

var
  infile,outfile : text;
  InfileName,OutfileName : filenametype;
  k_code : kanji_code;      { ASCII portion of escape sequence }
  ch1,ch2 : char;           { variables to hold characters }
  shifted_in : boolean;     { variable to indicate a KANJI string }
  select : integer;         { variable to indicate conversion type }

{ This procedure prints the version number and author's name and address }

procedure Introduction;

begin
  writeln('Japanese Code Converter version 1.0 (January 3, 1990)');
  writeln;
end; { procedure }

{ This procedure allows the user to select whether to convert a 7-bit file to }
{ an 8-bit file or vice-versa. }

procedure Select_Code_Type (var select : integer);

var
  choice : char;                                 { variable to hold choice }

begin
  writeln('Convert SHIFT-JIS Japanese file to 7-bit format     -> "1"');
  writeln('Convert SHIFT-JIS Japanese file to EUC format       -> "2"');
  writeln;
  writeln('Convert EUC Japanese file to 7-bit format           -> "3"');
  writeln('Convert EUC Japanese file to SHIFT-JIS format       -> "4"');
  writeln;
  writeln('Convert 7-bit Japanese file to SHIFT-JIS format     -> "5"');
  writeln('Convert 7-bit Japanese file to EUC format           -> "6"');
  writeln('Convert 7-bit Japanese file to another 7-bit format -> "7"');
  writeln;
  write('MAKE YOUR SELECTION -> ');              { write the prompt }
  readln(choice);                                { read input }
  writeln;
  if choice in ['1'..'7'] then                   { if choice is valid }
    begin
      case choice of
        '1' : select := 1;
        '2' : select := 2;
        '3' : select := 3;
        '4' : select := 4;
        '5' : select := 5;
        '6' : select := 6;
        '7' : select := 7;
      end; { case statement }
      writeln;
    end { if statement }
  else                                           { if choice is not valid }
    begin
      writeln('ILLEGAL CHOICE!');                { write warning message }
      writeln;
      Select_Code_Type(select);                  { recall procedure }
    end; { else statement }
end; { procedure }

{ This procedure sets the file names of the infile and outfile. }

procedure Set_Files (var InfileName,OutfileName : filenametype);

begin
  write('Infile name  -> ');
  readln(InfileName);
  writeln;
  write('Outfile name -> ');
  if eoln then                                   { if carriage return }
    begin
      readln;
      OutfileName := InfileName;                 { outfile equals infile }
    end { if statement }
  else                                           { else if there is input }
    readln(OutfileName);
  writeln;
  writeln;
end; { procedure }

{ This procedure skips the printable ASCII portion of an escape sequence. It }
{ can handle the three standard codes, NEW-JIS, OLD-JIS, and NEC CODE. }

procedure Skip_ESC_Seq (temp : char; var shifted_in : boolean);

var
  junk : char;                                   { character variable }

begin
  if (temp = '$') or (temp = '(') then           { if "$" or "(" }
    read(infile,junk);                           { read another character }
  if (temp = 'K') or (temp = '$') then           { if Kanji-In }
    shifted_in := true
  else                                           { else if Kanji-Out }
    shifted_in := false;
end; { procedure }

{ This procedure sets the KANJI code to be used throughout the program, and }
{ makes use of variant field records. }

procedure Set_KANJI_Code (var k_code : kanji_code);

var
  value : char;                                  { variable for choice }

begin
  writeln('* * * * * * * * Please Select 7-bit Japanese Code * * * * * * * *');
  writeln;
  writeln('NEW-JIS  (KI = "<ESC>',NEW_KI,'"/KO = "<ESC>',NEW_KO,'") -> "1"');
  writeln('OLD-JIS  (KI = "<ESC>',OLD_KI,'"/KO = "<ESC>',OLD_KO,'") -> "2"');
  writeln('NEC CODE (KI = "<ESC>',NEC_KI,'"/KO = "<ESC>',NEC_KO,'")   -> "3"');
  writeln;
  write('MAKE YOUR SELECTION -> ');              { ask for input }
  readln(value);                                 { read input }
  writeln;
  writeln;
  if not (value in ['1'..'3']) then              { if choice is not valid }
    begin
      writeln('ILLEGAL CHOICE!');                { write a warning message }
      writeln;
      Set_KANJI_Code(k_code);                    { call procedure again }
    end { if statement }
  else                                           { else if choice is valid }
    begin
      case value of                              { set code type }
        '1' : k_code.code := new;
        '2' : k_code.code := old;
        '3' : k_code.code := nec;
      end; { case statement }
      case k_code.code of                        { set ki and ko codes }
        new : begin
                k_code.ki := NEW_KI;
                k_code.ko := NEW_KO;
                writeln('7-bit Japanese code is set at NEW-JIS');
              end; { case statement }
        old : begin
                k_code.ki := OLD_KI;
                k_code.ko := OLD_KO;
                writeln('7-bit Japanese code is set at OLD-JIS');
              end; { case statement }
        nec : begin
                k_code.kiS := NEC_KI;
                k_code.koS := NEC_KO;
                writeln('7-bit Japanese code is set at NEC CODE');
              end; { case statement }
      end; { case statement }
    end; { else statement }
  writeln;
end; { procedure }

{ This procedure writes a Kanji-In escape sequence. }

procedure KANJI_In (k_code : kanji_code);

begin
  case k_code.code of
    new : write(outfile,ESC,k_code.ki);
    old : write(outfile,ESC,k_code.ki);
    nec : write(outfile,ESC,k_code.kiS);
  end; { case statement }
end; { procedure }

{ This procedure writes a Kanji-Out escape sequence. }

procedure KANJI_Out (k_code : kanji_code);

begin
  case k_code.code of
    new : write(outfile,ESC,k_code.ko);
    old : write(outfile,ESC,k_code.ko);
    nec : write(outfile,ESC,k_code.koS);
  end; { case statement }
end; { procedure }

{ This procedure uses the standard algorithm for converting 8-bit code to 7- }
{ bit code. Once converted, the characters are returned. }

procedure Eight_2_Seven (var ch1,ch2 : char);

var
  temp2 : char;                                  { temporary variable }

begin
  temp2 := ch2;                                  { set temp2 equal to ch2 }
  if ord(ch2) in [64..158] then
    ch2 := chr(ord(ch2) - 31)
  else if ord(ch2) in [159..252] then
    ch2 := chr(ord(ch2) - 126);
  if (ord(temp2) > 127) and (ord(temp2) <= 158) then
    ch2 := chr(ord(ch2) - 1);
  if (ord(ch1) in [129..159]) and (ord(temp2) in [64..158]) then
    ch1 := chr(((ord(ch1) - 113) * 2) + 1)
  else if (ord(ch1) in [129..159]) and (ord(temp2) in [159..252]) then
    ch1 := chr((ord(ch1) - 112) * 2)
  else if (ord(ch1) in [224..239]) and (ord(temp2) in [64..158]) then
    ch1 := chr(((ord(ch1) - 177) * 2) + 1)
  else if (ord(ch1) in [224..239]) and (ord(temp2) in [159..252]) then
    ch1 := chr((ord(ch1) - 176) * 2);
end; { procedure }

{ This procedure uses the standard algorithm for converting 7-bit code to 8- }
{ bit code. Once converted, the characters are returned. }

procedure Seven_2_Eight (var ch1,ch2 : char);

begin
  if odd(ord(ch1)) then
    ch2 := chr(ord(ch2) + 31)
  else
    ch2 := chr(ord(ch2) + 126);
  if (ord(ch2) >= 127) and (ord(ch2) < 158) then
    ch2 := chr(ord(ch2) + 1);
  if (ord(ch1) in [33..93]) and odd(ord(ch1)) then
    ch1 := chr(((ord(ch1) - 1) div 2) + 113)
  else if (ord(ch1) in [34..94]) and not (odd(ord(ch1))) then
    ch1 := chr((ord(ch1) div 2) + 112)
  else if (ord(ch1) in [95..125]) and odd(ord(ch1)) then
    ch1 := chr(((ord(ch1) - 1) div 2) + 177)
  else if (ord(ch1) in [96..126]) and not (odd(ord(ch1))) then
    ch1 := chr((ord(ch1) div 2) + 176);
end; { procedure }

{ This procedure converts the Japanese portion of a SHIFT-JIS Japanese file }
{ to a 7-bit format. }

procedure SHIFT_to_Seven (ch1,ch2 : char; shifted_in : boolean;
                          k_code : kanji_code);

var
  column : integer;                              { column counter }
  done : boolean;                                { boolean variable to finish }

begin
  done := false;                                 { not done }
  column := 0;                                   { column initially at zero }
  Set_KANJI_Code(k_code);                        { set the Kanji code }
  while not eof(infile) do                       { while file has data }
    begin
      while (not eoln(infile)) and (not done) do { while line has data }
        begin
          read(infile,ch1);                      { read a character into ch1 }
          if eof(infile) then                    { if end-of-file }
            done := true;                        { done }
          if ord(ch1) >= 129 then                { if SHIFT-JIS }
            begin
              if not shifted_in then             { if not shifted }
                begin
                  KANJI_In(k_code);              { write a Kanji-In }
                  shifted_in := true;            { shifted }
                end; { if statement }
              read(infile,ch2);                  { read a character into ch2 }
              if eof(infile) then                { if end-of-file }
                done := true;                    { done }
              Eight_2_Seven(ch1,ch2);            { convert ch1 and ch2 }
              write(outfile,ch1,ch2);            { write ch1 and ch2 }
              column := column + 2;              { increment column by 2 }
            end { if statement }
          else                                   { else if not SHIFT-JIS }
            begin
              if (ch1 <> NUL) and (ch1 <> LF) and (ch1 <> FF) then
                begin
                  if shifted_in then             { if shifted }
                    begin
                      shifted_in := false;       { not shifted }
                      KANJI_Out(k_code);         { write a Kanji-Out }
                    end; { if statement }
                  if ch1 = CR then               { if CR }
                    begin
                      writeln(outfile);          { go to next line of outfile }
                      column := 0;               { set column back to zero }
                    end { if statement }
                  else                           { else if not CR }
                    begin
                      write(outfile,ch1);        { write ch1 }
                      column := column + 1;      { increment column by 1 }
                    end; { else statement }
                end; { if statement }
            end; { else statement }
          if column >= MAX_COLUMN then           { if column at maximum }
            begin
              if shifted_in then                 { if shifted }
                begin
                  shifted_in := false;           { not shifted }
                  KANJI_Out(k_code);             { write a Kanji-Out }
                end; { if statement }
              writeln(outfile);                  { go to next line of outfile }
              if eoln(infile) then               { if end-of-line }
                readln(infile);                  { go to next line of infile }
              column := 0;                       { set column back to zero }
            end; { if statement }
        end; { inner while loop }
      if shifted_in then                         { if still shifted }
        begin
          shifted_in := false;                   { not shifted }
          KANJI_Out(k_code);                     { write a Kanji-Out }
        end; { if statement }
      if not done then                           { if not done }
        begin
          writeln(outfile);                      { go to next line of outfile }
          readln(infile);                        { go to next line of infile }
          column := 0;                           { set column back to zero }
        end; { if statement }
    end; { outer while loop }
  if not done then                               { if not done }
    if shifted_in then                           { if still shifted }
      KANJI_Out(k_code);                         { write a Kanji-Out }
end; { procedure }

{ This procedure converts the Japanese portion of a SHIFT-JIS Japanese file }
{ to a EUC format. }

procedure SHIFT_to_EUC (ch1,ch2 : char);

var
  column : integer;                              { column counter }
  done : boolean;                                { boolean variable to finish }

begin
  done := false;                                 { not done }
  column := 0;                                   { column initially at zero }
  while not eof(infile) do                       { while file has data }
    begin
      while (not eoln(infile)) and (not done) do { while line has data }
        begin
          read(infile,ch1);                      { read a character into ch1 }
          if eof(infile) then                    { if end-of-file }
            done := true;                        { done }
          if ord(ch1) >= 129 then                { if SHIFT-JIS }
            begin
              read(infile,ch2);                  { read a character into ch2 }
              if eof(infile) then                { if end-of-file }
                done := true;                    { done }
              Eight_2_Seven(ch1,ch2);            { convert ch1 and ch2 }
              ch1 := chr(ord(ch1) + 128);        { convert ch1 to EUC }
              ch2 := chr(ord(ch2) + 128);        { convert ch2 to EUC }
              write(outfile,ch1,ch2);            { write ch1 and ch2 }
              column := column + 2;              { increment column by 2 }
            end { if statement }
          else                                   { else if not SHIFT-JIS }
            begin
              if (ch1 <> NUL) and (ch1 <> LF) and (ch1 <> FF) then
                if ch1 = CR then                 { if CR }
                  begin
                    writeln(outfile);            { go to next line of outfile }
                    column := 0;                 { set column back to zero }
                  end { if statement }
                else                             { else if not CR }
                  begin
                    write(outfile,ch1);          { write ch1 }
                    column := column + 1;        { increment column by 1 }
                  end; { else statement }
            end; { else statement }
          if column >= MAX_COLUMN then           { if column at maximum }
            begin
              writeln(outfile);                  { go to next line of outfile }
              if eoln(infile) then               { if end-of-line }
                readln(infile);                  { go to next line of infile }
              column := 0;                       { set column back to zero }
            end; { if statement }
        end; { inner while loop }
      if not done then                           { if not done }
        begin
          writeln(outfile);                      { go to next line of outfile }
          readln(infile);                        { go to next line of infile }
          column := 0;                           { set column back to zero }
        end; { if statement }
    end; { outer while loop }
end; { procedure }

{ This procedure converts the Japanese portion of an EUC Japanese file to a }
{ 7-bit format. }

procedure EUC_to_Seven (ch1,ch2 : char; shifted_in : boolean;
                        k_code : kanji_code);

begin
  Set_KANJI_Code(k_code);                        { set the Kanji code }
  while not eof(infile) do                       { while file has data }
    begin
      while not eoln(infile) do                  { while line has data }
        begin
          read(infile,ch1);                      { read a character into ch1 }
          if ord(ch1) in [161..254] then         { if EUC }
            begin
              read(infile,ch2);                  { read a character into ch2 }
              ch1 := chr(ord(ch1) - 128);        { convert ch1 to 7-bit }
              ch2 := chr(ord(ch2) - 128);        { convert ch2 to 7-bit }
              if not shifted_in then             { if not shifted }
                begin
                  shifted_in := true;            { shifted }
                  KANJI_In(k_code);              { write a Kanji-In }
                end; { if statement }
              write(outfile,ch1,ch2);            { write ch1 and ch2 }
            end { if statement }
          else                                   { else if not EUC }
            begin
              if (ch1 <> LF) and (ch1 <> FF) then
                begin
                  if shifted_in then             { if shifted }
                    begin
                      shifted_in := false;       { not shifted }
                      KANJI_Out(k_code);         { write a Kanji-Out }
                    end; { if statement }
                  write(outfile,ch1);            { write ch1 }
                end; { else statement }
            end; { else statement }
        end; { inner while loop }
      if shifted_in then                         { if still shifted }
        begin
          shifted_in := false;                   { not shifted }
          KANJI_Out(k_code);                     { write a Kanji-Out }
        end; { if statement }
      writeln(outfile);                          { go to next line of outfile }
      readln(infile);                            { go to next line of infile }
    end; { outer while loop }
  if shifted_in then                             { if still shifted }
    KANJI_Out(k_code);                           { write a Kanji-Out }
end; { procedure }

{ This procedure converts the Japanese portion of an EUC Japanese file to a }
{ SHIFT-JIS format. }

procedure EUC_to_SHIFT (ch1,ch2 : char);

begin
  while not eof(infile) do                       { while file has data }
    begin
      while not eoln(infile) do                  { while line has data }
        begin
          read(infile,ch1);                      { read a character into ch1 }
          if ord(ch1) in [161..254] then         { if EUC }
            begin
              read(infile,ch2);                  { read a character into ch2 }
              ch1 := chr(ord(ch1) - 128);        { convert ch1 to 7-bit }
              ch2 := chr(ord(ch2) - 128);        { convert ch2 to 7-bit }
              Seven_2_Eight(ch1,ch2);            { convert ch1 and ch2 }
              write(outfile,ch1,ch2);            { write ch1 and ch2 }
            end { if statement }
          else                                   { else if not EUC }
            if (ch1 <> LF) and (ch1 <> FF) then
              write(outfile,ch1);                { write ch1 }
        end; { inner while loop }
      writeln(outfile);                          { go to next line of outfile }
      readln(infile);                            { go to next line of infile }
    end; { outer while loop }
end; { procedure }

{ This procedure converts the Japanese portion of a 7-bit Japanese file to a }
{ SHIFT-JIS format. }

procedure Seven_to_SHIFT (ch1,ch2 : char; shifted_in : boolean);

var
  temp : char;                                   { temporary variable }

begin
  while not eof(infile) do                       { while file has data }
    begin
      while not eoln(infile) do                  { while line has data }
        begin
          read(infile,ch1);                      { read a character }
          if ch1 = ESC then                      { if <ESC> }
            begin
              if shifted_in then                 { if shifted }
                begin
                  read(infile,temp);             { read a character into temp }
                  Skip_ESC_Seq(temp,shifted_in); { skip escape sequence }
                end { if statement }
              else                               { else if not shifted }
                begin
                  read(infile,temp);             { read a character into temp }
                  Skip_ESC_Seq(temp,shifted_in); { skip escape sequence }
                end; { else statement }
            end { if statement }
          else                                   { else if not <ESC> }
            begin
              if shifted_in then                 { if shifted }
                begin
                  read(infile,ch2);              { read a character into ch2 }
                  Seven_2_Eight(ch1,ch2);        { convert ch1 and ch2 }
                  write(outfile,ch1,ch2);        { write ch1 and ch2 }
                end { if statement }
              else                               { else if not shifted }
                if (ch1 <> LF) and (ch1 <> FF) then
                  write(outfile,ch1);            { write ch1 unconverted }
            end; { else statment }
        end; { inner while loop }
      writeln(outfile);                          { go to next line of outfile }
      readln(infile);                            { go to next line of infile }
    end; { outer while loop }
end; { procedure }

{ This procedure converts the Japanese portion of a 7-bit Japanese file to a }
{ EUC format. }

procedure Seven_to_EUC (ch1,ch2 : char; shifted_in : boolean);

var
  temp : char;                                   { temporary variable }

begin
  while not eof(infile) do                       { while file has data }
    begin
      while not eoln(infile) do                  { while line has data }
        begin
          read(infile,ch1);                      { read a character into ch1 }
          if ch1 = ESC then                      { if <ESC> }
            begin
              read(infile,temp);                 { read a character into temp }
              Skip_ESC_Seq(temp,shifted_in);     { skip escape sequence }
            end { if statement }
          else                                   { else if not <ESC> }
            begin
              if shifted_in then                 { if shifted }
                begin
                  read(infile,ch2);              { read a character into ch2 }
                  ch1 := chr(ord(ch1) + 128);    { convert ch1 }
                  ch2 := chr(ord(ch2) + 128);    { convert ch2 }
                  write(outfile,ch1,ch2);        { write ch1 and ch2 }
                end { if statement }
              else                               { else if not shifted }
                if (ch1 <> LF) and (ch1 <> FF) then
                  write(outfile,ch1);            { write ch1 }
            end; { else statement }
        end; { inner while loop }
      if shifted_in then                         { if still shifted }
        shifted_in := false;                     { not shifted }
      writeln(outfile);                          { go to next line of outfile }
      readln(infile);                            { go to next line of infile }
    end; { outer while loop }
end; { procedure }

{ This procedure converts the Japanese portion of a 7-bit Japanese file to }
{ a different 7-bit code. }

procedure Seven_to_Seven (ch1,ch2 : char; shifted_in : boolean;
                          k_code : kanji_code);

var
  temp : char;                                   { temporary variable }

begin
  Set_KANJI_Code(k_code);                        { set the Kanji code }
  while not eof(infile) do                       { while file has data }
    begin
      while not eoln(infile) do                  { while line has data }
        begin
          read(infile,ch1);                      { read a character into ch1 }
          if ch1 = ESC then                      { if <ESC> }
            begin
              read(infile,temp);                 { read a character into temp }
              Skip_ESC_Seq(temp,shifted_in);     { skip escape sequence }
              if shifted_in then                 { if shifted }
                KANJI_In(k_code)                 { write a Kanji-In }
              else                               { else if not shifted }
                KANJI_Out(k_code);               { write a Kanji-Out }
            end { if statement }
          else                                   { else if not <ESC> }
            begin
              if shifted_in then                 { if shifted }
                begin
                  read(infile,ch2);              { read a character into ch2 }
                  write(outfile,ch1,ch2);        { write outfile,ch1 and ch2 }
                end { if statement }
              else                               { else if not shifted }
                begin
                  if (ch1 <> LF) and (ch1 <> FF) then
                    write(outfile,ch1);          { write ch1 }
                end; { else statement }
            end; { else statement }
        end; { inner while loop }
      if shifted_in then                         { if still shifted }
        begin
          shifted_in := false;                   { not shifted }
          KANJI_Out(k_code);                     { write a Kanji-Out }
        end; { if statement }
      writeln(outfile);                          { go to next line of outfile }
      readln(infile);                            { go to next line of infile }
    end; { outer while loop }
  if shifted_in then                             { if still shifted }
    KANJI_Out(k_code);                           { write a Kanji-Out }
end; { procedure }

begin { main }
  k_code.code := new;
  ch1 := ' ';
  ch2 := ' ';
  InfileName := 'incoming';
  OutfileName := 'outgoing';
  shifted_in := false;
  Introduction;
  Select_Code_Type(select);                      { select conversion type }
  Set_Files(InfileName,OutfileName);             { set file names }
  open(file_variable := infile, file_name := InfileName, history := old);
  open(file_variable := outfile, file_name := OutfileName, history := new);
  reset(infile);
  rewrite(outfile);
  case select of
    1 : SHIFT_to_Seven(ch1,ch2,shifted_in,k_code);
    2 : SHIFT_to_EUC(ch1,ch2);
    3 : EUC_to_Seven(ch1,ch2,shifted_in,k_code);
    4 : EUC_to_SHIFT(ch1,ch2);
    5 : Seven_to_SHIFT(ch1,ch2,shifted_in);
    6 : Seven_to_EUC(ch1,ch2,shifted_in);
    7 : Seven_to_Seven(ch1,ch2,shifted_in,k_code);
  end; { case statement }
  close(infile);
  close(outfile);
end.
