//Sanjeev: sanjeev@adari.net
//Griphic Design Engineer
//Adari TeleComp Inc (www.adari.net)
//18th Dec 2002
//This Code is based on the logic behind the wonderful complete
//html parsing library at http://msalem.translator.cx/dist/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#define MLIST struct my_name_value_list
#define MOPT struct my_name_value_options_list

MLIST {
	char *name;
	char *value;
	MOPT {
		char *nam[20];
		char *val[20];
	}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);
char *memmanage(const char *tmp_src, size_t size, char arg);
void prn(char *msg, int linenum);

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

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

	if(argv[1])
			srcfile = argv[1];
	else
			printf("Usage:: %s filename\n", argv[0]);

	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!");
	}

	(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++) {
			if(store[i].next.nam[0] != NULL ) {
				printf("----------------------\n");
				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");
			}
			printf("%s = %s\n",store[i].name, store[i].value);
	}


	
	return 1;
}

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

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

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

				tmp_src = source;
				
				if(strncasecmp("input", source, 5) == 0 ) {
				
					source += 5;
					parseStart(source, 1);
				}
				else if(strncasecmp("textarea", source, 8) == 0 ) {

					source += 8;
					parseStart(source, 1);
				}
				else if((strncasecmp("select", source, 6) == 0) && (strncasecmp("selected", source, 8) != 0)) {
					source += 6;
					parseStart(source, 1);
					numSubargs = 0;
				}
				else if(strncasecmp("option", source, 6) == 0 ) {

					option = 1;
					source += 6;
					parseStart(source, 1);
					option = 0;
				}
				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 before opening of quote(or)
					//There are similiar quotes inside quotes like OnClick="....alert('"hai"') ..."
					//so skipping such values.
				while(isspace((int)*source)) source++;
			} else {
						
				htmltag = 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 ) {
						htmltag = memmanage(tmp_src, (size_t)(source-tmp_src +1), 'v');
					}
					else dead(88, "no close tag '\"' found", srclen - strlen(source));
				}
				else {
					tmp_src = source;
					while(*source != '\0' && !isspace((int)*source) && *source != '>' ) source++;
					if( isspace((int)*source) ) {
						htmltag = memmanage(tmp_src, (size_t)(source-tmp_src +1), 'v');
					}
					else dead(138, "no close tag '\"' found", srclen - strlen(source));
				}	
				source++;
				while(isspace((int)*source)) source++;
			}
		}
	}
	return;
}

char *memmanage(const char *tmp_src, size_t size, char arg) {
	
	register int res = 0;
		
		htmltag = (char *)calloc(1, size); //+1 for nulltermination
		if(!htmltag) {
				return "";
		}

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

		if(arg == 'n') {
			mname = htmltag;
			if(!option) {
				numArgs++;
				store[numArgs-1].name = mname;
			} else {
				numSubargs++;
				store[numArgs].next.nam[numSubargs - 1] = mname;
			}
		}
		else {
			mvalue = htmltag;
			if(!option)
				store[numArgs-1].value = mvalue;
			else {
				store[numArgs].next.val[numSubargs - 1] = mvalue;
				//puts(store[numArgs].next.val[numSubargs - 1]);
			}

		}
		
		return;
}

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

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);
}

