/*******************************************************
  CONV.C        Konvertierungen aller Art
 *******************************************************/

#include <stdlib.h>
#include <math.h>
#include "conv.h"
#include "serial.h"
#include "cmd.h"

/******************************************************************************
   Dezimal-Konvertierung Long in Pufferbereich.
   digits = gewünschte Anzahl Stellen.
            digits<0 = mit führenden Nullen,
	    sonst    = mit führenden Leerzeichen
   Buffer = Zeiger auf den Ergebnispuffer, mindestens 4 Byte groß.
   BufLen = Gesamtgröße des Ergebnispuffers. Soll mindestens 3 Byte größer
            sein als digits
 ******************************************************************************/

long LONGtoStr (long aValue, int digits, char* Buffer, int BufLen)
{ char* P;
  char* Q;
  long  L;
  char  v;
  int   i, j, k;
  ldiv_t T;

  *Buffer = 0;
  if (BufLen<4) return aValue;

  i = BufLen - 1;
  j = digits;
  if (j<0) j = -j;

  if (i < (j+3))      /* mehr Stellen als Bufferplatz */
  { Buffer[0] = '?';
    Buffer[1] = 0;
    return aValue;
  }

  Buffer[i--] = 0;    /* Endemarker setzen */
  if (aValue<0)
       { L = -aValue;
         v = 1;
       }
  else { L = aValue;
         v = 0;
       }

  if (!L)  Buffer[i--] = '0';
  while (i)
  { if (!L) goto _lready;
    T = ldiv(L,10);
    L = T.quot;
    Buffer[i--] = '0'+T.rem;
  }

                     /* i = 0, d.h. der Buffer ist voll! */
  i = 0; j = BufLen - 2;
  Buffer[i++] = '>';
  while (i<j) Buffer[i++] = '9';
  return aValue;


/* So, die Ziffern sind erzeugt, jetzt wird formatiert.
   i zeigt auf freien Platz vor 1. Ziffer
 */

_lready:
  k = BufLen - i - 2;       /* k = Anzahl gehabter Digits */

  if (digits < 0)           /* mit Nullen auffüllen */
  { j = -digits;            /* j = Sollstellenzahl */
    if (v) k++;             /* eine Stelle für '-' berücksichtigen */
    while (k++ < j)
    { if (i > 0) Buffer[i--] = '0'; }

    if (v) Buffer[i--]= '-'; /* Vorzeichen eintragen */
  }

  else                      /* mit Spaces auffüllen */
  { if (v)
     { Buffer[i--] = '-';   /* Vorzeichen eintragen */
       k++;                 /* Stelle berücksichtigen */
     }
     j = digits;
     while (k++ < j)
     { if (i > 0) Buffer[i--] = ' '; }
  }
  ++i;                 /* i zeigt jetzt auf 1. Zeichen */
  if (i)
  { P = Buffer;
    Q = &Buffer[i];
    j = BufLen - 1;
    while (j--) *P++ = *Q++;
    *P = 0;
  }
  return aValue;
}



/******************************************************************************
   Float in String wandeln.
   digits = Gesamtstellenzahl,
   dezi   = Anzahl Nachkommastellen, max. 9
 ******************************************************************************/

const float fdezimals[10] =
  { 1.0E+0, 1.0E+1, 1.0E+2, 1.0E+3, 1.0E+4, 1.0E+5, 1.0E+6, 1.0E+7, 1.0E+8, 1.0E+9 };

const float ldezimals[10] =
  { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };


float FFtoStr (float aValue, int digits, int dezi, char* Buffer, int BufLen)
{ float F;
  char* P;
  long  L, G;
  int   i, di, dna, Exponent, Vorzeichen;

  Buffer[0] = '?';                         /* String löschen */
  Buffer[1] = 0;

  Vorzeichen = Exponent =  0;              /* Vorzeichen und Exponent */
  F = aValue;
  if (F < 0)
  { Vorzeichen = 1;
    F = -F;
  }

  di  = digits;
  if (di>(BufLen-2)) di = BufLen - 2;
  dna = dezi;
  if (di<1) di = 1;
  if (dna>(di-2)) dna = di - 2;
  if (dna<0) dna = 0;
  if (dna>9) dna = 9;

  if (F > 999999999.0)
  { Exponent = 10;
    F = F / 1000000000.0;
    while (F >= 10.0)
     { F = F / 10.0;
       ++Exponent;
     }
    dna = di - 6;
    if (dna<1) dna = 1;
  }

                                /* F ist ab jetzt nicht negativ */
  L = F;                        /* L = ganzer Teil von |F| */
  F = F - L;                    /* F = Rest (F= F - ganzer_Teil_von_F) */
  if (dna) di = di - dna - 1;   /* Platz für Punkt und Nachkomma abziehen */
  F = F * fdezimals[dna] + 0.5; /* Wert ggf. aufrunden */
  G = F;                        /* Gebrochenen Teil als Long gerundet */
  if (G>=ldezimals[dna])        /* wenn Überlauf durch Rundungsfehler */
     { G = 0; ++L; }

  LONGtoStr (L, di, Buffer, BufLen);
  if (Vorzeichen)
  { i = 0;
    while (Buffer[i]==' ') ++i;
    if (!i)                     /* kein Platz vor der 1. Ziffer */
    { i = BufLen - 1;
      while (i) { Buffer[i] = Buffer[i-1]; --i; }
      ++i;
    }
    Buffer[--i] = '-';
  }

  if (dna)
  { P = Buffer;
    di = BufLen;
    while (*P) { ++P; --di; }
    if (di > 1) { *P++ = '.'; *P = 0; --di; }
    LONGtoStr (G, -dna, P, di);
  }

if (Exponent)
  { P = Buffer;
    di = BufLen;
    while (*P) { ++P; --di; }
    if (di > 1) { *P++ = 'E'; *P = 0; --di; }
    LONGtoStr (Exponent, 1, P, di);
  }

  return aValue;
}


void FF_Out (float f, int digits, int dezi)
{ char S[32];
  FFtoStr(f, digits, dezi, S, sizeof(S));
  V24_StrOut(S);
}



/****************************************************

         Funktionen für diverse Eingaben
            (Stringinhalte --> Zahlen)

 ****************************************************/


  /* 1 Nibble aus Kommandozeile lesen. Bei Fehlern: return -1 */
int GetNibble (char** Zptr)
{ char c;
  char* Pt;
  Pt = *Zptr;
  if (!*Pt) return -1;
  c = UpCase (*Pt++);
  *Zptr = Pt;
  if (c<'0') return -1;
  if (c<='9') return c-'0';
  if (c<'A') return -1;
  if (c<'G') return c-55;
  return -1;
}


dword Hex_In (char** Zptr)
{ dword i;
  long j;
  i = 0;
  IgnoreSpace(Zptr);
  j = GetNibble(Zptr);
  while (j>=0) { i = (i << 4) + j;
                 j = GetNibble(Zptr); }
  return i;
}





dword Long_In (char** Zptr)
{ long i;
  int j;
  char vorzeichen;
  char* Pt;
  i = 0;
  vorzeichen = 0;
  IgnoreSpace (Zptr);
  Pt = *Zptr;
  if (*Pt=='-') {vorzeichen = 1; ++Pt; }
  *Zptr = Pt;
  j = GetNibble (Zptr);
  if (j>9) j = -1;
  while (j>=0) { i = (i * 10) + j;
                 j = GetNibble(Zptr); }
  --*Zptr;
  if (vorzeichen) return -i;
  return i;
}


float Float_In (char** Zptr)  /* float aus String lesen */
{ float R;
  float T;
  int   i;
  char* Pt;
  byte  c;
  char  dp_seen;
  char  vorzeichen;

  dp_seen    = 0;
  vorzeichen = 0;
  R = 0.0;
  T = 1.0;
  IgnoreSpace (Zptr);
  Pt = *Zptr;
  c = *Pt++;
  if (c=='-')
   { vorzeichen = 1;
     c = *Pt++;
   }
  else
   { if (c=='+') c = *Pt++;
   }

Schleife:
  if (c=='.') { c=  *Pt++; dp_seen=1; }
  if (c<'0') goto Schlend;
  if (c>'9') goto Schlend;
  i = c - '0';
  R = R * 10.0 + i;
  if (dp_seen) T = T * 10.0;
  c = *Pt++;
  goto Schleife;

Schlend:
  --Pt;
  *Zptr = Pt;
  R = R / T;

  if (UpCase(*Pt)=='E')
  { ++Pt;
    *Zptr = Pt;
    i = Long_In(Zptr);
    while (i)
    { if (i<0) { R = R / 10.0; ++i; };
      if (i>0) { R = R * 10.0; --i; };
    }
  }
  if (vorzeichen) R = - R;
  return R;
}


  /* Zeichen 'a...z' in Großbuchstaben wandeln */
char UpCase ( char aChar)
{ if (aChar<'a')  return aChar;
  if (aChar<='z') return aChar-32;
  return aChar;
}

  /* Leerzeichen in der Kommandozeile übergehen */
void IgnoreSpace (char** Zptr)
{ char* Pt;
  Pt = *Zptr;
  while (*Pt==' ') ++Pt;
  *Zptr = Pt;
}

const float FRound[5] = { 10.0, 100.0, 1000.0, 10000.0, 100000.0 };

float FF_round (float aValue, byte Digits)
{ float f;
  int n;
  n = Digits-1;
  if (n<0) n = 0;
  if (n>4) n = 4;
  f = floor((fabs(aValue) * FRound[n]) + 0.5);
  if (aValue<0) f = -f;
  f = f / FRound[n];
  return f;
}

char match (char* item, char** Zptr)
{ char* P;
  IgnoreSpace(Zptr);
  P = *Zptr;
  if (UpCase(*P) != *item) return 0;
  while (*item) { if (UpCase(*P++)!=(*item++)) return 0; }
  *Zptr = P;
  IgnoreSpace(Zptr);
  return 1;
}


const char HexChars[17]   = {"0123456789ABCDEF"};


/* ein Hex-Zeichen ausgeben */
void Nibble_Out (int aHex)
{ V24_CharOut (HexChars[aHex & 0x0F]); }

/* ein Byte als Hexa ausgeben */
void HexB_Out (byte aHex)
{ Nibble_Out (aHex >> 4);
  Nibble_Out (aHex);
}

/* ein Word als Hexa ausgeben */
void HexW_Out (word aHex)
{ HexB_Out (aHex >> 8);
  HexB_Out (aHex);
}

/* ein DWORD als Hexa ausgeben */
void HexL_Out (long aHex)
{ HexW_Out (aHex >> 16);
  HexW_Out (aHex);
}

/* ein QWORD als Hexa ausgeben */
void HexQ_Out (int64 aHex)
{ HexL_Out (aHex >> 32);
  HexL_Out (aHex);
}


/* Dezimal-Ausgabe */
void Dezi_Out (long aDez, signed char digits)
{ int i;
  int dig;
  char s[16];
  char c;

  c = ' ';
  dig = digits;
  if (dig<0) { dig = -digits; c = '0'; }

  i = 0;
  s[0] = 0;
  if (!aDez) s[++i]= '0';
  if (aDez<0) {V24_CharOut('-'); aDez = -aDez;}
  while (aDez)
  { s[++i] = (aDez % 10) + '0';
    aDez = aDez / 10;
  }
  while (i<dig) { V24_CharOut(c);  --dig; }
  while (s[i])  { V24_CharOut(s[i]); --i; }
}

/* eigene Stringfunktionen */

char* StringCopy (char* ziel, char* quelle, int bufmax)
{ --bufmax;
  while ((bufmax) && (*quelle))
  { *ziel++ = *quelle++;
    --bufmax;
  }
  *ziel = 0;
  return ziel;
}

char* StringAdd (char* ziel, char* quelle, int bufmax)
{ --bufmax;
  while ((bufmax) && (*ziel))
  { --bufmax;
    ++ziel;
  }
 while ((bufmax) && (*quelle))
  { *ziel++ = *quelle++;
    --bufmax;
  }
  *ziel = 0;
  return ziel;
}

