/*
 * sanjeev (sanjeev@adari.net)
 * Graphic Design Engineer
 * Adari Telecomp Inc. (www.adari.net)
 * (18 Dec 02) Modified 20 Dec 02
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>

#define MLIST struct my_name_value_list
#define MOPT struct my_name_value_options_list

MLIST {
	char *name;
	MOPT {
		char *nam[20];
		char *val[20];
		int  *count;
	}next;
};

static int numArgs = 0, numSubargs = 0;
char *htmltag, *mname, *mvalue;
MLIST store[60];
int option;

int main(int argc, char *argv[]);
void parseStart(const char *source, int iter);
void memmanage(const char *tmp_src, size_t size, char arg);
void prn(char *msg, int linenum);
void dead(int linenum, char *message, /*@null@*/ int srclinenum);

int main(int argc, char *argv[]) {

	FILE *file;
	char *source = NULL,*srcfile = NULL;
	struct stat fileop; // file operations!
	int i,j;

	if(argv[1])
            srcfile = argv[1];
    else {
            printf("Usage:: %s filename\n", argv[0]);
			exit(0);
	}
printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
	
	file = fopen( srcfile, "r");
	if(!file) {
			perror("open");
			exit(EXIT_FAILURE);
	}
		
	if(stat(srcfile, &fileop) == -1 ) {
			fprintf(stderr, "file ( %s ) cannot be opened for reading\n", srcfile);
			exit(EXIT_FAILURE);
	}

	source = calloc(fileop.st_size+1,1);

	if(!source) {
			dead(33, "Memory Allocation Failure!", 0);
	}

	(void)fread(source,1,(size_t)fileop.st_size,file);
	(void)fclose(file);
	parseStart(source, 0);
	free(source);
	free(htmltag);
	
	printf("%d\n",numArgs);
	for(i=0; i < numArgs; i++) {
				printf("+++++++++++++++++++++++++++\n");
			printf(">> %s\n",store[i].name);
			if(store[i].next.nam[0] != NULL ) {
				printf("+-------------------------+\n");
				printf("+ number of parameters: %d\n",store[i].next.count);
				j = 0;
				do {
					printf("  %s = %s\n",store[i].next.nam[j], store[i].next.val[j]);
					j++;
				} while (store[i].next.nam[j] != NULL);
				printf("+-------------------------+\n");
			}
	}


	
	return 0;
}

void parseStart(const char *source, int iter) {

	const char *tmp_src;
	char quote;
	
	if( !iter ) {
		while(*source != '\0' && *source != '<') source++;
		source++;	
		if( *source != '/' && *source != '!' && !isspace((int)*(source)) ) {

			while(*source != '\0' && !isspace((int)*(source)) && *source != '>') {

				tmp_src = source;
				
				if(strncasecmp("input", source, 5) == 0 ) {

					memmanage("input", (size_t)6, 'm');
					source += 5;
					parseStart(source, 1);
				}
				else if(strncasecmp("textarea", source, 8) == 0 ) {

					memmanage("textarea", (size_t)9, 'm');
					source += 8;
					parseStart(source, 1);
				}
				else if((strncasecmp("select", source, 6) == 0) && (strncasecmp("selected", source, 8) != 0)) {

					memmanage("select", (size_t)7, 'm');
					source += 6;
					parseStart(source, 1);
				}
				else if(strncasecmp("option", source, 6) == 0 ) {
						
					source += 6;
					parseStart(source, 1);
				}
				source++;
			}
			if(*source != '\0')
					parseStart(source, 0);
		}
		else if( *source == '!' || *source == '/' ) {

			while(*source != '>') source++;
			source++;
			if(*source != '\0')
					parseStart(source,0);

		}
	}
	else {
		while (*source != '\0' && *source != '>') {
			while(isspace((int)*source)) source++;
			tmp_src = source;

			while( *source != '\0' && *source != '=' 
							&& !isspace((int)*source) && *source != '>') source++;
			while(isspace((int)*source)) source++;
			if( *source != '=' ) {
					//There is a problem in html code like: value"blah blah blah"(quote opened 
					//and closed with out an '=' sign (or)
					//There are similiar quotes inside quotes like OnClick="....alert('"hai"') ..."
					//skipping this
				while(isspace((int)*source)) source++;
			} else {
						
				memmanage(tmp_src, (size_t)(source-tmp_src +1), 'n');
				source++;
						
				while(*source != '\0' && isspace((int)*source)) source++;

				if(*source == '"' || *source == '\'') {
					quote = *source;
					source++;	
					tmp_src = source;
					while(*source != '\0' && *source != quote && *source != '>' ) source++;
					if( *source == quote ) {
						memmanage(tmp_src, (size_t)(source-tmp_src +1), 'v');
					}
					else dead(88, "no close tag '\"' found", source-tmp_src);
				}
				else {
					tmp_src = source;
					while(*source != '\0' && !isspace((int)*source) 
									&& *source != '>' && *source != '/') source++;
					if( isspace((int)*source) || *source == '/' || *source == '>') {
						memmanage(tmp_src, (size_t)(source-tmp_src +1), 'v');
					}
					else dead(138, "no close tag '\"' found", source-tmp_src);
				}	
				source++;
				while(isspace((int)*source)) source++;
			}
		}
	}
	return;
}

void memmanage(const char *tmp_src, size_t size, char arg) {
	
		htmltag = (char *)calloc(1, size);
		if(!htmltag) {
				return;
		}

		memcpy(htmltag, tmp_src, (size - 1));

		if(arg == 'm') {

			numArgs++;
			numSubargs = 0;
			store[numArgs -1].name = htmltag;
			store[numArgs -1].next.count = 0;
		} else if(numArgs > 0) {
			if(arg == 'n') {

				numSubargs++;
				mname = htmltag;
				store[numArgs -1].next.nam[numSubargs -1] = mname;
				store[numArgs -1].next.count = store[numArgs -1].next.count + 1;
			} else {

				mvalue = htmltag;
				store[numArgs -1].next.val[numSubargs -1] = mvalue;
			}
		}
				
				
			
		return;
}

void prn(char *msg, int linenum) {
	
		printf("PASSED with message>> %s , line number>> %d\n",msg,linenum);
}

void dead(int linenum, char *message, /*@null@*/ int srclinenum) {
	printf("in exit from line number:: %d\n", linenum);
	printf("with message:: %s\n", message);
	if(srclinenum)
		printf("Source pointer at:: %d\n", srclinenum);
	exit(EXIT_FAILURE);
}

