interp_utils.awk	-- return "" if scale_type == log and v <= 0

function IU_init(config, interp, name,    key, work, n_ary, ary, i, v_pat, v_len) {

	interp["name"] = name

	# get the scale type (linear (default) and  log10 so far
	key = name ".scale_type"
	work = config["_globals", key]
	if(work == "")
		interp["scale_type"] = "linear"
	else if(work == "linear" || work == "log")
		interp["scale_type"] = work
	else{
		print("ERROR: IU_init: unknown scale_type: %s\n", key) > "/dev/stderr"
		return 1
	}

	# get the values
	key = name ".values"
	work = config["_globals", key]
	if(work == ""){
		printf("ERROR: IU_init: no key named \"%s\" in config\n", key) > "/dev/stderr"
		return 1
	}
	n_ary = split(work, ary, "|")
	interp["nvalues"] = n_ary
	interp["is_grad"] = 0
	interp["v_len"] = 0	# set only for grad elts
	for(i = 1; i <= n_ary; i++){
		sub(/^[ \t]*/, "", ary[i])
		sub(/[ \t]*$/, "", ary[i])
		if(index(ary[i], ":") != 0){
			interp["is_grad"] = 1
			v_pat = v_pat "g"
			v_len = IU_check_grad(ary[i])
			if(v_len == 0){
				printf("ERROR: IU_init: IU_check_grad failed for value %d (%s)\n", i, ary[i]) > "/dev/stderr"
				return 1
			}else if(interp["v_len"] == 0){
				interp["v_len"] = v_len
			}else if(v_len != interp["v_len"]){
				printf("ERROR: IU_init: v_len (%d) for value %d (%s) differs from current v_len (%d)\n", v_len, i, ary[i], interp["v_len"]) > "/dev/stderr"
				return 1
			}
		}else
			v_pat = v_pat "b"
		interp["values", i] = ary[i]
	}

	# get the breaks
	key = name ".breaks"
	work = config["_globals", key]
	if(work == ""){
		printf("ERROR: IU_init: no key named \"%s\" in config\n", key) > "/dev/stderr"
		return 1
	}
	n_ary = split(work, ary, "|")
	interp["nbreaks"] = n_ary
	for(i = 1; i <= n_ary; i++){
		sub(/^[ \t]*/, "", ary[i])
		sub(/[ \t]*$/, "", ary[i])
		interp["breaks", i] = ary[i] + 0	# force numeric
	}
	if(!interp["is_grad"]){
		if(interp["nbreaks"] != interp["nvalues"] - 1){
			printf("ERROR: IU_init: nbreaks (%d) != nvalues - 1 (%d)\n", interp["nbreaks"], interp["nvalues"] - 1) > "/dev/stderr"
			return 1
		}
	}else if(interp["nbreaks"] == interp["nvalues"] + 1){
		if(!match(v_pat, /^gg*$/)){
			printf("ERROR: IU_init: nbreaks (%d) = nvalues + 1 (%d): all values must be gradients\n", interp["nbreaks"], interp["nvalues"] + 1) > "/dev/stderr"
			return 1
		}
		interp["v_ob_info"] = ""
	}else if(interp["nbreaks"] == interp["nvalues"]){
		if(!match(v_pat, /^bgg*$/) && !match(v_pat, /^gg*b$/)){
			printf("ERROR: IU_init: nbreaks (%d) = nvalues (%d): All but first or last, but not both values must grad\n", interp["nbreaks"], interp["nvalues"]) > "/dev/stderr"
			return 1
		}
		interp["v_ob_info"] = v_pat ~ /^b/ ? "^" : "$"
	}else if(interp["nbreaks"] == interp["nvalues"] - 1){
		printf("DEBUG: IU_init: nb = nv - 1: chk that we have v[1] = bin, v[2:$-1] = grad, v[$] = bin\n") > "/dev/stderr"
		if(!match(v_pat, /^bgg*b$/)){
			printf("ERROR: IU_init: nbreaks (%d) = nvalues - 1 (%d): all values but first and last must be grad\n", interp["nbreaks"], interp["nvalues"] - 1) > "/dev/stderr"
			return 1
		}
		interp["v_ob_info"] = "^$"
	}else{
		printf("ERROR: IU_init: bad nbreaks (%d), legal values are (%d, %d, %d)\n", interp["nbreaks"], interp["nvalues"] - 1, interp["nvalues"], interp["nvalues"] + 1) > "/dev/stderr"
		return 1
	}

	# check that breaks are strictly ascending, insures interp denoms are > 0
	for(i = 2; i <= interp["nbreaks"]; i++){
		if(interp["breaks", i] <= interp["breaks", i-1]){
			printf("ERROR: IU_init: breaks must be strictly ascending: breaks[%d] (%g) <= breaks[%d] (%g)\n", i-1, interp["breaks", i-1], i, interp["breaks", i]) > "/dev/stderr"
			return 1
		}
	}

	# check for any exceptions
	key = name ".exceptions"
	work = config["_globals", key]
	if(work != ""){
		if(IU_parse_exceptions(interp, work))
			return 1
	}

	# init all counts to 0
	for(i = 0; i <= interp["nbreaks"] + 1; i++)
		interp["counts", i] = 0
	interp["tcounts"] = 0

	return 0
}

function IU_check_grad(grad,   v_len, n_ary, ary, i, n_ary2, ary2, j) {

	v_len = 0
	n_ary = split(grad, ary, ":")
	if(n_ary != 2){
		printf("ERROR: IU_check_grad: grad %s has %d fields, must have %d\n", grad, n_ary, 2) > "/dev/stderr"
		return 0
	}
	for(i = 1; i <= n_ary; i++){
		n_ary2 = split(ary[i], ary2, ",")
		if(v_len == 0)
			v_len = n_ary2
		else if(n_ary2 != v_len){
			printf("ERROR: IU_check_grad: vector %s has %d elements, must have %d\n", ary[i], n_ary2, v_len) > "/dev/stderr"
			return 0
		}
	}

	return v_len
}

function IU_parse_exceptions(interp, str,   err, n_ary, ary, i, colon, cond, op, opnd, value) {

	err = 0
	interp["exceptions"] = str
	n_ary = split(str, ary, "|")
	for(i = 1; i <= n_ary; i++){
		sub(/^  */, "", ary[i])
		sub(/  *$/, "", ary[i])
	}
	interp["nexceptions"] = n_ary
	for(i = 1; i <= n_ary; i++){
		colon = index(ary[i], ":")
		if(colon == 0){
			printf("ERROR: IU_parse_exception: no colon: %s\n", ary[i]) > "/dev/stderr"
			return 1
		}
		cond = substr(ary[i], 1, colon - 1)
		sub(/^  */, "", cond)
		sub(/  *$/, "", cond)
		if(cond == ""){
			printf("ERROR: IU_parse_exception: empty condition: %s\n", ary[i]) > "/dev/stderr"
			return 1
		}
		# op can be <=, <, ==, !=, >=, >
		op = substr(cond, 1, 2)
		if(op == "<=" || op == "==" || op == "!=" || op == ">="){
			opnd = substr(cond, 3)
		}else{
			op = substr(op, 1, 1)
			if(op == "<" || op == ">")
				opnd = substr(cond, 2)
			else{
				printf("ERROR: IU_parse_exception: unknown operator \"%s\"\n", cond) > "/dev/stderr"
				return 1
			}
		}
		sub(/^  */, "", opnd)
		sub(/  *$/, "", opnd)
		if(cond == ""){
			print("ERROR: IU_parse_exception: exception %d: %s: empty operand %s\n", i, ary[i]) > "/dev/stderr"
			return 1
		}

		value = substr(ary[i], colon + 1)
		sub(/^  */, "", value)
		sub(/  *$/, "", value)
		# TODO? value can be empty, is this OK?

		interp["exceptions", i, "op"] = op
		interp["exceptions", i, "opnd"] = opnd + 0 # force numeric
		interp["exceptions", i, "value"] = value
		interp["ecounts", i] = 0
	}
	return err
}

function IU_dump(file, interp,   i, keys, nk) {

	printf("interp = {\n") > file
	printf("\tname          = %s\n", interp["name"]) > file
	printf("\tscale_type    = %s\n", interp["scale_type"]) > file
	printf("\tis_grad       = %d\n", interp["is_grad"]) > file
	printf("\tv_ob_info     = %s\n", interp["v_ob_info"]) > file
	printf("\tv_len         = %d\n", interp["v_len"]) > file
	printf("\tnvalues       = %d\n", interp["nvalues"]) > file
	printf("\tvalues        = %s", interp["values", 1]) > file
	for(i = 2; i <= interp["nvalues"]; i++)
		printf(" | %s", interp["values", i]) > file
	printf("\n") > file
	printf("\tnbreaks       = %d\n", interp["nbreaks"]) > file
	printf("\tbreaks        = %s", interp["breaks", 1]) > file
	for(i = 2; i <= interp["nbreaks"]; i++)
		printf(" | %s", interp["breaks", i]) > file
	printf("\n") > file
	printf("\ttcounts       = %d\n", interp["tcounts"]) > file
	printf("\tcounts        = %d", interp["counts", 1]) > file
	for(i = 2; i <= interp["nbreaks"] + 1; i++)
		printf(" | %d", interp["counts", i]) > file
	printf("\n") > file
	if(!("exceptions" in interp))
		printf("\texceptions    =\n") > file
	else{
		printf("\texceptions    = %d {\n", interp["nexceptions"]) > file
		for(i = 1; i <= interp["nexceptions"]; i++)
			printf("\t\t%d = %s | %s | %s\n", i, interp["exceptions", i, "op"], interp["exceptions", i, "opnd"], interp["exceptions", i, "value"]) > file
		printf("\t}\n") > file
		printf("\tecounts       = %d", interp["ecounts", 1]) > file
		for(i = 2; i <= interp["nexceptions"]; i++)
			printf(" | %d", interp["ecounts", i]) > file
		printf("\n") > file
	}

	printf("}\n") > file
}

function IU_interpolate(interp, v,   ev, idx, work, n_ary, ary, i) {

	if("exceptions" in interp){
		ev = IU_handle_exceptions(interp, v)
		if(ev != "")
			return ev
	}else if(interp["scale_type"] == "log"){
		if(v <= 0)
			return ""
	}

	idx = IU_search(interp, v)
	interp["tcounts"]++
	interp["counts", idx]++
	if(!interp["is_grad"]){
		return interp["values", idx]
	}else{
		# nbreaks = nvalues - 1
		if(interp["v_ob_info"]  == ""){	# ^gg*$, take out of bounds values from first and last grad elemnt
			if(idx == 1){
				work = interp["values", 1]
				n_ary = split(work, ary, ":")
				return ary[1]
			}else if(idx == interp["nbreaks"] + 1){
				work = interp["values", interp["nvalues"]]
				n_ary = split(work, ary, ":")
				return ary[2]
			}else
				return IU_interpolate_grad(interp, interp["values", idx - 1], v, interp["breaks", idx - 1], interp["breaks", idx])
		}else if(interp["v_ob_info"] == "^"){	# ^bgg*$, lower out of bounds specified, take higher ob from last grad element
			if(idx == 1)
				return interp["values", 1]
			else if(idx == interp["nbreaks"] + 1){
				work = interp["values", interp["nvalues"]]
				n_ary = split(work, ary, ":")
				return ary[2]
			}else
				return IU_interpolate_grad(interp, interp["values", idx], v, interp["breaks", idx], interp["breaks", idx + 1])
		}else if(interp["v_ob_info"] == "$"){	# ^gg*b$, upper out of bounds specified, take lower ob from first grad element
			if(idx == 1){
				work = interp["values", 1]
				n_ary = split(work, ary, ":")
				return ary[1]
			}else if(idx == interp["nbreaks"] + 1)
				return interp["values", idx - 1]
			else
				return IU_interpolate_grad(interp, interp["values", idx - 1], v, interp["breaks", idx - 1], interp["breaks", idx])
		}else{	# ^bgg*b$, lower & upper ob info specified
			if(idx == 1 || idx == interp["nbreaks"] + 1)
				return interp["values", idx]
			else
				return IU_interpolate_grad(interp, interp["values", idx], v, interp["breaks", idx], interp["breaks", idx + 1])
		}
	}
}

function IU_handle_exceptions(interp, v,   i, hit) {

	for(i = 1; i <= interp["nexceptions"]; i++){
		hit = ""
		if(interp["exceptions", i, "op"] == "<"){
			if(v < interp["exceptions", i, "opnd"])
				hit = "<"
		}else if(interp["exceptions", i, "op"] == "<="){
			if(v <= interp["exceptions", i, "opnd"])
				hit = "<="
		}else if(interp["exceptions", i, "op"] == "=="){
			if(v == interp["exceptions", i, "opnd"])
				hit = "=="
		}else if(interp["exceptions", i, "op"] == "!="){
			if(v != interp["exceptions", i, "opnd"])
				hit = "!="
		}else if(interp["exceptions", i, "op"] == ">="){
			if(v >= interp["exceptions", i, "opnd"])
				hit = ">="
		}else if(v >= interp["exceptions", i, "opnd"])
			hit = ">"
		if(hit){
			interp["ecounts", i]++
			interp["tcounts"]++
			return interp["exceptions", i, "value"]
		}
	}

	return ""
}

function IU_interpolate_grad(interp, grad, v, v_min, v_max,   n_ary, ary, n_ary2, ary2, i, g_min, g_max, f, rstr) {

	# grad is well formed or IU_init() would have failed
	n_ary = split(grad, ary, ":")
	n_ary2 = split(ary[1], ary2, ",")
	for(i = 1; i <= n_ary2; i++)
		g_min[i] = ary2[i] + 0	# force numeric
	n_ary2 = split(ary[2], ary2, ",")
	for(i = 1; i <= n_ary2; i++)
		g_max[i] = ary2[i] + 0	# force numeric

	# other scales may be possible but for now
	if(interp["scale_type"] == "log"){
		log10 = log(10)
		v = log(v)/log10
		v_min = log(v_min)/log10
		v_max = log(v_max)/log10
	}

	f = (v - v_min) / (v_max - v_min)	# safe b/c IU_init() checked that v_max > v_min
	rstr = ""
	for(i = 1; i <= n_ary2; i++){
		rstr = rstr ((i > 1) ? "," : "") sprintf("%g", g_min[i] + f * (g_max[i] - g_min[i]))
	}
	return rstr
}

function IU_search(interp, v,   i, j, k, cv) {

	# deal with out of range values here to simplify the binary interval search
	if(v <= interp["breaks", 1])
		return 1
	else if(v > interp["breaks", interp["nbreaks"]])
		return interp["nbreaks"] + 1

	# binary search on intervals
	i = 1 ; j = interp["nbreaks"];
	for( ; i <= j ; ){
		k = int((i+j)/2)
		if(v == interp["breaks", k]){
			return k
		}else if(v < interp["breaks", k]){
			if(v > interp["breaks", k-1])
				return k
			j = k - 1
		}else{
			if(v <= interp["breaks", k+1])
				return k + 1
			i = k + 1
		}
	}
	# should never get here!
	return 0
}

function IU_init(config, interp, name,    key, work, n_ary, ary, i, v_pat, v_len) {

	interp["name"] = name

	# get the scale type (linear (default) and  log10 so far
	key = name ".scale_type"
	work = config["_globals", key]
	if(work == "")
		interp["scale_type"] = "linear"
	else if(work == "linear" || work == "log")
		interp["scale_type"] = work
	else{
		print("ERROR: IU_init: unknown scale_type: %s\n", key) > "/dev/stderr"
		return 1
	}

	# get the values
	key = name ".values"
	work = config["_globals", key]
	if(work == ""){
		printf("ERROR: IU_init: no key named \"%s\" in config\n", key) > "/dev/stderr"
		return 1
	}
	n_ary = split(work, ary, "|")
	interp["nvalues"] = n_ary
	interp["is_grad"] = 0
	interp["v_len"] = 0	# set only for grad elts
	for(i = 1; i <= n_ary; i++){
		sub(/^[ \t]*/, "", ary[i])
		sub(/[ \t]*$/, "", ary[i])
		if(index(ary[i], ":") != 0){
			interp["is_grad"] = 1
			v_pat = v_pat "g"
			v_len = IU_check_grad(ary[i])
			if(v_len == 0){
				printf("ERROR: IU_init: IU_check_grad failed for value %d (%s)\n", i, ary[i]) > "/dev/stderr"
				return 1
			}else if(interp["v_len"] == 0){
				interp["v_len"] = v_len
			}else if(v_len != interp["v_len"]){
				printf("ERROR: IU_init: v_len (%d) for value %d (%s) differs from current v_len (%d)\n", v_len, i, ary[i], interp["v_len"]) > "/dev/stderr"
				return 1
			}
		}else
			v_pat = v_pat "b"
		interp["values", i] = ary[i]
	}

	# get the breaks
	key = name ".breaks"
	work = config["_globals", key]
	if(work == ""){
		printf("ERROR: IU_init: no key named \"%s\" in config\n", key) > "/dev/stderr"
		return 1
	}
	n_ary = split(work, ary, "|")
	interp["nbreaks"] = n_ary
	for(i = 1; i <= n_ary; i++){
		sub(/^[ \t]*/, "", ary[i])
		sub(/[ \t]*$/, "", ary[i])
		interp["breaks", i] = ary[i] + 0	# force numeric
	}
	if(!interp["is_grad"]){
		if(interp["nbreaks"] != interp["nvalues"] - 1){
			printf("ERROR: IU_init: nbreaks (%d) != nvalues - 1 (%d)\n", interp["nbreaks"], interp["nvalues"] - 1) > "/dev/stderr"
			return 1
		}
	}else if(interp["nbreaks"] == interp["nvalues"] + 1){
		if(!match(v_pat, /^gg*$/)){
			printf("ERROR: IU_init: nbreaks (%d) = nvalues + 1 (%d): all values must be gradients\n", interp["nbreaks"], interp["nvalues"] + 1) > "/dev/stderr"
			return 1
		}
		interp["v_ob_info"] = ""
	}else if(interp["nbreaks"] == interp["nvalues"]){
		if(!match(v_pat, /^bgg*$/) && !match(v_pat, /^gg*b$/)){
			printf("ERROR: IU_init: nbreaks (%d) = nvalues (%d): All but first or last, but not both values must grad\n", interp["nbreaks"], interp["nvalues"]) > "/dev/stderr"
			return 1
		}
		interp["v_ob_info"] = v_pat ~ /^b/ ? "^" : "$"
	}else if(interp["nbreaks"] == interp["nvalues"] - 1){
		printf("DEBUG: IU_init: nb = nv - 1: chk that we have v[1] = bin, v[2:$-1] = grad, v[$] = bin\n") > "/dev/stderr"
		if(!match(v_pat, /^bgg*b$/)){
			printf("ERROR: IU_init: nbreaks (%d) = nvalues - 1 (%d): all values but first and last must be grad\n", interp["nbreaks"], interp["nvalues"] - 1) > "/dev/stderr"
			return 1
		}
		interp["v_ob_info"] = "^$"
	}else{
		printf("ERROR: IU_init: bad nbreaks (%d), legal values are (%d, %d, %d)\n", interp["nbreaks"], interp["nvalues"] - 1, interp["nvalues"], interp["nvalues"] + 1) > "/dev/stderr"
		return 1
	}

	# check that breaks are strictly ascending, insures interp denoms are > 0
	for(i = 2; i <= interp["nbreaks"]; i++){
		if(interp["breaks", i] <= interp["breaks", i-1]){
			printf("ERROR: IU_init: breaks must be strictly ascending: breaks[%d] (%g) <= breaks[%d] (%g)\n", i-1, interp["breaks", i-1], i, interp["breaks", i]) > "/dev/stderr"
			return 1
		}
	}

	# check for any exceptions
	key = name ".exceptions"
	work = config["_globals", key]
	if(work != ""){
		if(IU_parse_exceptions(interp, work))
			return 1
	}

	# init all counts to 0
	for(i = 0; i <= interp["nbreaks"] + 1; i++)
		interp["counts", i] = 0
	interp["tcounts"] = 0

	return 0
}

function IU_check_grad(grad,   v_len, n_ary, ary, i, n_ary2, ary2, j) {

	v_len = 0
	n_ary = split(grad, ary, ":")
	if(n_ary != 2){
		printf("ERROR: IU_check_grad: grad %s has %d fields, must have %d\n", grad, n_ary, 2) > "/dev/stderr"
		return 0
	}
	for(i = 1; i <= n_ary; i++){
		n_ary2 = split(ary[i], ary2, ",")
		if(v_len == 0)
			v_len = n_ary2
		else if(n_ary2 != v_len){
			printf("ERROR: IU_check_grad: vector %s has %d elements, must have %d\n", ary[i], n_ary2, v_len) > "/dev/stderr"
			return 0
		}
	}

	return v_len
}

function IU_parse_exceptions(interp, str,   err, n_ary, ary, i, colon, cond, op, opnd, value) {

	err = 0
	interp["exceptions"] = str
	n_ary = split(str, ary, "|")
	for(i = 1; i <= n_ary; i++){
		sub(/^  */, "", ary[i])
		sub(/  *$/, "", ary[i])
	}
	interp["nexceptions"] = n_ary
	for(i = 1; i <= n_ary; i++){
		colon = index(ary[i], ":")
		if(colon == 0){
			printf("ERROR: IU_parse_exception: no colon: %s\n", ary[i]) > "/dev/stderr"
			return 1
		}
		cond = substr(ary[i], 1, colon - 1)
		sub(/^  */, "", cond)
		sub(/  *$/, "", cond)
		if(cond == ""){
			printf("ERROR: IU_parse_exception: empty condition: %s\n", ary[i]) > "/dev/stderr"
			return 1
		}
		# op can be <=, <, ==, !=, >=, >
		op = substr(cond, 1, 2)
		if(op == "<=" || op == "==" || op == "!=" || op == ">="){
			opnd = substr(cond, 3)
		}else{
			op = substr(op, 1, 1)
			if(op == "<" || op == ">")
				opnd = substr(cond, 2)
			else{
				printf("ERROR: IU_parse_exception: unknown operator \"%s\"\n", cond) > "/dev/stderr"
				return 1
			}
		}
		sub(/^  */, "", opnd)
		sub(/  *$/, "", opnd)
		if(cond == ""){
			print("ERROR: IU_parse_exception: exception %d: %s: empty operand %s\n", i, ary[i]) > "/dev/stderr"
			return 1
		}

		value = substr(ary[i], colon + 1)
		sub(/^  */, "", value)
		sub(/  *$/, "", value)
		# TODO? value can be empty, is this OK?

		interp["exceptions", i, "op"] = op
		interp["exceptions", i, "opnd"] = opnd + 0 # force numeric
		interp["exceptions", i, "value"] = value
		interp["ecounts", i] = 0
	}
	return err
}

function IU_dump(file, interp,   i, keys, nk) {

	printf("interp = {\n") > file
	printf("\tname          = %s\n", interp["name"]) > file
	printf("\tscale_type    = %s\n", interp["scale_type"]) > file
	printf("\tis_grad       = %d\n", interp["is_grad"]) > file
	printf("\tv_ob_info     = %s\n", interp["v_ob_info"]) > file
	printf("\tv_len         = %d\n", interp["v_len"]) > file
	printf("\tnvalues       = %d\n", interp["nvalues"]) > file
	printf("\tvalues        = %s", interp["values", 1]) > file
	for(i = 2; i <= interp["nvalues"]; i++)
		printf(" | %s", interp["values", i]) > file
	printf("\n") > file
	printf("\tnbreaks       = %d\n", interp["nbreaks"]) > file
	printf("\tbreaks        = %s", interp["breaks", 1]) > file
	for(i = 2; i <= interp["nbreaks"]; i++)
		printf(" | %s", interp["breaks", i]) > file
	printf("\n") > file
	printf("\ttcounts       = %d\n", interp["tcounts"]) > file
	printf("\tcounts        = %d", interp["counts", 1]) > file
	for(i = 2; i <= interp["nbreaks"] + 1; i++)
		printf(" | %d", interp["counts", i]) > file
	printf("\n") > file
	if(!("exceptions" in interp))
		printf("\texceptions    =\n") > file
	else{
		printf("\texceptions    = %d {\n", interp["nexceptions"]) > file
		for(i = 1; i <= interp["nexceptions"]; i++)
			printf("\t\t%d = %s | %s | %s\n", i, interp["exceptions", i, "op"], interp["exceptions", i, "opnd"], interp["exceptions", i, "value"]) > file
		printf("\t}\n") > file
		printf("\tecounts       = %d", interp["ecounts", 1]) > file
		for(i = 2; i <= interp["nexceptions"]; i++)
			printf(" | %d", interp["ecounts", i]) > file
		printf("\n") > file
	}

	printf("}\n") > file
}

function IU_interpolate(interp, v,   ev, idx, work, n_ary, ary, i) {

	if("exceptions" in interp){
		ev = IU_handle_exceptions(interp, v)
		if(ev != "")
			return ev
	}

	idx = IU_search(interp, v)
	interp["tcounts"]++
	interp["counts", idx]++
	if(!interp["is_grad"]){
		return interp["values", idx]
	}else{
		# nbreaks = nvalues - 1
		if(interp["v_ob_info"]  == ""){	# ^gg*$, take out of bounds values from first and last grad elemnt
			if(idx == 1){
				work = interp["values", 1]
				n_ary = split(work, ary, ":")
				return ary[1]
			}else if(idx == interp["nbreaks"] + 1){
				work = interp["values", interp["nvalues"]]
				n_ary = split(work, ary, ":")
				return ary[2]
			}else
				return IU_interpolate_grad(interp, interp["values", idx - 1], v, interp["breaks", idx - 1], interp["breaks", idx])
		}else if(interp["v_ob_info"] == "^"){	# ^bgg*$, lower out of bounds specified, take higher ob from last grad element
			if(idx == 1)
				return interp["values", 1]
			else if(idx == interp["nbreaks"] + 1){
				work = interp["values", interp["nvalues"]]
				n_ary = split(work, ary, ":")
				return ary[2]
			}else
				return IU_interpolate_grad(interp, interp["values", idx], v, interp["breaks", idx], interp["breaks", idx + 1])
		}else if(interp["v_ob_info"] == "$"){	# ^gg*b$, upper out of bounds specified, take lower ob from first grad element
			if(idx == 1){
				work = interp["values", 1]
				n_ary = split(work, ary, ":")
				return ary[1]
			}else if(idx == interp["nbreaks"] + 1)
				return interp["values", idx - 1]
			else
				return IU_interpolate_grad(interp, interp["values", idx - 1], v, interp["breaks", idx - 1], interp["breaks", idx])
		}else{	# ^bgg*b$, lower & upper ob info specified
			if(idx == 1 || idx == interp["nbreaks"] + 1)
				return interp["values", idx]
			else
				return IU_interpolate_grad(interp, interp["values", idx], v, interp["breaks", idx], interp["breaks", idx + 1])
		}
	}
}

function IU_handle_exceptions(interp, v,   i, hit) {

	for(i = 1; i <= interp["nexceptions"]; i++){
		hit = ""
		if(interp["exceptions", i, "op"] == "<"){
			if(v < interp["exceptions", i, "opnd"])
				hit = "<"
		}else if(interp["exceptions", i, "op"] == "<="){
			if(v <= interp["exceptions", i, "opnd"])
				hit = "<="
		}else if(interp["exceptions", i, "op"] == "=="){
			if(v == interp["exceptions", i, "opnd"])
				hit = "=="
		}else if(interp["exceptions", i, "op"] == "!="){
			if(v != interp["exceptions", i, "opnd"])
				hit = "!="
		}else if(interp["exceptions", i, "op"] == ">="){
			if(v >= interp["exceptions", i, "opnd"])
				hit = ">="
		}else if(v >= interp["exceptions", i, "opnd"])
			hit = ">"
		if(hit){
			interp["ecounts", i]++
			interp["tcounts"]++
			return interp["exceptions", i, "value"]
		}
	}

	return ""
}

function IU_interpolate_grad(interp, grad, v, v_min, v_max,   n_ary, ary, n_ary2, ary2, i, g_min, g_max, f, rstr) {

	# grad is well formed or IU_init() would have failed
	n_ary = split(grad, ary, ":")
	n_ary2 = split(ary[1], ary2, ",")
	for(i = 1; i <= n_ary2; i++)
		g_min[i] = ary2[i] + 0	# force numeric
	n_ary2 = split(ary[2], ary2, ",")
	for(i = 1; i <= n_ary2; i++)
		g_max[i] = ary2[i] + 0	# force numeric

	# other scales may be possible but for now
	if(interp["scale_type"] == "log"){
		log10 = log(10)
		v = log(v)/log10
		v_min = log(v_min)/log10
		v_max = log(v_max)/log10
	}

	f = (v - v_min) / (v_max - v_min)	# safe b/c IU_init() checked that v_max > v_min
	rstr = ""
	for(i = 1; i <= n_ary2; i++){
		rstr = rstr ((i > 1) ? "," : "") sprintf("%g", g_min[i] + f * (g_max[i] - g_min[i]))
	}
	return rstr
}

function IU_search(interp, v,   i, j, k, cv) {

	# deal with out of range values here to simplify the binary interval search
	if(v <= interp["breaks", 1])
		return 1
	else if(v > interp["breaks", interp["nbreaks"]])
		return interp["nbreaks"] + 1

	# binary search on intervals
	i = 1 ; j = interp["nbreaks"];
	for( ; i <= j ; ){
		k = int((i+j)/2)
		if(v == interp["breaks", k]){
			return k
		}else if(v < interp["breaks", k]){
			if(v > interp["breaks", k-1])
				return k
			j = k - 1
		}else{
			if(v <= interp["breaks", k+1])
				return k + 1
			i = k + 1
		}
	}
	# should never get here!
	return 0
}


Do not use double underscores to escape underscores.

C and C++ reserve macro names containing adjacent underscores.

"Each name that contains a double underscore (__) or begins with an
 underscore followed by an uppercase letter (2.11) is reserved to
 the implementation for any use."
-- C++ 2003, 17.4.3.1.2 Global names [lib.global.names] (via StackOverflow)

#!/bin/awk
#
# Copyright (c) 2014, Michal Policht. This file is dually licensed under terms of
# either WTFPL or BEER-WARE LICENSE. You may obtain the copy of WTFPL or BEER-WARE
# LICENSE in nearest drug store.
#
# THIS SOFTWARE IS ADDICTED TO DRUGS AND ALCOHOL AND IS A SUSPECT OF DRIVING UNDER THE
# INFLUENCE OF ALCOHOL. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS NOT" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS AND APPLICATION AND
# ACCOMODATION FOR A PARTICULAR PURPOSE AND MANY OTHERS NOT MENTIONED, NOR EVEN
# INVENTED WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
# OR CONTRIBUTORS BE LIABLE FOR ANY TEMPORAL, PERMANENT, UNFORTUNATE, UNLUCKY,
# LUCKY, DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ACCIDENTAL, MENTAL,
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION;
# OR BEING KILLED BY A LIGHTNING; OR FLOOD; OR FIRE; OR ANTEATER (INCLUDING BUT NOT
# LIMITED TO, GIANT ANTEATER, ANTEATER WHO LIES ON A SOFA; ANTEATER WHO LISTENS HEAVY
# METAL MUSIC; ANTEATER WHO ATE HUMAN BEFORE) OR ANOTHER BEING.) HOWEVER CAUSED AND ON
# ANY, ANY THEORY OF LIABILITY, CONSPIRACY THEORY, ANY THEORY OF RELATIVITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
# WAY OUT OF THE USE OF THIS SOFTWARE, ARISING IN ANY WAY OUT OF THE SUN, EVEN IF PROMISSED
# WISHED OR ASSURED SUCH DAMAGE. THIS SOFTWARE CAN REALLY DO TERRIBLE THINGS.
#
# Script updates C/C++ include guards with macros based on header path (including directory structure).
# It seeks for "#ifndef, #define" pair and substitutes first encountered pair with generated values.
# Script does not distinguish include guards from other macros, so each HEADER FILE MUST CONTAIN
# INCLUDE GUARD AS ITS FIRST "#ifndef, #define" MACRO PAIR. Script only updates include guards;
# if file does not contain something that looks like include guard to the script it will not add one.
# Script will also eat everything after last "#endif", presumably include guard comment. It's a stupid
# beast, so always backup your data before use.
#
# usage: awk [-v prefix="PREFIX"] -f awkgward.awk header
# example: awk -v prefix="PROJECT_" -f awkgward.awk file.hpp
#
# parameters:
# header - header file.
#
# required tools: awk.

function create_guard_macro(prefix, filename)
{
    escaped_underscores = toupper(filename);
    # Just in case, escape single underscores.
    gsub(/_/, "_u_", escaped_underscores);
    # \/ = slash (/), \. = dot (.), \\ = backslash (\) - replace them with underscore.
    gsub(/[\/\.\\]/, "_", escaped_underscores);
    return prefix escaped_underscores;
}

function create_guard(prefix, filename)
{
    guard_macro = create_guard_macro(prefix, filename);
    guard = "#ifndef " guard_macro ORS "#define " guard_macro;
    return guard;
}

function print_or_buf(line)
{
    if (global_buf_mode)
        global_buf = global_buf line ORS;
    else
        print line;
}

BEGIN {
    S_START = 0;
    S_FIRST_IFNDEF = 1;
    S_END = 2;

    if (!prefix)
        prefix = "";

    global_buf = "";
    global_buf_mode = 0;
    endif_line = "";

    ifndef_buf = "";
    # simple automata:
    # S_START            /^#ifndef\s.*/  -> S_FIRST_IFNDEF     /^#define\s.*/ -> S_END     // -> S_START
    # S_FIRST_IFNDEF     /^#define\s.*/ -> S_END
    # S_END              // -> S_END
    state = S_START;
}

/^#ifndef[\t ].*/ {
    if (state == S_START) {
        ifndef_buf = $0;
        state = S_FIRST_IFNDEF;
        next;
    }
}

/^#define[\t ].*/ {
    if (state == S_FIRST_IFNDEF) {
        #eat old guard and replace it with new one
        print_or_buf(create_guard(prefix, FILENAME));
        state = S_END;
        next;
    }
    if (state == S_START)
        state = S_END;
}

/^#endif[\t ].*/ {
    #flush old buffer and whatever was in endif line
    if (global_buf_mode) {
        print endif_line;
        printf global_buf;
        global_buf = "";
    }
    endif_line = $0;
    global_buf_mode = 1;
    next;
}

{
    if (state == S_END || state == S_START)
        print_or_buf($0);
    if (state == S_FIRST_IFNDEF) {
        print_or_buf(ifndef_buf);
        print_or_buf($0);
        state = S_END;
    }
}

END {
    if (global_buf_mode) {
        #it's last endif so do not print full endif_line
        print "#endif";
        printf global_buf; #flush whatever was after last endif
    }
}

#!/bin/awk
#
# Copyright (c) 2014, Michal Policht. This file is dually licensed under terms of
# either WTFPL or BEER-WARE LICENSE. You may obtain the copy of WTFPL or BEER-WARE
# LICENSE in nearest drug store.
#
# THIS SOFTWARE IS ADDICTED TO DRUGS AND ALCOHOL AND IS A SUSPECT OF DRIVING UNDER THE
# INFLUENCE OF ALCOHOL. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS NOT" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS AND APPLICATION AND
# ACCOMODATION FOR A PARTICULAR PURPOSE AND MANY OTHERS NOT MENTIONED, NOR EVEN
# INVENTED WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
# OR CONTRIBUTORS BE LIABLE FOR ANY TEMPORAL, PERMANENT, UNFORTUNATE, UNLUCKY,
# LUCKY, DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ACCIDENTAL, MENTAL,
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION;
# OR BEING KILLED BY A LIGHTNING; OR FLOOD; OR FIRE; OR ANTEATER (INCLUDING BUT NOT
# LIMITED TO, GIANT ANTEATER, ANTEATER WHO LIES ON A SOFA; ANTEATER WHO LISTENS HEAVY
# METAL MUSIC; ANTEATER WHO ATE HUMAN BEFORE) OR ANOTHER BEING.) HOWEVER CAUSED AND ON
# ANY, ANY THEORY OF LIABILITY, CONSPIRACY THEORY, ANY THEORY OF RELATIVITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
# WAY OUT OF THE USE OF THIS SOFTWARE, ARISING IN ANY WAY OUT OF THE SUN, EVEN IF PROMISSED
# WISHED OR ASSURED SUCH DAMAGE. THIS SOFTWARE CAN REALLY DO TERRIBLE THINGS.
#
# Script updates C/C++ include guards with macros based on header path (including directory structure).
# It seeks for "#ifndef, #define" pair and substitutes first encountered pair with generated values.
# Script does not distinguish include guards from other macros, so each HEADER FILE MUST CONTAIN
# INCLUDE GUARD AS ITS FIRST "#ifndef, #define" MACRO PAIR. Script only updates include guards;
# if file does not contain something that looks like include guard to the script it will not add one.
# Script will also eat everything after last "#endif", presumably include guard comment. It's a stupid
# beast, so always backup your data before use.
#
# usage: awk [-v prefix="PREFIX"] -f awkgward.awk header
# example: awk -v prefix="PROJECT_" -f awkgward.awk file.hpp
#
# parameters:
# header - header file.
#
# required tools: awk.

function create_guard_macro(prefix, filename)
{
    double_underscore = toupper(filename);
    # just in case, double single underscores
    gsub(/_/, "__", double_underscore);
    # \/ = slash (/), \. = dot (.), \\ = backslash (\) - replace them with underscore.
    gsub(/[\/\.\\]/, "_", double_underscore);
    return prefix double_underscore;
}

function create_guard(prefix, filename)
{
    guard_macro = create_guard_macro(prefix, filename);
    guard = "#ifndef " guard_macro ORS "#define " guard_macro;
    return guard;
}

function print_or_buf(line)
{
    if (global_buf_mode)
        global_buf = global_buf line ORS;
    else
        print line;
}

BEGIN {
    S_START = 0;
    S_FIRST_IFNDEF = 1;
    S_END = 2;

    if (!prefix)
        prefix = "";

    global_buf = "";
    global_buf_mode = 0;
    endif_line = "";

    ifndef_buf = "";
    # simple automata:
    # S_START            /^#ifndef\s.*/  -> S_FIRST_IFNDEF     /^#define\s.*/ -> S_END     // -> S_START
    # S_FIRST_IFNDEF     /^#define\s.*/ -> S_END
    # S_END              // -> S_END
    state = S_START;
}

/^#ifndef[\t ].*/ {
    if (state == S_START) {
        ifndef_buf = $0;
        state = S_FIRST_IFNDEF;
        next;
    }
}

/^#define[\t ].*/ {
    if (state == S_FIRST_IFNDEF) {
        #eat old guard and replace it with new one
        print_or_buf(create_guard(prefix, FILENAME));
        state = S_END;
        next;
    }
    if (state == S_START)
        state = S_END;
}

/^#endif[\t ].*/ {
    #flush old buffer and whatever was in endif line
    if (global_buf_mode) {
        print endif_line;
        printf global_buf;
        global_buf = "";
    }
    endif_line = $0;
    global_buf_mode = 1;
    next;
}

{
    if (state == S_END || state == S_START)
        print_or_buf($0);
    if (state == S_FIRST_IFNDEF) {
        print_or_buf(ifndef_buf);
        print_or_buf($0);
        state = S_END;
    }
}

END {
    if (global_buf_mode) {
        #it's last endif so do not print full endif_line
        print "#endif";
        printf global_buf; #flush whatever was after last endif
    }
}


fixed search_tests.awk identify the name of a test case between the first pair of parenthesis ( ... ) after the keyword BOOST_AUTO_TEST_CASE

BEGIN {
  PREFIX=""
}

$0 ~ "^ *BOOST_FIXTURE_TEST_SUITE.*\\(" {
  sub("^.*\\( *", "");
  sub(" *\\,.*$", "");
  PREFIX=$0;
}

$0 ~ "^ *BOOST_AUTO_TEST_SUITE_END *\\( *\\)" {
  PREFIX=""
}

$0 ~ "^ *BOOST_AUTO_TEST_CASE *\\(" {
  sub("^ *BOOST_AUTO_TEST_CASE *\\( *", "")
  sub(" *\\).*$", "")
  if ( PREFIX ) {
    printf "%s/%s\n", PREFIX, $0
  } else {
    printf "%s\n", $0
  }
}

$0 ~ "^ *#include  *\"" {
  sub("^[^\"]*\" *", "");
  sub(" *\".*$", "");
  #print "#include", $0
  callfile($0)
}

END {
}

function callfile(f) {
	if (system("test -f " f) == 0) {
		ARGV[ARGC]=f
		ARGC++
	}
}

# vim: ts=2 sw=2 et


Shell: rewrite initRlwrap()

Shell: rewrite initRlwrap()

####################################################################
# Shell.awk                                                        #
####################################################################

# Detect external readline wrapper (rlwrap).
function initRlwrap() {
    Rlwrap = ("rlwrap --version 2>/dev/null" | getline) ? "rlwrap" : ""
}

# Prompt for interactive session.
function prompt(    i, p, temp) {
    p = Option["prompt"]

    # Format specifiers supported by strftime().
    # Roughly following ISO 8601:1988, with the notable exception of "%S", "%t" and "%T".
    # GNU libc extensions like "%l", "%s" and "%_*" are not supported.
    # See: <https://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html>
    #      <http://pubs.opengroup.org/onlinepubs/007908799/xsh/strftime.html>
    if (p ~ /%a/) gsub(/%a/, strftime("%a"), p)
    if (p ~ /%A/) gsub(/%A/, strftime("%A"), p)
    if (p ~ /%b/) gsub(/%b/, strftime("%b"), p)
    if (p ~ /%B/) gsub(/%B/, strftime("%B"), p)
    if (p ~ /%c/) gsub(/%c/, strftime("%c"), p)
    if (p ~ /%C/) gsub(/%C/, strftime("%C"), p)
    if (p ~ /%d/) gsub(/%d/, strftime("%d"), p)
    if (p ~ /%D/) gsub(/%D/, strftime("%D"), p)
    if (p ~ /%e/) gsub(/%e/, strftime("%e"), p)
    if (p ~ /%F/) gsub(/%F/, strftime("%F"), p)
    if (p ~ /%g/) gsub(/%g/, strftime("%g"), p)
    if (p ~ /%G/) gsub(/%G/, strftime("%G"), p)
    if (p ~ /%h/) gsub(/%h/, strftime("%h"), p)
    if (p ~ /%H/) gsub(/%H/, strftime("%H"), p)
    if (p ~ /%I/) gsub(/%I/, strftime("%I"), p)
    if (p ~ /%j/) gsub(/%j/, strftime("%j"), p)
    if (p ~ /%m/) gsub(/%m/, strftime("%m"), p)
    if (p ~ /%M/) gsub(/%M/, strftime("%M"), p)
    if (p ~ /%n/) gsub(/%n/, strftime("%n"), p)
    if (p ~ /%p/) gsub(/%p/, strftime("%p"), p)
    if (p ~ /%r/) gsub(/%r/, strftime("%r"), p)
    if (p ~ /%R/) gsub(/%R/, strftime("%R"), p)
    if (p ~ /%u/) gsub(/%u/, strftime("%u"), p)
    if (p ~ /%U/) gsub(/%U/, strftime("%U"), p)
    if (p ~ /%V/) gsub(/%V/, strftime("%V"), p)
    if (p ~ /%w/) gsub(/%w/, strftime("%w"), p)
    if (p ~ /%W/) gsub(/%W/, strftime("%W"), p)
    if (p ~ /%x/) gsub(/%x/, strftime("%x"), p)
    if (p ~ /%X/) gsub(/%X/, strftime("%X"), p)
    if (p ~ /%y/) gsub(/%y/, strftime("%y"), p)
    if (p ~ /%Y/) gsub(/%Y/, strftime("%Y"), p)
    if (p ~ /%z/) gsub(/%z/, strftime("%z"), p)
    if (p ~ /%Z/) gsub(/%Z/, strftime("%Z"), p)

    # %_ : prompt message
    if (p ~ /%_/)
        gsub(/%_/, sprintf(Locale[getCode(Option["hl"])]["message"], ""), p)

    # %l : home language
    if (p ~ /%l/)
        gsub(/%l/, Locale[getCode(Option["hl"])]["display"], p)

    # %L : home language (English name)
    if (p ~ /%L/)
        gsub(/%L/, Locale[getCode(Option["hl"])]["name"], p)

    # %s : source language
    # 's' is the format-control character for string

    # %S : source language (English name)
    if (p ~ /%S/)
        gsub(/%S/, Locale[getCode(Option["sl"])]["name"], p)

    # %t : target languages, separated by "+"
    if (p ~ /%t/) {
        temp = Locale[getCode(Option["tl"][1])]["display"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "+" Locale[getCode(Option["tl"][i])]["display"]
        gsub(/%t/, temp, p)
    }

    # %T : target languages (English names), separated by "+"
    if (p ~ /%T/) {
        temp = Locale[getCode(Option["tl"][1])]["name"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "+" Locale[getCode(Option["tl"][i])]["name"]
        gsub(/%T/, temp, p)
    }

    # %, : target languages, separated by ","
    if (p ~ /%,/) {
        temp = Locale[getCode(Option["tl"][1])]["display"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "," Locale[getCode(Option["tl"][i])]["display"]
        gsub(/%,/, temp, p)
    }

    # %< : target languages (English names), separated by ","
    if (p ~ /%</) {
        temp = Locale[getCode(Option["tl"][1])]["name"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "," Locale[getCode(Option["tl"][i])]["name"]
        gsub(/%</, temp, p)
    }

    # %/ : target languages, separated by "/"
    if (p ~ /%\//) {
        temp = Locale[getCode(Option["tl"][1])]["display"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "/" Locale[getCode(Option["tl"][i])]["display"]
        gsub(/%\//, temp, p)
    }

    # %? : target languages (English names), separated by "/"
    if (p ~ /%\?/) {
        temp = Locale[getCode(Option["tl"][1])]["name"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "/" Locale[getCode(Option["tl"][i])]["name"]
        gsub(/%\?/, temp, p)
    }

    # %s : source language
    printf(AnsiCode["bold"] AnsiCode[tolower(Option["prompt-color"])] p AnsiCode[0] " ", Locale[getCode(Option["sl"])]["display"]) > "/dev/stderr"
}

####################################################################
# Shell.awk                                                        #
####################################################################

# Detect external readline wrapper (rlwrap).
function initRlwrap() {
    Rlwrap = !system("rlwrap --version >/dev/null 2>/dev/null") ? "rlwrap" : ""
}

# Prompt for interactive session.
function prompt(    i, p, temp) {
    p = Option["prompt"]

    # Format specifiers supported by strftime().
    # Roughly following ISO 8601:1988, with the notable exception of "%S", "%t" and "%T".
    # GNU libc extensions like "%l", "%s" and "%_*" are not supported.
    # See: <https://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html>
    #      <http://pubs.opengroup.org/onlinepubs/007908799/xsh/strftime.html>
    if (p ~ /%a/) gsub(/%a/, strftime("%a"), p)
    if (p ~ /%A/) gsub(/%A/, strftime("%A"), p)
    if (p ~ /%b/) gsub(/%b/, strftime("%b"), p)
    if (p ~ /%B/) gsub(/%B/, strftime("%B"), p)
    if (p ~ /%c/) gsub(/%c/, strftime("%c"), p)
    if (p ~ /%C/) gsub(/%C/, strftime("%C"), p)
    if (p ~ /%d/) gsub(/%d/, strftime("%d"), p)
    if (p ~ /%D/) gsub(/%D/, strftime("%D"), p)
    if (p ~ /%e/) gsub(/%e/, strftime("%e"), p)
    if (p ~ /%F/) gsub(/%F/, strftime("%F"), p)
    if (p ~ /%g/) gsub(/%g/, strftime("%g"), p)
    if (p ~ /%G/) gsub(/%G/, strftime("%G"), p)
    if (p ~ /%h/) gsub(/%h/, strftime("%h"), p)
    if (p ~ /%H/) gsub(/%H/, strftime("%H"), p)
    if (p ~ /%I/) gsub(/%I/, strftime("%I"), p)
    if (p ~ /%j/) gsub(/%j/, strftime("%j"), p)
    if (p ~ /%m/) gsub(/%m/, strftime("%m"), p)
    if (p ~ /%M/) gsub(/%M/, strftime("%M"), p)
    if (p ~ /%n/) gsub(/%n/, strftime("%n"), p)
    if (p ~ /%p/) gsub(/%p/, strftime("%p"), p)
    if (p ~ /%r/) gsub(/%r/, strftime("%r"), p)
    if (p ~ /%R/) gsub(/%R/, strftime("%R"), p)
    if (p ~ /%u/) gsub(/%u/, strftime("%u"), p)
    if (p ~ /%U/) gsub(/%U/, strftime("%U"), p)
    if (p ~ /%V/) gsub(/%V/, strftime("%V"), p)
    if (p ~ /%w/) gsub(/%w/, strftime("%w"), p)
    if (p ~ /%W/) gsub(/%W/, strftime("%W"), p)
    if (p ~ /%x/) gsub(/%x/, strftime("%x"), p)
    if (p ~ /%X/) gsub(/%X/, strftime("%X"), p)
    if (p ~ /%y/) gsub(/%y/, strftime("%y"), p)
    if (p ~ /%Y/) gsub(/%Y/, strftime("%Y"), p)
    if (p ~ /%z/) gsub(/%z/, strftime("%z"), p)
    if (p ~ /%Z/) gsub(/%Z/, strftime("%Z"), p)

    # %_ : prompt message
    if (p ~ /%_/)
        gsub(/%_/, sprintf(Locale[getCode(Option["hl"])]["message"], ""), p)

    # %l : home language
    if (p ~ /%l/)
        gsub(/%l/, Locale[getCode(Option["hl"])]["display"], p)

    # %L : home language (English name)
    if (p ~ /%L/)
        gsub(/%L/, Locale[getCode(Option["hl"])]["name"], p)

    # %s : source language
    # 's' is the format-control character for string

    # %S : source language (English name)
    if (p ~ /%S/)
        gsub(/%S/, Locale[getCode(Option["sl"])]["name"], p)

    # %t : target languages, separated by "+"
    if (p ~ /%t/) {
        temp = Locale[getCode(Option["tl"][1])]["display"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "+" Locale[getCode(Option["tl"][i])]["display"]
        gsub(/%t/, temp, p)
    }

    # %T : target languages (English names), separated by "+"
    if (p ~ /%T/) {
        temp = Locale[getCode(Option["tl"][1])]["name"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "+" Locale[getCode(Option["tl"][i])]["name"]
        gsub(/%T/, temp, p)
    }

    # %, : target languages, separated by ","
    if (p ~ /%,/) {
        temp = Locale[getCode(Option["tl"][1])]["display"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "," Locale[getCode(Option["tl"][i])]["display"]
        gsub(/%,/, temp, p)
    }

    # %< : target languages (English names), separated by ","
    if (p ~ /%</) {
        temp = Locale[getCode(Option["tl"][1])]["name"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "," Locale[getCode(Option["tl"][i])]["name"]
        gsub(/%</, temp, p)
    }

    # %/ : target languages, separated by "/"
    if (p ~ /%\//) {
        temp = Locale[getCode(Option["tl"][1])]["display"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "/" Locale[getCode(Option["tl"][i])]["display"]
        gsub(/%\//, temp, p)
    }

    # %? : target languages (English names), separated by "/"
    if (p ~ /%\?/) {
        temp = Locale[getCode(Option["tl"][1])]["name"]
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "/" Locale[getCode(Option["tl"][i])]["name"]
        gsub(/%\?/, temp, p)
    }

    # %s : source language
    printf(AnsiCode["bold"] AnsiCode[tolower(Option["prompt-color"])] p AnsiCode[0] " ", Locale[getCode(Option["sl"])]["display"]) > "/dev/stderr"
}


Wrap brlapi_brldefs.h with the correct #define. (dm)

###############################################################################
# BRLTTY - A background process providing access to the console screen (when in
#          text mode) for a blind person using a refreshable braille display.
#
# Copyright (C) 1995-2014 by The BRLTTY Developers.
#
# BRLTTY comes with ABSOLUTELY NO WARRANTY.
#
# This is free software, placed under the terms of the
# GNU General Public License, as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any
# later version. Please see the file LICENSE-GPL for details.
#
# Web Page: http://mielke.cc/brltty/
#
# This software is maintained by Dave Mielke <dave@mielke.cc>.
###############################################################################

BEGIN {
  writeHeaderPrologue("BRLAPI_INCLUDED_BRLAPI_BRLDEFS", "api.h")
}

END {
  writeMacroDefinition("BRL_MSK_BLK", "(BRLAPI_KEY_TYPE_MASK | BRLAPI_KEY_CMD_BLK_MASK)", "mask for command type")
  writeMaskDefinition("ARG", "mask for command value/argument")
  writeMacroDefinition("BRL_MSK_FLG", "BRLAPI_KEY_FLAGS_MASK", "mask for command flags")
  writeMacroDefinition("BRL_MSK_CMD", "(BRL_MSK_BLK | BRL_MSK_ARG)", "mask for command")

  writeHeaderEpilogue()
}

function writeMaskDefinition(name, help) {
  writeSymbolDefinition(name, "BRL_MSK_", "", "BRLAPI_KEY_CMD_", "_MASK", help)
}

function writeSymbolDefinition(name, brlPrefix, brlSuffix, apiPrefix, apiSuffix, help) {
  writeMacroDefinition(brlPrefix name brlSuffix, apiPrefix name apiSuffix, help)
}

function brlCommand(name, symbol, value, help) {
  writeSymbolDefinition(name, "BRL_CMD_", "", "(BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_", ")", help)
}

function brlBlock(name, symbol, value, help) {
  if (name == "PASSCHAR") {
    writeMacroDefinition("BRL_KEY_" name, "(BRLAPI_KEY_TYPE_SYM | 0X0000)", help)
  } else if (name == "PASSKEY") {
    writeMacroDefinition("BRL_KEY_" name, "(BRLAPI_KEY_TYPE_SYM | 0XFF00)", help)
  } else {
    writeSymbolDefinition(name, "BRL_BLK_", "", "(BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_", ")", help)
  }
}

function brlKey(name, symbol, value, help) {
  writeMacroDefinition("BRL_KEY_" name, "(BRLAPI_KEY_SYM_" getBrlapiKeyName(name) " & 0XFF)", help)
}

function brlFlag(name, symbol, value, help) {
  if (match(name, "^[^_]*_")) {
    type = substr(name, 1, RLENGTH-1)
    if (type == "CHAR") {
      name = substr(name, RLENGTH+1)
      writeSymbolDefinition(name, "BRL_FLG_" type "_", "", "BRLAPI_KEY_FLG_", "", help)
      return
    }
  }
  writeSymbolDefinition(name, "BRL_FLG_", "", "BRLAPI_KEY_FLG_", "", help)
}

function brlDot(number, symbol, value, help) {
  writeSymbolDefinition(number, "BRL_DOT", "", "BRLAPI_DOT", "", help)
}

###############################################################################
# BRLTTY - A background process providing access to the console screen (when in
#          text mode) for a blind person using a refreshable braille display.
#
# Copyright (C) 1995-2014 by The BRLTTY Developers.
#
# BRLTTY comes with ABSOLUTELY NO WARRANTY.
#
# This is free software, placed under the terms of the
# GNU General Public License, as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any
# later version. Please see the file LICENSE-GPL for details.
#
# Web Page: http://mielke.cc/brltty/
#
# This software is maintained by Dave Mielke <dave@mielke.cc>.
###############################################################################

BEGIN {
  writeHeaderPrologue("BRLAPI_INCLUDED_BRLDEFS", "api.h")
}

END {
  writeMacroDefinition("BRL_MSK_BLK", "(BRLAPI_KEY_TYPE_MASK | BRLAPI_KEY_CMD_BLK_MASK)", "mask for command type")
  writeMaskDefinition("ARG", "mask for command value/argument")
  writeMacroDefinition("BRL_MSK_FLG", "BRLAPI_KEY_FLAGS_MASK", "mask for command flags")
  writeMacroDefinition("BRL_MSK_CMD", "(BRL_MSK_BLK | BRL_MSK_ARG)", "mask for command")

  writeHeaderEpilogue()
}

function writeMaskDefinition(name, help) {
  writeSymbolDefinition(name, "BRL_MSK_", "", "BRLAPI_KEY_CMD_", "_MASK", help)
}

function writeSymbolDefinition(name, brlPrefix, brlSuffix, apiPrefix, apiSuffix, help) {
  writeMacroDefinition(brlPrefix name brlSuffix, apiPrefix name apiSuffix, help)
}

function brlCommand(name, symbol, value, help) {
  writeSymbolDefinition(name, "BRL_CMD_", "", "(BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_", ")", help)
}

function brlBlock(name, symbol, value, help) {
  if (name == "PASSCHAR") {
    writeMacroDefinition("BRL_KEY_" name, "(BRLAPI_KEY_TYPE_SYM | 0X0000)", help)
  } else if (name == "PASSKEY") {
    writeMacroDefinition("BRL_KEY_" name, "(BRLAPI_KEY_TYPE_SYM | 0XFF00)", help)
  } else {
    writeSymbolDefinition(name, "BRL_BLK_", "", "(BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_", ")", help)
  }
}

function brlKey(name, symbol, value, help) {
  writeMacroDefinition("BRL_KEY_" name, "(BRLAPI_KEY_SYM_" getBrlapiKeyName(name) " & 0XFF)", help)
}

function brlFlag(name, symbol, value, help) {
  if (match(name, "^[^_]*_")) {
    type = substr(name, 1, RLENGTH-1)
    if (type == "CHAR") {
      name = substr(name, RLENGTH+1)
      writeSymbolDefinition(name, "BRL_FLG_" type "_", "", "BRLAPI_KEY_FLG_", "", help)
      return
    }
  }
  writeSymbolDefinition(name, "BRL_FLG_", "", "BRLAPI_KEY_FLG_", "", help)
}

function brlDot(number, symbol, value, help) {
  writeSymbolDefinition(number, "BRL_DOT", "", "BRLAPI_DOT", "", help)
}