#!/usr/bin/awk -f

function gobble(s, x)
{
	sub(/^ /, "", line)
	match(line, "^" "(" s ")")
	x = substr(line, 1, RLENGTH)
	line = substr(line, RLENGTH+1)
	return x 
}

function convert(i, j, t)
{
	type = argtypes[i,j]
	name = argnames[i,j]
	opt  = optionals[i,j]
	tabs = x = ""

	for (i = 0; i < t; i++) { tabs = tabs "\t" }

	if (type == "int") {
		x = tabs "convert_to_long_ex(" name ext ");\n" \
			(ext? tabs name " = Z_LVAL_PP(" name ext ");\n": "")
		ints = ints "\tint " name ";\n"
	} else if (type == "bool") {
		x = tabs "convert_to_long_ex(" name ext ");\n" \
			(ext? tabs name " = Z_LVAL_PP(" name ext ");\n": "")
		ints = ints "\tint " name ";\n"
	} else if (type == "double") {
		x = tabs "convert_to_double_ex(" name ext ");\n" \
			(ext? tabs name " = Z_DVAL_PP(" name ext ");\n": "")
		doubles = doubles "\tdouble " name ";\n"
	} else if (type == "float") {
		x = tabs "convert_to_double_ex(" name ext ");\n" \
			(ext? tabs name " = (float) Z_DVAL_PP(" name ext ");\n": "")
		floats = floats "\tfloat " name ";\n"
	} else if (type == "string") {
		x = tabs "convert_to_string_ex(" name ext ");\n" \
			(ext? tabs name " = Z_STRVAL_PP(" name ext ");\n": "")
		(ext ? strings = strings "\tchar *" name " = NULL;\n" : 0)
			if (string_lens) {
				x = x tabs name "_len = Z_STRLEN_PP(" name ext ");\n"
				ints = ints "\tint " name "_len;\n"
			}
	} else if (type == "array") {
		x = "convert_to_array_ex(" name ext ");\n"
	} else if (type == "resource") {
		if (opt && i > -1) {
			resources = resources "\tif (argc < " j+1 ") {\n" \
				comment("\t\t/* Argument not given, do something before\n\t\t   trying to fetch resource " name ". */\n") \
				"\t}\n\tZEND_FETCH_RESOURCE(???, ???, " name ext ", " name "_id, \"???\", ???G());\n"
		} else {
			resources = resources "\tZEND_FETCH_RESOURCE(???, ???, " name ext ", " name "_id, \"???\", ???G());\n"
		}
		funcvals = funcvals "\tint " name "_id = -1;\n"
	} else {
		x = comment(tabs "/* Write your own code here to handle argument " name ". */\n")
	}

	if (x) return x
}

function comment(s)
{
	if (i_know_what_to_do_shut_up_i_dont_need_your_help_mode) {
		return
	} else {
		return s
	}
}

BEGIN {
	name = "[_A-Za-z][_A-Za-z0-9]*"
	type = "int|double|float|string|bool|array|object|resource|mixed|void"
	num_funcs = 0

	if (assign_params) ext = "_arg"

	if (xml && xml != "yes") {
		xmldoc = xml
	} else {
		xmldoc = extname "/" extname ".xml"
	}
			

	xmlhead = " <reference id=\"ref." extname "\">\n" \
		"  <title> functions</title>\n" \
		"  <titleabbrev></titleabbrev>\n\n" \
		"  <partintro>\n" \
    		"   <para>\n" \
    		"   </para\n" \
    		"  </partintro>\n\n";

	xmlfoot = " </reference>\n\n" \
		"<!-- Keep this comment at the end of the file\n" \
		"Local variables:\n" \
		"mode: sgml\n" \
		"sgml-omittag:t\n" \
		"sgml-shorttag:t\n" \
		"sgml-minimize-attributes:nil\n" \
		"sgml-always-quote-attributes:t\n" \
		"sgml-indent-step:1\n" \
		"sgml-indent-data:t\n" \
		"sgml-parent-document:nil\n" \
		"sgml-default-dtd-file:\"../../manual.ced\"\n" \
		"sgml-exposed-tags:nil\n" \
		"sgml-local-catalogs:nil\n" \
		"sgml-local-ecat-files:nil\n" \
		"End:\n" \
		"-->\n"
}

{
	args_max = args_min = optional = i = 0
	line = $0

	func_type = gobble(type);
	func_name = gobble(name);

	if (gobble("\\(")) {
		if (gobble("\\[")) optional = 1
		while (arg_type = gobble(type)) {
			arg_name = gobble(name)
			argtypes[num_funcs,args_max] = arg_type
			argnames[num_funcs,args_max] = arg_name

			args_max++
			if (optional) {
				optionals[num_funcs,i] = optional
				if (arg_type != "resource") {
					useswitch[num_funcs] = 1
				}
			} else {
					args_min++
			}

			if (x = gobble("\\[")) {
				optional++
			}

			y = gobble(",")
			if (!x && y && optional) {
				check_argc_in_switch[num_funcs] = 1
				grouped_optional_param[num_funcs,i] = 1
			}
			i++
		}
	}

	if (x = gobble("\\)")) {
		sub(/^[ \t]+/, "", line)
		fcomments[num_funcs] = line
	}

	funcs[num_funcs]   = func_name
	types[num_funcs]   = func_type
	maxargs[num_funcs] = args_max
	minargs[num_funcs] = args_min

	num_funcs++
}

END {
	if (xml) print xmlhead > xmldoc
	for (i = 0; i < num_funcs; i++) {
		
		compareargc = maxargs[i] - minargs[i]
		closefetch = xmlparams = funcvals = resources = handleargs = closeopts = ""
		ints = doubles = floats = strings = arrays = ""

		proto = "/* {{{ proto " types[i] " " funcs[i] "("


	 refid = funcs[i]
	 gsub(/_/, "-", refid)
	 xmlstr = "  <refentry id=\"function." refid "\">\n" \
		"   <refnamediv>\n" \
		"    <refname>" funcs[i] "</refname>\n" \
		"    <refpurpose>" fcomments[i] "</refpurpose>\n" \
		"   </refnamediv>\n" \
		"   <refsect1>\n" \
		"    <title>Description</title>\n" \
		"    <funcsynopsis>\n" \
		"     <funcprototype>\n" \
		"      <funcdef>" types[i] " <function>" funcs[i] "</function></funcdef>\n"

		if (maxargs[i]) {
			zvals = "\tzval "
			if (compareargc) {
				funcvals = "\tint argc;\n"
				if (minargs[i]) {
					fetchargs = "\targc = ZEND_NUM_ARGS();\n\tif (argc < " \
						minargs[i] " || argc > " maxargs[i] \
						" || zend_get_parameters_ex(argc, "
				} else {
					fetchargs = "\targc = ZEND_NUM_ARGS();\n\tif (argc > " \
						maxargs[i] " || (argc && zend_get_parameters_ex(argc, "
					closefetch = ")"
				}
			} else {
				fetchargs = "\tif (ZEND_NUM_ARGS() != " maxargs[i] \
					" || zend_get_parameters_ex(" maxargs[i] ", "
			}
		}

		for (j = 0; j < maxargs[i]; j++) {

			if (j) {
				zvals = zvals ", "
				fetchargs = fetchargs ", "
			}

			zvals = zvals "**" argnames[i,j] ext
			fetchargs = fetchargs "&" argnames[i,j] ext

			xmlparams = xmlparams "     <paramdef>" argtypes[i,j]
			if (j > minargs[i]-1) {
				if (!grouped_optional_param[i,j-1]) {
					if (j > 0) proto = proto " "
					proto = proto "["
					closeopts = closeopts "]"
				}
				xmlparams = xmlparams "\n      <parameter><optional>" \
					argnames[i,j] \
					"</optional></parameter>\n     </paramdef>\n"
			} else {
				xmlparams = xmlparams \
					" <parameter>" \
					argnames[i,j] \
					"</parameter></paramdef>\n"
			}

			if (j > 0) proto = proto ", "
			proto = proto argtypes[i,j] " " argnames[i,j]

			# Clean up this mess...

			if (useswitch[i]) {
				if (grouped_optional_param[i,j] && code) {
					handleargs = convert(i, j, 3) \
						((grouped_optional_param[i,j-1]) ? "" : comment("\t\t\t/* Fall-through. */\n")) \
						handleargs
				} else {
					if (j > minargs[i]-1) {
						if (code = convert(i, j, 3)) {
							handleargs = "\t\tcase " j+1 ":\n" code \
								((grouped_optional_param[i,j-1]) ? "" : comment("\t\t\t/* Fall-through. */\n")) \
								handleargs
						} else {
							handleargs = "\t\tcase " j+1 ":" \
							comment("\t/* Fall-through. */") \
							"\n" handleargs
						}
					} else if (j >= minargs[i]-1) {
						if (code = convert(i, j, 3)) {
							handleargs = "\t\tcase " j+1 ":\n" code handleargs
						} else {
							handleargs = "\t\tcase " j+1 ":\n" handleargs
						}
					} else {
						if (code = convert(i, j, 3)) handleargs = code handleargs
					}
				}
			} else {
				if (code = convert(i, j, 1)) handleargs = handleargs code
			}
		}

		proto = proto closeopts ")\n   " fcomments[i] " */\nPHP_FUNCTION(" funcs[i] ")\n{"
		if (maxargs[i]) {
			zvals = zvals ";"
			fetchargs = fetchargs ") == FAILURE)" closefetch "{\n\t\tWRONG_PARAM_COUNT;\n\t}\n"
		}
		if (assign_params) funcvals = ints doubles floats strings
		if (resources) funcvals = funcvals "\t???LS_FETCH();\n"
		if (useswitch[i]) {
			if (check_argc_in_switch[i]) {
				check_argc = "\t\tdefault:\n\t\t\tWRONG_PARAM_COUNT;\n"
			} else {
				check_argc = ""
			}
			handleargs = "\tswitch (argc) {\n" \
				handleargs \
				(minargs[i] ? "" : "\t\tcase 0:\n") \
				"\t\t\tbreak;\n" check_argc "\t}"
		}
		xmlstr = xmlstr xmlparams \
			"     </funcprototype>\n" \
			"    </funcsynopsis>\n" \
			"    <para>\n" \
			"    </para>\n" \
			"   </refsect1>\n" \
			"  </refentry>\n"

		print proto > stubfile
		if (zvals) print zvals > stubfile
 		if (funcvals) print funcvals > stubfile
		if (fetchargs) print fetchargs > stubfile
		if (resources) {
				print resources > stubfile
				if (!stubs) print "" > extname "/function_warning"
		}
		if (handleargs) print handleargs > stubfile
		if (!i_know_what_to_do_shut_up_i_dont_need_your_help_mode) {
			print "\n\tphp_error(E_WARNING, \"" funcs[i] ": not yet implemented\");" > stubfile
		}
		print "}\n/* }}} */\n" > stubfile

		if (stubs) {
			h_stubs = h_stubs "PHP_FUNCTION(" funcs[i] ");\n"
			c_stubs = c_stubs "\tPHP_FE(" funcs[i] ",\tNULL)\n"
		} else {
			print "PHP_FUNCTION(" funcs[i] ");" > extname "/function_declarations"
			print "\tPHP_FE(" funcs[i] ",\tNULL)" > extname "/function_entries"
		}

		if (xml) print xmlstr > xmldoc
	}

	if (stubs) {
		print "\n/* ----------------------------------------------------------- */\n" > stubfile
		print c_stubs > stubfile
		print "\n/* ----------------------------------------------------------- */\n" > stubfile
		print h_stubs > stubfile
	}

	if (xml) print xmlfoot > xmldoc
}

#
# Local variables:
# tab-width: 2
# c-basic-offset: 2
# End:

