/*
*****************************************************************************
     My starting number : 02
     Used modules: 02TAB.C, 02TABP2.C,02TABP3.C

     02TAB.C - solves task no. 1
     02TABP2.C - solves task no. 2
     02TABP3.C - unfinished, only data structures and readdata() function
		 modified for task no. 3

     Note: I'm writing this comments at the end of the competition, so only
     the file 02TAB.C will be commented. The others are using the same ideea,
     with some little variations.
******************************************************************************
*/

#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>

//constants that define the alignament type
#define NO_FORM 0
#define H_CENTR 1
#define V_CENTR 2
#define A_CENTR 3

//type definitions
typedef unsigned char UCHAR;
typedef unsigned int UINT;
/*the next is the structure used for each line
  contains: no. of cells/line, the text in each cell and the alignament
  type (array ctype).
  EVERYTHING IN HERE IS DYNAMIC MEMORY ALLOCATION.
*/
typedef struct t{
     int nrofcels;
     char far **ctext;
     int *ctype;
     struct t *next;
     } LINE;
/*temporary structure used only for one line; the data in here will be copied
    in the LINE structure*/
typedef struct r{
     char *text;
     int align;
     struct r *next;
     } LTEXT;

int cpl=80,totsize,nrl;
char inf[66],outf[66];
UCHAR far *buffer;//file buffer
LINE **llist;//the final array which will contain all data for the cells
UINT wh,size;
int *csize;//dynamic array which holds the size of each cell
FILE *fout;

//malloc with memory verification
void far *smalloc(long size)
{
     void far *tmp;

     tmp=farmalloc(size);
     if(tmp==NULL)
     {
	printf("Not enough memory\n");
	exit(0x10);
     }
     return tmp;
}

//finds the end of a tag by skipping extra spaces
void findend()
{
     char k;

     k=buffer[wh];wh++;
     while((k!='>')&&(wh<size))
     {
	k=buffer[wh];wh++;
     }
}

//returns the filesize of the file associated with FS
long filesize(FILE *fs)
{
     long now,len;

     now=ftell(fs);fseek(fs,0,SEEK_END);
     len=ftell(fs);fseek(fs,now,SEEK_SET);
     return len;
}

//allocates space in memory for a LINE structure
LINE *NewLine()
{
     LINE *tmp;

     tmp=(LINE *)smalloc(sizeof(LINE));
     tmp->nrofcels=0;
     tmp->ctext=NULL;
     tmp->ctype=NULL;
     return tmp;
}

//allocates space in memory for a LTEXT structure
LTEXT *NewText()
{
     LTEXT *tmp;

     tmp=(LTEXT *)smalloc(sizeof(LTEXT));
     tmp->text=NULL;
     tmp->align=NO_FORM;
     tmp->next=NULL;
     return tmp;
}

/*this function will search in the input string for consecvent spaces; it
  will also delete all non-literal characters (ex."\r","\n") and then it
  will search for '&'-based constructions.*/
void prelbuf(char *tx)
{
     char *k;

     k=strstr(tx," ");
     while(k!=NULL)
     {
	while(k[1]==' ') memmove(k,k+1,strlen(k));
	k=strstr(k+1," ");
     }
     k=strstr(tx,"&");
     while(k!=NULL)
     {
	switch(toupper(k[1]))
	{
	   case 'L':memmove(k+1,k+4,strlen(k)-1);k[0]='<';break;
	   case 'G':memmove(k+1,k+4,strlen(k)-1);k[0]='>';break;
	   case 'A':memmove(k+1,k+5,strlen(k)-2);k[0]='&';break;
	}
	k=strstr(k+1,"&");
     }
     k=tx+strlen(tx)-1;while(!isprint(k[0]))
     {
	k[0]=0;
	k--;
     }
}

/*this function reads the data in the input file and loads it in an organized
  manner*/
void readdata()
{
     FILE *fp;
     char k,kk;
     UINT firstline=1;//shows us if we are on the first line of the file
     LINE *sant,*crt,*now;//list structure, type LINE
     LTEXT *lsant,*lcrt,*lnow;//list structure, type LTEXT
     char tbuf[2000],tpos=0;//text buffer and position in it
     int ct;//contor

     fp=fopen(inf,"rb");
     if(fp==NULL)
     {
	printf("Error reading input file\n");
	exit(0x10);
     }
     buffer=(UCHAR far *)smalloc(filesize(fp));//file buffer allocation
     fread(buffer,size=(UINT)filesize(fp),1,fp);
     wh=0;nrl=0;
     sant=NewLine();crt=sant;//init list 1
     lsant=NewText();lcrt=lsant;//init list 2
     while(wh<size)
     {
	k=buffer[wh];
	switch(k)
	{
	   case '<':
	      k=toupper(buffer[wh+1]);wh+=2;
	      //search for a legal tag
	      while((k!='R')&&(k!='H')&&(k!='D')&&(wh<size))
	      {
		 k=toupper(buffer[wh]);
		 wh++;
	      }
	      switch(k)
	      {
		 case 'R':
		    /*new line tag : if it is not the first line, we flush
		      the information from line structure LTEXT into the
		      big structure LINE ; also allocates space for a new
		      line*/
		    if(!firstline)
		    {
		       crt->ctext=(char far **)smalloc(crt->nrofcels*sizeof(char far*));
		       crt->ctype=(int *)smalloc(crt->nrofcels*sizeof(int));
		       lnow=lsant->next;
		       for(ct=0;ct<crt->nrofcels;ct++)
		       {
			  crt->ctext[ct]=lnow->text;
			  crt->ctype[ct]=lnow->align;
			  lnow=lnow->next;
		       }
		       lcrt=lsant;
		    }
		    firstline=0;
		    nrl++;now=NewLine();
		    crt->next=now;crt=now;findend();
		    break;
		 case 'D':
		 case 'H':
		    //init text buffer, read text, call prelbuf()
		    kk=k;findend();tpos=0;memset(tbuf,0,2000);
		    do
		    {
		       k=buffer[wh];wh++;
		       if(k!='<') tbuf[tpos++]=k;
		    }
		    while((k!='<')&&(wh<size));wh--;
		    prelbuf(tbuf);
		    //the new information are aded to structure LTEXT
		    lnow=NewText();
		    lnow->text=(char *)smalloc(strlen(tbuf)+1);
		    strcpy(lnow->text,tbuf);
		    lcrt->next=lnow;lcrt=lnow;
		    crt->nrofcels++;
		    if(kk=='H') lnow->align=A_CENTR;
	      }
	      break;
	   default:wh++;
	}
     }
     //final flush, for the last line in the file
     crt->ctext=(UCHAR far **)smalloc(crt->nrofcels*sizeof(UCHAR *));
     crt->ctype=(int *)smalloc(crt->nrofcels*sizeof(int));
     lnow=lsant->next;
     for(ct=0;ct<crt->nrofcels;ct++)
     {
	crt->ctext[ct]=lnow->text;
	crt->ctype[ct]=lnow->align;
	lnow=lnow->next;
     }
     //and now the list of lines, also dynamic allocation
     llist=(LINE **)smalloc(nrl*sizeof(LINE *));
     now=sant->next;for(ct=0;ct<nrl;ct++)
     {
	llist[ct]=now;
	now=now->next;
     }
     //now we have an array for each line of the input file with all we need.
     //realease the file buffer
     farfree(buffer);
}

/*calculates size of the tabel by finding out the biggest text in each cell
  and then using it to find the total size.*/
void calcsize()
{
     int ct,i,k;

     csize=(int *)smalloc(llist[0]->nrofcels*sizeof(int));
     for(ct=0;ct<nrl;ct++) csize[ct]=0;
     for(ct=0;ct<llist[0]->nrofcels;ct++)
	for(i=0;i<nrl;i++)
	   if(csize[ct]<strlen(llist[i]->ctext[ct]))
	      csize[ct]=strlen(llist[i]->ctext[ct]);
     for(ct=totsize=0;ct<llist[0]->nrofcels;ct++) totsize+=csize[ct]+2;
     totsize+=1+llist[0]->nrofcels;
     //verification for line length
     if(totsize>cpl)
     {
	printf("Error: Table is too long to fit line.\n");
	exit(0x10);
     }
}

//this will write a single line in the file using the center type
void wline(int k)
{
     int i,nrs,ct;

     fprintf(fout,"| ");
     for(ct=0;ct<llist[k]->nrofcels;ct++)
     {
	if(llist[k]->ctype[ct]==0)
	{
	   fprintf(fout,"%s",llist[k]->ctext[ct]);
	   for(i=0;i<csize[ct]-strlen(llist[k]->ctext[ct]);i++)
	      fprintf(fout," ");
	}
	else
	{
	   nrs=(csize[ct]-strlen(llist[k]->ctext[ct]))/2;
	   for(i=0;i<nrs;i++) fprintf(fout," ");
	   fprintf(fout,"%s",llist[k]->ctext[ct]);
	   for(i=0;i<csize[ct]-nrs-strlen(llist[k]->ctext[ct]);i++)
	      fprintf(fout," ");
	}
	fprintf(fout," | ");
     }
     fprintf(fout,"\n");
}

//wtab will call wline() to write the text and will also write the tabel face.
void wtab()
{
     int ct,i,j;

     fout=fopen(outf,"wt");
     if(fout==NULL)
     {
	printf("Could not open output file.\n");
	exit(0x10);
     }
     fprintf(fout,"+");
     for(ct=0;ct<totsize-2;ct++) fprintf(fout,"-");fprintf(fout,"+\n");
     wline(0);
     for(ct=1;ct<nrl;ct++)
     {
	fprintf(fout,"|");
	for(i=0;i<llist[0]->nrofcels-1;i++)
	{
	   for(j=0;j<csize[i]+2;j++) fprintf(fout,"-");
	   fprintf(fout,"+");
	}
	for(j=0;j<csize[llist[0]->nrofcels-1]+2;j++) fprintf(fout,"-");
	fprintf(fout,"|\n");
        wline(ct);
     }
     fprintf(fout,"+");
     for(ct=0;ct<totsize-2;ct++) fprintf(fout,"-");fprintf(fout,"+\n");
}

//main program : read parameters, call all functions.
void main(int argc,char **argv)
{
     int fpar;

     clrscr();
     if(argc<3)
     {
	printf("Invalid number of parameters\n");
	exit(0x10);
     }
     fpar=1;
     if(argv[1][0]=='-') {sscanf(argv[1]+1,"%i",&cpl);fpar=2;}
     strcpy(inf,argv[fpar]);strcpy(outf,argv[fpar+1]);
     readdata();calcsize();wtab();
}