/*
    Keyboard.c, Copyright 1998 (c) by Lukas Ruf,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.

    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.

    For further information, please visit http://www.tik.ee.ethz.ch/~topsy

    This software is provided under the terms of the GNU General Public Licence.

    A full copy of the GNU GPL is provided in the file COPYING found in the 
    development root of Topsy.
*/
/*
        This copyright notice supercedes all originally or previously used 
        copyrights being used within the source code.
        
        Author: Lukas Ruf <lr@lpr.ch>
*/

// ************************************************************************** //
// Copyrights (c) 1998 Lukas Ruf                                              //
// ************************************************************************** //
// Keyboard: Creating of KeyTable.S                                           //
//           Read ASCII Text File with structure as defined in Keyboard.dok   //
//           Create a KeyTable.S File for translation (KeyTrlTbl)             //
//           The Compiled File represents a data block in .data section       //
//           Position in this block equals to the KEYCODE.                    //
//           The ASCII Character (8b) is located at this position             //
//           COMMENTS in the Input file: ';' on first position of line !!     //
//           Special ASCII Character:                                         //
//              0x00 : No Output to Keybuffer                                 //
//              0xFF : Send Associated Message (16b) located in KeyMsgTbl     //
// ************************************************************************** //

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "TextRead.hpp"


#define KEYTABLEFILE "KeyTable.S"

void Hello() {
  printf("\nKeyboard: (c) by Lukas Ruf, lr@lpr.ch\n");
  //printf("Program call: \n Keyboard <KeyboardLayoutFile> [Prefix] [TruncateFlag]\n");
  return;
}

FILE *CreateKeyTable() {
  FILE *lf  = fopen(KEYTABLEFILE,"w");
  char *H1  = "/* KeyTable.S : Keycode to ASCII Character Table     */\n",
       *H2  = "/* THIS FILE IS AUTOMATICALLY CREATED BY KEYBOARD    */\n",
       *H3  = "/* KEYBOARD (c) 1998 Lukas Ruf, lr@lpr.ch            */\n",
       *H4  = ".data\n.align 4,0x9090\n\n";
  if (lf) {
    fwrite((void *)H1,1,strlen(H1),lf);
    fwrite((void *)H2,1,strlen(H2),lf);
    fwrite((void *)H3,1,strlen(H3),lf);
    fwrite((void *)H4,1,strlen(H4),lf);
  }
  return lf;
}

void CloseKeyTable(FILE *pf) {
  char *H1 = "/* End of KeyTable.S : Created for Topsy386 */\n";
  if (pf) {
    fwrite((void *)H1,1,strlen(H1),pf);
    fclose(pf);
  }
  return;
}

int GetKeyCode(unsigned char *pkey) {
//  printf("Processing %s",pkey);
  int xret  = -1;
  if (!pkey || !*pkey) return xret; 
  int i     = 0;
  bool ldec = true;
  while (pkey[i]) {   // is KEYCODE a decimal number ?
    if (!(pkey[i] >= '0' && pkey[i] <= '9')) ldec = false;
    i++;
  }
  if (ldec) xret = atoi((const char*)pkey); // literals are not handled yet (TIME)
  else {                        // like ENTER, A, UP, etc.
  }
  return xret;
}

unsigned char GetASCIICode(unsigned char *pasc) {
//  printf(" -- ASCII Code %s \n",pasc);
  unsigned char xret = 0x00;
  if (!pasc || !*pasc) return xret;
  int i     = 0;
  bool ldec = true;
  while (pasc[i]) {   // is ASCIICODE a decimal number ?
    if (!(pasc[i] >= '0' && pasc[i] <= '9')) ldec = false;
    i++;
  }
  if (ldec) 
    xret = (unsigned char)atoi((const char*)pasc); // literals are not handled yet (TIME)
  else if (*pasc == '#')  // Message to be sent when key is pressed
    xret = 0xFF;
  else if (*pasc == '\'') // Normal ASCII code is specified
    xret = *(pasc+1);   
  else {                  // DESCRIPTION OF ASCII like ENTER etc. 
  }                       // not handled yet
  return xret;
}

ushort GetMsgNo(unsigned char *pasc) {
  ushort xret = 0x0000; 
  if (!pasc || !*pasc) return xret;
  unsigned char *lc = new unsigned char[32];
  int i = 0;
  if (*pasc++ == '#') {
    while (*pasc >= '0' && *pasc <= '9') {
      lc[i++] = *pasc;
      pasc++;
    }
    if (i)
      xret = (ushort)atoi((const char*)lc);
  }
  delete lc;
  return xret;
}
  
void Hexer(char *po, ushort pi, unsigned char pl) {
  char lHex[] = "0123456789ABCDEF";
  po[pl+2]  = 0x00; // make ASCIIZ
  po[0]     = '0'; po[1]  = 'x';
  for (;(pl > 0);) {
    po[--pl+2]  = lHex[pi%16];
    pi /= 16;
  }
  return;
}

int ConvertInputToKeyTable(unsigned char *pi, unsigned char *ppref, bool pt) {
  int     xret = 0, ik, ia, lmaxT = 0, lmaxM = 0;
  unsigned char  *lkey = new unsigned char[32];     // KEYCODE
  unsigned char  *lasc = new unsigned char[32];     // ASCII CODE
  unsigned char  *ltbl = new unsigned char[1024];   // KeyTrlTbl
  ushort *lmsg = new ushort[1024];  // KeyMsgTbl
  memset(ltbl,0,1024);
  memset(lmsg,0,1024*2);
  printf("Convert %s using prefix %s\n",(char*)pi,(char*)ppref);
  TextReadC *tr = new TextReadC((char*)pi);
  while (!tr->EoF()) {
    unsigned char *lLine = tr->GetNextLine();
    memset(lkey,0,32); ik = 0;
    memset(lasc,0,32); ia = 0;
    if (lLine && *lLine != ';') { // if not empty line or comment
      while (*lLine == ' ') lLine++;  // skip leeding spaces
      while (*lLine && *lLine != ' ' && ik < 32-1) {
        lkey[ik++] = *lLine;
        lLine++;
      }   
      while (*lLine == ' ') lLine++;  // skip spaces between
      while (*lLine && *lLine != ' ' && ia < 32-1) {
        lasc[ia++] = *lLine;
        lLine++;
      }   
      if (ik && ia) {
      /* Now: KEYCODE and TRANSLATED CODE (ASCII) are filled in */
        int     lkeypos = GetKeyCode(lkey);
        unsigned char   lascii  = GetASCIICode(lasc);
        if (lkeypos > lmaxT) lmaxT = lkeypos;
        if (lkeypos > -1)
          ltbl[lkeypos]   = lascii;
        else 
          xret = 1;
        if (lascii == 0xFF && lkeypos > -1) {
          if (lkeypos > lmaxM) lmaxM = lkeypos;
          ushort lmsgno = GetMsgNo(lasc);
          lmsg[lkeypos] = lmsgno;
        }
      }
      else
        xret = 1;
    } 
  }
  if (!xret) {
    FILE *lo = CreateKeyTable();
    if (lo) {
      char *lobuff = new char[256]; *lobuff = 0x00;
      char tmp[12]; tmp[0] = 0x00;
      if (!(pt && !lmaxT)) {
        lmaxT++;
        if (!pt) lmaxT = 1024;
        lmaxT = ((lmaxT >> 3)+1) << 3;
        fwrite(".globl ",1,7,lo);
        if (ppref) strcpy(lobuff,(char*)ppref);
        strcat(lobuff,"KeyTrlTbl");
        fwrite(lobuff,1,strlen(lobuff),lo);
        fwrite("\n\n",1,2,lo); strcat(lobuff,":");
        for (int i = 0; (i < lmaxT); i++) {
          if (i %  8 == 0x00) {
            sprintf(tmp,"  // %.3X\n",i); strcat(lobuff,tmp);
            fwrite((void *)lobuff,1,strlen(lobuff),lo);
            memset(lobuff,0,256);
            strcat(lobuff,".byte ");
          }
          Hexer(tmp,ltbl[i],2);
          strcat(lobuff,tmp); tmp[0] = 0x00;
          if ((i+1) %  8 != 0x00) strcat(lobuff,", ");
        }
      }
      strcat(lobuff,"\n\n");
      fwrite((void *)lobuff,1,strlen(lobuff),lo);
      *lobuff = 0x00;
      tmp[0] = 0x00;
      if (!(pt && !lmaxM)) {
        lmaxM++;
        if (!pt) lmaxM = 1024;
        lmaxM = (lmaxM >> 3) << 3;
        fwrite(".globl ",1,7,lo);
        if (ppref) strcpy(lobuff,(char*)ppref);
        strcat(lobuff,"KeyMsgTbl");
        fwrite(lobuff,1,strlen(lobuff),lo);
        fwrite("\n\n",1,2,lo); strcat(lobuff,":");
        for (int i = 0; (i < lmaxM); i++) {
          if (i %  8 == 0x00) {
            sprintf(tmp,"  // %.3X\n",i); strcat(lobuff,tmp);
            fwrite((void *)lobuff,1,strlen(lobuff),lo);
            memset(lobuff,0,256);
            strcat(lobuff,".byte ");
          }
          Hexer(tmp,lmsg[i],4);
          strcat(lobuff,tmp); tmp[0] = 0x00;
          if ((i+1) %  8 != 0x00) strcat(lobuff,", ");
        }
      }
      strcat(lobuff,"\n\n");
      fwrite((void *)lobuff,1,strlen(lobuff),lo);
      delete lobuff;
      CloseKeyTable(lo);
    }
    else 
      xret = 1;
  }
  delete tr;
  delete ltbl;
  delete lmsg;
  delete lasc;
  delete lkey;
  return xret;
}

int main(int argc, char **argv) {
  Hello();
  if (argc > 3)
    return ConvertInputToKeyTable((unsigned char*)argv[1],(unsigned char*)argv[2],true);
  if (argc > 2)
    return ConvertInputToKeyTable((unsigned char*)argv[1],(unsigned char*)argv[2],false);
  if (argc > 1)
    return ConvertInputToKeyTable((unsigned char*)argv[1],NULL           ,false);
  return 1;
}