// Ganz einfacher Taschenrechner mit Brüchen (als Struktur)
// + - * / von links nach rechts ohne Vorrang
// Version mit Kürzen
// 
// Aufruf: bruch-kuerzen bruch1 op1 bruch2 op2 bruch3 ...
//
// Klaus Kusche, 2012

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct bruch {
  int z;
  int n;
};

typedef struct bruch bruch;

int ggT(int a, int b);
void Kuerzen(bruch *b);
bruch Plus(bruch l, bruch r);
bruch Minus(bruch l, bruch r);
bruch Mal(bruch l, bruch r);
bruch Durch(bruch l, bruch r);
void Ausgabe(bruch a);
bruch Eingabe(const char *str);

int ggT(int a, int b)
{
  // Euklid'scher Algorithmus, auf den Zahlen *ohne* Vorzeichen
  a = abs(a);
  b = abs(b);
  
  while (b > 0) {
    int r = a % b;
    a = b;
    b = r;
  }
  
  return a;
}

void Kuerzen(bruch *b)   // Das Argument ist ein Pointer auf einen Bruch
                         // (wir wollen ja den Bruch im Aufrufer ändern!)
                         // ==> Zugriff mit -> statt .
{
  if (b->n == 0) {
    fprintf(stderr, "Nenner ist 0!\n");
    exit(EXIT_FAILURE);
  }

  // Vorzeichen nach oben bringen, Nenner soll immer >0 sein
  if (b->n < 0) {
    b->z = -b->z;
    b->n = -b->n;
  }

  int g = ggT(b->z, b->n);
  b->z /= g;
  b->n /= g;
}

bruch Plus(bruch l, bruch r)
{
  bruch ergeb;
  ergeb.z = l.z * r.n + r.z * l.n;
  ergeb.n = l.n * r.n;
  Kuerzen(&ergeb);
  return ergeb;
}

bruch Minus(bruch l, bruch r)
{
//  bruch ergeb;
//  ergeb.z = l.z * r.n - r.z * l.n;
//  ergeb.n = l.n * r.n;
// Alternative Variante mit Initialisierung statt Zuweisung:
  bruch ergeb = { l.z * r.n - r.z * l.n, l.n * r.n };
  Kuerzen(&ergeb);
  return ergeb;
}

bruch Mal(bruch l, bruch r)
{
  bruch ergeb;
  ergeb.z = l.z * r.z;
  ergeb.n = l.n * r.n;
  Kuerzen(&ergeb);
  return ergeb;
}

bruch Durch(bruch l, bruch r)
{
  bruch ergeb;
  ergeb.z = l.z * r.n;
  ergeb.n = l.n * r.z;
  Kuerzen(&ergeb);
  return ergeb;
}

void Ausgabe(bruch a)
{
  if (a.n != 1) {
    printf("%d/%d\n", a.z, a.n);
  } else {
    printf("%d\n", a.z);
  }
}

bruch Eingabe(const char *str)
{
  bruch ergeb;
  
  ergeb.z = atoi(str);
  const char *slash = strchr(str, '/');
  if (slash == NULL) {          // Kein / gefunden
// Alternative zu atoi + strchr:
// strtol speichert einen Pointer auf das erste nicht-Ziffern-Zeichen in slash
//  char *slash;
//  ergeb.z = strtol(str, &slash, 10);
//  if (*slash != '/') {
    ergeb.n = 1;            // Kürzen in diesem Fall unnötig
  } else {
    ergeb.n = atoi(slash + 1);  // Der Nenner beginnt 1 Zeichen hinter dem /
    Kuerzen(&ergeb);
  }
  return ergeb;
}

int main(int argc, const char *argv[])
{
  // 1, 3, 5, ... Eingabeworte (+1 für den Programmnamen) sind ok
  if (argc % 2 != 0) {
    fprintf(stderr, "%s: Die Anzahl der Eingabeelemente stimmt nicht!\n",
            argv[0]);
    exit(EXIT_FAILURE);
  }

  bruch result = Eingabe(argv[1]);       // erster/linker Bruch
  // Schleife in Zweierschritten ab erstem Rechenzeichen
  for (int i = 2; i < argc; i += 2) {  
    bruch input = Eingabe(argv[i + 1]);  // nächster/rechter Bruch
    switch (argv[i][0]) {          // Rechenzeichen dazwischen
      case '+':
        result = Plus(result, input);
        break;
      case '-':
        result = Minus(result, input);
        break;
      case 'x':
         result = Mal(result, input);
        break;
      case '/':
        result = Durch(result, input);
        break;
      default:
        fprintf(stderr, "%s: %c: Kein Rechenzeichen?\n", argv[0], argv[i][0]);
        exit(EXIT_FAILURE);
    }
  }

  Ausgabe(result);
  
  exit(EXIT_SUCCESS);
}
