/* titel: ascii.c; gibt Ascii-Zeichen aus. Eingabe oktal, dezimal, hex */
/* ASCII := American Standard Code for Information Interchange   */

#include <stdio.h>
#include <stdlib.h>  /* wegen exit             */
#include <ctype.h>   /* wegen iscntrl, isdigit */
#include <string.h>  /* wegen strcmp, strlen   */

/* Definition eines Arrays von Strings: jedes Array-Element ist ein
   String und als solcher ebenfalls ein Array, allerdings von char.
   Die Strings selbst werden daher als Pointer auf char deklariert und
   durch ihre explizite Angabe initialisiert.
*/
char *name[] = { "NUL","SOH","STX","ETX","EOT","ENQ","ACK","BEL","BS", "HT","LF",
                 "VT", "FF", "CR", "SO", "SI", "DLE","DC1","DC2","DC3","DC4","NAK",
                 "SYN","ETB","CAN","EM", "SUB", "ESC","FS", "GS", "RS", "US", "SP"};

char *eingabe = "\
  Eingabe eines Einzelzeichens liefert dessen Asciiwert \n\
  Eingabe von ^Zeichen liefert Asciiwert des Control-Zeichens\n\
  Eingabe einer mehrstelligen Ziffer liefert zugehoeriges Asciizeichen\n\
  Eingabe einer Ziffer mit vorangestelltem\n\
              o, O oder 0:      Ziffer wird oktal gelesen\n\
              d oder D:         Ziffer wird dezimal gelesen\n\
              x oder X:         Ziffer wird hexadezimal gelesen\n\
              tab:              Eine Ascii-Tabelle wird ausgegeben\n\
              TAB:              Eine Tabelle der Zeichen > 127 wird ausgegeben\n\
  Abbruch durch Eingabe von \"ex\" oder mit Ctrl-C\n";

/* Die folgende Funktion verwendet Zeigerarithmetik fuer Arrays
 s ist eine Zeigervariable fuer char, die anfangs auf den Beginn eines
 char-Arrays zeigt, der fuer die Speicherung einer Zeile verwendet werden soll.
 Nach jedem empfangenen Zeiche wird s inkrementiert, also erreicht, dass s
 auf eine neue Position zeigt, um das naechste Zeichen aufnehmen zu koennen.  */

void mygetline(char *s) { /* Prueft keinen Speicher-Ueberlauf!!! */
  int c, cc = 0;
  while ( (c=getchar()) != '\n' && c != EOF ) {
    *s++ = c; cc++;
  }
  if ( cc == 0 && c == '\n')  /* newline nur eintragen, wenn es einziges
  Zeichen der Zeile ist, damit es als Ascii-Zeichen erkannt werden kann.*/
    *s++ = c;
  *s = '\0';
}

void tabelle(int x) {
  int i;
  printf("\n");
  if (x==0) {
    for (i=0; i < 31; i++)
      printf("\t%3d %2x %s\t%3d %2x %c\t%3d %2x %c\t%3d %2x %c\n",\
             i,i,name[i],i+32,i+32,i+32,i+64,i+64,i+64,i+96,i+96,i+96);
      printf("\t%3d %2x %s\t%3d %2x %c\t%3d %2x %c\t%3d %2x DEL\n",\
             i,i,name[i],i+32,i+32,i+32,i+64,i+64,i+64,i+96,i+96);
  }
  else
    for (i=128; i < 128 + 32; i++)
      printf("\t%3d %2x ??? \t%3d %2x %c\t%3d %2x %c\t%3d %2x %c\n",\
             i,i,  i+32,i+32,i+32,i+64,i+64,i+64,i+96,i+96,i+96);
  printf("\n");
}

int main() {
  char s[10]; int c; void tabelle(int);
  printf( "%s", eingabe );
  while (1) {
    printf(": ");
    mygetline(s);      /* scanf("%s",s)  geht nicht wegen \n */
    if ( strcmp(s, "ex" ) == 0 )   /* Abbruch */
      exit(0);
    if ( strcmp(s, "tab") == 0 ) {
      tabelle(0); continue;
    }
    if ( strcmp(s, "TAB") == 0) {
      tabelle(1); continue;
    }
    if ( strlen(s) == 1 ) c = s[0];
    else if ( s[0] == '^' ) c = s[1] & 0x1f;   /* Nur die letzten 5 Bit */
    else if ( s[0] == 'o' || s[0] == 'O' || s[0] == '0')
      sscanf(&s[1],"%o",&c); /* liest aus dem String beginnend bei &s[1] */
    else if ( s[0] == 'd' || s[0] == 'D')
      sscanf(&s[1],"%d",&c);
    else if        ( isdigit( s[0] ) )        
      sscanf(s, "%d", &c);                
    else if ( s[0] == 'x' || s[0] == 'X' )        
      sscanf(&s[1],"%x",&c);
    c &= 0xff;
    if ( !iscntrl(c) && c != ' ')
      printf("ASCII(%c) = o%o  d%d  x%x\n",c,c,c,c);
    else if ( c == ' ' )
      printf("ASCII( ) = %s = o%o  d%d  x%x\n",name[c],c,c,c);
    else if ( c != 0x7f )
      printf("ASCII(^%c) = %s = o%o  d%d  x%x\n",  c+0x40,name[c],c,c,c);
    else
      printf("ASCII(DEL) = o%o  d%d  x%x\n",c,c,c);
  }
}
