//written by Nikola Tosic aka Mogli lifeartist87@gmail.com


#include <stdio.h>
#include <limits.h>
#include <stdarg.h>

#define ERR 1
#define ARTMC_SHIFT (SHRT_MIN&(SHRT_MIN>>1))
#define LOGIC_SHIFT (!(SHRT_MIN&(SHRT_MIN>>1))
#define SHRT_BIT (sizeof(short)*8)
#define b00 0
#define b01 1
#define b10 2
#define b11 3

typedef enum {false,true} boolean;

void reg_print(short,char,short,short,char,char*);
void bin_print(short);
long mnozenje_but(short,short);
boolean pattern(char*,int, ... );
boolean string_eq(char*,char*);

int main()
{
	short a=-14,b=-9;
	long c;
	putchar('\n');

	c= mnozenje_but(a,b);
	printf("\n -14 * -9 = %d \n",c);
    return 0;
}

long mnozenje_but(short m,short p)
{
	//inicijalizacija registara a i p1,deklaracija promenljivih
	short a=0,i;
	char p1=0;
	char pp1,znak;
	
	for(i=0;i<SHRT_BIT;i++)
	{	
		//1.stampa trenunti sadrzaj registara
		putchar('\n');
		reg_print(m,0,a,p,p1,"mapp1");
		if(i==0)
			printf(" Inicijalizacija \n");
		else
			printf(" (a,p,p1)>>1 \n");
			
		//2.odredjivanje zadjeg bita u p i bita u p
		pp1=(2*(1&p))+p1;
	
		//3.izvrsavanje odredjene operacije u zavisnosti od pp1
		switch(pp1)
		{
			case b01: 
				a+=m;
				znak='+';
				break;
			case b10:
				a-=m;
				znak='-';
				break;
			case b00:
			case b11:
			default :
				znak='0';
				break;
				
		}
		
		//4.stampa sadrzaje registara posle izvrsene operacije
		reg_print(m,0,a,p,p1,"mapp1");
		if (znak=='0')
			printf(" bez promene \n" );
		else
			printf(" A = A %c M\n",znak);

		//5.aritmeticko shiftovanje registara app1 udesno za jedan
		p1=1&p;
		if(ARTMC_SHIFT)
		 //ako je pomeranje signed promenljivih  aritmeticko
			p = (p>0)?(p>>1)|((a&1)<<(SHRT_BIT-1)):(a&1)?p>>1:(p>>1)&SHRT_MAX;
		else //ako je pomeranje signed promenljivih logicko
			p=(p>>1) | ((a&1)<<(SHRT_BIT-1));
		a = (a >> 1);
		
	}
	putchar('\n');
	reg_print(0,0,a,p,0,"map");
	printf(" rezultat\n");
	
	return ((a<<SHRT_BIT)|p);
}
	
//stampa registre m,c,a,p i p1, mod moze biti "map","mcap","mapp1"	
void reg_print(short m,char c,short a,short p,char p1,char* mode)
{
	//provera za gresku pri pozivu f-je
	if(!pattern(mode,3,"map","mcap","mapp1"))
	{
		fprintf(stderr,"Los poziv f-je reg_print, proveri argumet char* mode\n");	
	}
	else
	{
		bin_print(m);
		putchar(' ');
		if(string_eq(mode,"mcap")) //ako je mod "mcap" stampa se registar c
		{
			putchar( (!c)?'0':'1');
			putchar(' ');
		}
		bin_print(a);
		putchar(' ');
		bin_print(p);
		putchar(' ');
		if(string_eq("mapp1",mode)) //ako je mod "mapp1" stampa se registar p1
		{
			putchar( (!p1)?'0':'1');
			putchar(' ');
		}
	}
}

//stampa binarni oblik neke varijable tipa short
void bin_print(short n)
{
	int i;
	
	for(i=0;i<sizeof(short)*8;i++)
		putchar(((((1<<sizeof(short)*8-1)>>i)&n)!=0)?'1':'0');
}

//funkija koja vraca 1 ako je prvi string jednak jednom od ostalih
//nakon prvog stringa je broj stringova  koji se pretrazuju
//koristi se promenljiva lista argumenata(pogledaj komentare u kodu f-je)
boolean pattern(char* s,int n, ...)
{
	char* pattern;
	va_list ap;  //ap se definise kao pokazivac na argumente iz liste
	va_start(ap,n); //ap pokazuje na prvi argument posle argumenta n

	while((n--)>0)
	{
		//va_arg uzima vrednost na koju pokazuje ap
		//nekog tipa, koji je drugi argument funkcije va_arg,
		//a zatim pomera ap tako da pokazuje na sledeci argument iz
		//promenljive liste argumenata
		//makroi va_arg, va_list, va_start, va_end su definisani u <stdarg.h>
		pattern=va_arg(ap,char*); 
		if(string_eq(s,pattern))
			return true;
	}
	
	va_end(ap);
	return false;
}

//funkcija koja vraca 0 ako stringovi nisu jednaki i 1 ako jesu
boolean string_eq(char* s1,char* s2)
{
	while(*s1!='\0' || *s2!='\0')
	{
		if(*s1!=*s2)
			return false;
			
		s1++;s2++;
	}
	return true;
}

