/*
 * Calculator.c          projekt pro kurs C v Amiga Review
 */

/* potÒebn× hlaviÃkov× soubory */
#include <ctype.h>       /* prÁce s typy znakÊ */
#include <stdio.h>       /* operace vstup/vÙstup */
#include <string.h>      /* operace s ÒetÅzci */

/* definice booleovsk×ho typu i s hodnotami;
 * standardnÅ je definovÁn v <exec/types.h> */
typedef short           BOOL;
#define TRUE            1
#define FALSE           0

/* definice pouÚÉvanÙch symbolÊ */
#define MAX_DELKA             1000
#define ZNAME_OPERATORY       "+-"

/* globÁlnÉ ÒetÅzec identifikujÉcÉ program a jeho verzi */
#define VERZE_KALKULACKY "KalkulaÃka 1.01 (9.10.1995)"
char *VERSION = "\0$VER: "VERZE_KALKULACKY;



/* naÓe varianta funkce strcat ... pÒipojÉ ÒetÅzec, ale vynechÁ
 * vÓechny nezajÉmav× znaky = tzv. bÉl× znaky (mezery apod.) */
/* funkce strcat pÒÉpojÉ k prvnÉmu ÒetÅzci druhÙ ÒetÅzec,
 * vrÁtÉ ukazatel na prnÉ ÒetÅzec */
char *NasStrCat(char *retezec, char *pripojovany)
{
/* ukazatel× na znak: 'kam' urÃuje pozici, kam se bude kopÉrovat;
 *                    'odkud urÃuje pozici, odkud se kopÉruje */
     char *kam, *odkud;

/* pomocÉ for-cyklu provedeme pÒÉpojenÉ;
 * poÃÁteÃnÉ inicializace - kam ukazuje za poslednÉ znak retezec;
 *                          odkud na prvnÉ znak pÒipojovan×ho ÒetÅzce */
/* podmÉnka = dÅlej, dokud nejsme na konci pripojovany (Òetezce jsou
 * ukonÃovÁny znakem '\0' - ten se bude brÁt jako logickÁ hodnota FALSE */
/* po okopÉrovÁnÉ se provede odkud++ = posun na dalÓÉ znak */
     for(kam = retezec + strlen(retezec), odkud = pripojovany;
	 *odkud; odkud++)
/* isspace vracÉ TRUE (pravda), je-li danÙ znak mezera, konec ÒÁdku apod. */
/* pokud je to nÅjakÙ rozumnÙ znak --> okopÉrujeme ho na pozici kam */
/* pokud okopÉrujeme, posuneme kam na dalÓÉ zapisovacÉ polÉÃko */
	  if (!isspace(*odkud))
	  {
	       *kam = *odkud;
	       kam++;
	  }
/* ukonÃenÉ vytvÁÒen×ho ÒetÅzce ... umÉstÉme na jeho konec znak '\0' */
     *kam = '\0';

/* vrÁtÉme ukazatel na poÃÁtek ÒetÅzce */
     return(retezec);
}

/* pomocnÁ funkce pro pÒeskoÃenÉ reÁln×ho ÃÉsla */
/* vstup: ukazatel na znak (= na ÒetÅzec), tj. ukazuje na
 *        1. pismeno pÒeskakovan×ho ÃÉsla;
 * vÙstup:ukazatel na znak (= na ÒetÅzec) - bude ukazovat na
 *        znak nÁsledujÉcÉ za pÒeskakovanÙm ÃÉslem */
char *PreskokCisla(char *cislo)
{
/* ÃÉslo mÁ tvar <znam×nko><ÃÉslice>.<ÃÉslice>E<znam×nko><ÃÉslice> */

/* je-li na poÃÁtku znam×nko, posuneme se na dalÓÉ znak ÃÉsla */
     if ((*cislo == '+') || (*cislo == '-'))
	  cislo++;
/* pÒeskoÃenÉ ÕvodnÉch ÃÉslic */
/* isdigit je funkce, kterÁ vracÉ TRUE (pravda), je-li danÙ znak ÃÉslice */
/* dÅlÁme: dokud je (*cislo) ÃÉslice, posunujeme se na dalÓÉ znak */
     for( ; isdigit(*cislo); cislo++);

/* pokud nÁsleduje teÃka --> ÃÉslo mÁ i desetinnou ÃÁst;
 * to pÒeskoÃÉme stejnÙm zpÊsobem */
     if (*cislo == '.')
     {    cislo++;  /* posuneme se za teÃku */
	  for( ; isdigit(*cislo); cislo++);
     }

/* pokud nÁsleduje 'e' nebo 'E', mÁ ÃÉslo exponent; pÒeskoÃÉme ho */
/* toupper je funkce, kterÁ mal× pÉsmeno pÒevede na velk× */
     if (toupper(*cislo) == 'E')
     {    cislo++;  /* posun na znak za 'E' */
       /* je-li na poÃÁtku exponentu znam×nko,
	* posuneme se na dalÓÉ znak exponentu */
	  if ((*cislo == '+') || (*cislo == '-'))
	       cislo++;
       /* pÒeskoÃÉme vÓechny ÃÉslice exponentu */
	  for( ; isdigit(*cislo); cislo++);
     }

/* vrÁtÉme ukazatel na znak za ÃÉslem ... ten je v 'cislo' */
     return(cislo);
}

/* funkce, kterÁ projde ÒetÅzec s vÙrazem a urÃÉ jeho hodnotu */
/* je-li vÙraz chybnÙ, vrÁtÉ FALSE;
 * v opaÃn×m pÒÉpadÅ vracÉ TRUE a
 * vÙsledek uloÚÉ do promÅnn× vysledek */
BOOL ProjdiRetezec(char *vyraz, double *vysledek)
{
/* pomocn× reÁln× promÅnn× pro vyhodnocnÉ vÙrazu */
     double vysl = 0, operand;
/* operator bude obsahovat znaÃku poslednÉho operÁtoru;
 * zatÉm umÉme jen '+', '-' */
     char operator = '+';
/* booleovskÁ promÅnnÁ - mÁme jiÚ skonÃit? */
     BOOL end = FALSE;

/* dokud nenÉ konec = end */
     while (!end)
     {
/* mÅlo nÁsledovat ÃÉslo (pÒÉpadnÅ pÒedchÁzen× mezerami apod.)
 * pÒeÃteme jej; */
	  if (0 >= sscanf(vyraz, "%lg", &operand))
/* nenÁsledovalo ÃÉslo, ale nÅco jin×ho = chyba ve vÙrazu */
	       return(FALSE);

/* nalezneme dalÓÉ operÁtor v ÒetÅzci = posuneme se za ÃÉslo */
	  vyraz = PreskokCisla(vyraz);

/* pokud odÃÉtÁme, vynÁsobÉme operand -1 a pÒiÃteme */
/* zatÉm nic jin×ho neÚ sÃÉtÁnÉ a odÃÉtÁnÉ neumÉme */
	  if (operator == '-') operand *= -1;
	  vysl += operand;

	  if ((*vyraz != '+') && (*vyraz != '-'))
	  { /* nenÁsleduje jiÚ operÁtor = mÁ bÙt konec vÙrazu */
	    /* pokud je tam tedy nÅco jin× neÚ konec Òetezce --> chyba */
	       if (*vyraz != '\0') return(FALSE);
	       end = TRUE;
	  }
	  else
/* v opaÃn×m pÒÉpadÅ si novÙ operÁtor zapamatujeme */
/* a posuneme se na dalÓÉ znak - znak za operÁtorem */
	  {    operator = *vyraz;
	       vyraz++;
	  }
     }
/* vyhodnotili jsme ÕspeÓnÅ vÙraz -->
 * vrÁtÉme vÙsledek volajÉcÉ funkci */
     *vysledek = vysl;
     return(TRUE);
}

/* hlavnÉ funkce programu = vstupnÉ bod */
int main(int argc, char *argv[])
/* argc udÁvÁ poÃet argumentÊ = ÒetÅzcÊ v pÒÉkazov× ÒÁdce */
/* argv pÒedstavuje pole ÒetÅzcÊ = slov v pÒÉkazov× ÒÁdce */
/* nÁvratovÁ hodnota je chybovÙ kÏd vrÁcenÙ AmigaDOSu */
{
/* promÅnnÁ na vÙsledek vÙpoÃtu */
     double vysledek;
/* pomocna celoÃÉselnÁ promÅnnÁ */
     int i;
/* pole znakÊ = ÒetÅzec; na poÃÁtku je prÁzdnÙ */
/* samotn× jm×no 'vyraz' pak reprezentuje adresu pole = ÒetÅzce */
     char vyraz[MAX_DELKA] = "";

/* zatÉm neumÉme startovat z Workbenche */
     if (argc == 0) return(20);
/* a poÚadujeme, aby byl zadÁn vÙraz k vyhodnocenÉ */
     if (argc == 1)
     {    printf("Nebyly zadÁny ÚÁdn× argumety!\n");
	  printf("NenÉ co poÃÉtat...\n");
	  return(5);
     }

/* vÓechny parametry spojÉme do jednoho Òetezce */
/* testujeme, zda je v poli vyraz dost mÉsta;
 * pokud je jiÚ zaplnÅno, pÒeruÓÉme pÒipojovÁnÉ */
/* pro pÒÉpojenÉ uÚÉvÁme NasStrCat, kterÙ vypustÉm vÓechny mezery apod. */
     for(i = 1; i < argc; i++)
	  if (strlen(vyraz) + strlen(argv[i]) + 1 < MAX_DELKA)
	       NasStrCat(vyraz, argv[i]);
	  else break;

/* ve vyraz je nynÉ celÙ vÙraz urÃenÙ ke spoÃtenÉ --> */
/* spoÃteme a vytiskneme zadanÙ vÙraz a vÙsledek vÙpoÃtu */
     if (ProjdiRetezec(vyraz, &vysledek))
	  printf("VÙsledek:\n%s = %G\n", vyraz, vysledek);
     else printf("Chyba v zadan×m vÙrazu!\n");

/* vÓe probÅhlo korektnÅ */
     return(0);
}

