#!/usr/bin/awk -f

function check_flag(flag,mesg) {
	if (flag == 0) {
		printf(mesg);
		exit(1);
	}
}

function debug_version(num,val) {
	if (!debug)
		return
	printf("D:card(%d):v(1/%d)=%s\n", num,version_num[num],val);
}

BEGIN {
	FS="[, \t]+";
	devnum = 0;
	cardnum = 0;
	funcid["memory_card"] = 1;
	funcid["serial_port"] = 2;
	funcid["parallel_port"] = 3;
	funcid["fixed_disk"] = 4;
	funcid["video_adapter"] = 5;
	funcid["network_adapter"] = 6;
	funcid["aims_card"] = 7;
	funcid["scsi_adapter"] = 8;
#	debug = 1;
}
/^[[:space:]]*#/ {
	next
}
/^$/ {
	device_flag = 0;
	card_flag = 0;
	next
}

# (;_;)
{
	gsub(/^[[:space:]]*/,"");
}

# device config
$1 == "device" {
	if (debug) {
		printf("D:device %s\n",$2);
	}
	device_flag = 1;
	devname[devnum] = $2;
	next
}
$1 == "class" {
	check_flag(device_flag,"device flag is invalid\n");
	class[devname[devnum]] = $2
	if (debug) {
		printf("D:class:%s\n",$2);
	}
	# cb_enabler will be ignored
	if ($3 == "module") {
		gsub(/.*module /,"");
		sub(/", "/,"\"@\"");
		module_num[devname[devnum]] = split($0,mod,"@");
		mod_1[devname[devnum]] = mod[1];
		if (debug) {
			printf("D:module(1):%s\n",mod[1]);
		}
		if (module_num[devname[devnum]] == 2) {
			mod_2[devname[devnum]] = mod[2];
			if (debug) {
				printf("D:module(2):%s\n",mod[2]);
			}
		}
	} else {
		printf("3rd item is not module\n");
		exit(1);
	} 
	devnum++;
	next
}

# card config
$1 == "card" {
	card_flag = 1;
	match($0,/".*"/);
	cardname[cardnum] = substr($0,RSTART,RLENGTH);
	if (debug) {
		printf("D:card(%d) %s\n",cardnum,cardname[cardnum]);
	}
	ano_num[cardnum] = 0;
	tuple_num[cardnum] = 0;
	version_num[cardnum] = 0;
	man_num[cardnum] = 0;
	cis_num[cardnum] = 0;
	pci_num[cardnum] = 0;
	func_num[cardnum] = 0;
	pre_cardnum = cardnum;
	cardnum++;
	next;
}
$1 == "anonymous" {
	check_flag(card_flag,"card flag is invalid\n");
	ano_num[pre_cardnum] = 1;
	next;
}
$1 == "tuple" {
	check_flag(card_flag,"card flag is invalid\n");
	tuple_num[pre_cardnum] = 1;
	next;
}
$1 == "function" {
	check_flag(card_flag,"card flag is invalid\n");
	func_num[pre_cardnum] = 1;
	funcname[pre_cardnum] = $2;
	if (debug) {
		printf("D:card(%d):f=%s\n",funcname[pre_cardnum]);
	}
}
$1 == "version" {
	check_flag(card_flag,"card flag is invalid\n");
	match($0,/".*"/);
	ss = substr($0,RSTART,RLENGTH);
	gsub(/", "/,"\"@\"",ss);
	version_num[pre_cardnum] = split(ss,ver,"@");
	if (version_num[pre_cardnum] >= 1) {
		version_1[pre_cardnum] = ver[1];
		debug_version(pre_cardnum,version_1[pre_cardnum]);
		if (version_num[pre_cardnum] >= 2) {
			version_2[pre_cardnum] = ver[2];
			debug_version(pre_cardnum,version_2[pre_cardnum]);
			if (version_num[pre_cardnum] >= 3) {
				version_3[pre_cardnum] = ver[3];
				debug_version(pre_cardnum,version_3[pre_cardnum]);
				if (version_num[pre_cardnum] == 4) {
					version_4[pre_cardnum] = ver[4];
					debug_version(pre_cardnum,version_4[pre_cardnum]);
				}
			}
		}
	}
	next;
}
$1 == "manfid" {
	check_flag(card_flag,"card flag is invalid\n");
	man_num[pre_cardnum] = 1;
	man_1[pre_cardnum] = $2
	man_2[pre_cardnum] = $3
	if (debug) {
		printf("D:card(%d):m1=%s\n",
		pre_cardnum, man_1[pre_cardnum]);
		printf("D:card(%d):m2=%s\n",
		pre_cardnum, man_2[pre_cardnum]);
	}
	next;
}

$1 == "pci" {
	check_flag(card_flag,"card flag is invalid\n");
	pci_num[pre_cardnum] = 1;
	pci_1[pre_cardnum] = $2
	pci_2[pre_cardnum] = $3
	if (debug) {
		printf("D:card(%d):p1=%s\n",
		pre_cardnum, pci_1[pre_cardnum]);
		printf("D:card(%d):p2=%s\n",
		pre_cardnum, pci_2[pre_cardnum]);
	}
	next;
}

$1 == "cis" {
	check_flag(card_flag,"card flag is invalid\n");
	cis_num[pre_cardnum] = 1;
	match($0,/".*"/);
	cisname[pre_cardnum] = substr($0,RSTART,RLENGTH);
	if (debug) {
		printf("D:card(%d):c=%s\n", pre_cardnum, cisname[pre_cardnum]);
	}
	next;
}

$1 == "bind" {
	if (card_flag == 0) {
		printf("card flag is invalid\n");
		exit(1);
	}
	if (NF == 2) {
		bind_num[pre_cardnum] = 1;
		bind_1[pre_cardnum] = $2;
		if (debug) {
			printf("D:card(%d):b(1/1)=%s\n", pre_cardnum, bind_1[pre_cardnum]);
		}
	} else if (NF == 3) {
		bind_num[pre_cardnum] = 2;
		match($0,/".*"/);
		ss = substr($0,RSTART,RLENGTH);
		gsub(/", "/,"\"@\"",ss);
		split(ss,bin,"@");
		bind_1[pre_cardnum] = bin[1];
		bind_2[pre_cardnum] = bin[2];
		bind_to[pre_cardnum] = 0;
		if (debug) {
			printf("D:card(%d):b(1/2)=%s\n", pre_cardnum, bind_1[pre_cardnum]);
			printf("D:card(%d):b(2/2)=%s\n", pre_cardnum, bind_2[pre_cardnum]);
		}
	} else if (NF == 7) {
		bind_num[pre_cardnum] = 2;
		bind_1[pre_cardnum] = $2;
		bind_2[pre_cardnum] = $5;
		bind_to[pre_cardnum] = 1;
		if (debug) {
			printf("D:card(%d):b(1/2)=%s -> 0\n", pre_cardnum, bind_1[pre_cardnum]);
			printf("D:card(%d):b(2/2)=%s -> 1\n", pre_cardnum, bind_2[pre_cardnum]);
		}
	}
	next;
}

END {
	if (debug) {
		printf("CARD %d\n",cardnum);
	}
# header
	printf("# module match_flags args...\n");
# print manufacture ids and Version_1 infos
	printf("# Manufacture and Version1\n");
	for(i = 0;i < cardnum;i++) {
# skip
		if (tuple_num[i] || ano_num[i] || cis_num[i] || pci_num[i] || func_num[i] || bind_num[i] == 2)
			continue;
# module
		if (bind_num[i] == 1) {
			if (module_num[bind_num[i]] == 2) {
				continue;
			}
			gsub(/"/,"",bind_1[i]);
			printf("%s",bind_1[i]);
		}
# match_flag
		match_flag = 0;
		if (man_num[i] != 0) {
			match_flag = 1;
		}
		if (version_num[i] == 1) {
			match_flag += 2;
		} else if (version_num[i] == 2) {
			match_flag += 4;
		} else if (version_num[i] == 3) {
			match_flag += 6;
		} else if (version_num[i] == 4) {
			match_flag += 8;
		}
		printf("  0x%x",match_flag);
# manufacture
		if (man_num[i] != 0) {
			printf(" %s %s", man_1[i],man_2[i]);
		}
# version1
		if (version_num[i] >= 1) {
			printf(" %s",version_1[i]);
			if (version_num[i] >= 2) {
				printf(" %s",version_2[i]);
				if (version_num[i] >= 3) {
					printf(" %s",version_3[i]);
					if (version_num[i] == 4) {
						printf(" %s",version_4[i]);
					}
				}
			}
		}
		printf("\n");
	}
# print function ids
	printf("# Function\n");
	for(i = 0;i < cardnum;i++) {
		if (func_num[i]) {
# module
			if (bind_num[i] == 1) {
				if (module_num[bind_num[i]] == 2) {
					continue;
				}
				gsub(/"/,"",bind_1[i]);
				printf("%s",bind_1[i]);
			}
# match_flag
			match_flag = 1 * (2^4);

			printf("  0x%x 0x%x\n",
				match_flag,funcid[funcname[i]]);

		}
	}
}

