gofrontend: deduplicate C syscall function declarations

A gccgo language extension allows a function to be declared multiple
times. Avoid the use of this extension by dedeplicating declarations
in mksyscall.awk.

R=iant
CC=gofrontend-dev
https://golang.org/cl/89130043

# Copyright 2011 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# This AWK script reads a Go file with comments describing syscall
# functions and the C routines they map to.  It generates the Go code
# which calls the C routines.

# The syscall functins are marked by lines beginning with "//sys" and
# read like func declarations if //sys is replaced by func, but:
#	* The parameter lists must give a name for each argument.
#	  This includes return parameters.
#	* The parameter lists must give a type for each argument:
#	   the (x, y, z int) shorthand is not allowed.
#	* If the return parameter is an error, it must be named err.

# A line beginning with //sysnb is like //sys, except that the
# goroutine will not be suspended during the execution of the library
# call.  This must only be used for library calls which can never
# block, as otherwise the library call could cause all goroutines to
# hang.

# After the //sys or //sysnb line comes a second line which describes
# the C function.  The name must be the name of the function in the C
# library, and may be the same as the Go function.  The limitations on
# the argument list are the same as for the //sys line, but there must
# be at most one result parameter, and it must be given as just a
# type, without a name.

BEGIN {
    print "// This file was automatically generated by mksyscall.awk"
    print ""
    print "package syscall"
    print ""
    print "import \"unsafe\""
    print ""
    status = 0
}

/^\/\/sys/ {
    if ($1 == "//sysnb") {
	blocking = 0
    } else {
	blocking = 1
    }

    line = $0

    if (match(line, "//sys(nb)?[ 	]*[a-zA-Z0-9_]+\\([^()]*\\) *(\\(([^()]+)\\))?") == 0) {
	print "unmatched line:", $0 | "cat 1>&2"
	status = 1
	next
    }

    # Sets a[1] = //sysnb, a[2] == function name.
    split(line, a, "[ 	(]+")
    gofnname = a[2]

    off = match(line, "\\([^()]*\\)")
    end = index(substr(line, off, length(line) - off + 1), ")")
    gofnparams = substr(line, off + 1, end - 2)

    line = substr(line, off + end, length(line) - (off + end) + 1)
    off = match(line, "\\([^()]*\\)")
    if (off == 0) {
	gofnresults = ""
    } else {
	end = index(substr(line, off, length(line) - off + 1), ")")
	gofnresults = substr(line, off + 1, end - 2)
    }

    getline
    line = $0

    if (match(line, "//[a-zA-Z0-9_]+\\([^()]*\\)") == 0) {
	print "unmatched C line", $0, "after", gofnname | "cat 1>&2"
	status = 1
	next
    }

    split(line, a, "[ 	(]+")
    cfnname = substr(a[1], 3, length(a[1]) - 2)

    off = match(line, "\\([^()]*\\)")
    end = index(substr(line, off, length(line) - off + 1), ")")
    cfnparams = substr(line, off + 1, end - 2)

    line = substr(line, off + end + 1, length(line) - (off + end) + 1)
    while (substr(line, 1, 1) == " ") {
	line = substr(line, 2, length(line) - 1)
    }
    end = index(line, " ")
    if (end != 0) {
	line = substr(line, 1, end)
    }
    cfnresult = line

    printf("// Automatically generated wrapper for %s/%s\n", gofnname, cfnname)
    if (!(cfnname in cfns)) {
        cfns[cfnname] = 1
        printf("//extern %s\n", cfnname)
        printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult)
    }
    printf("func %s(%s) %s%s%s%s{\n",
	   gofnname, gofnparams, gofnresults == "" ? "" : "(", gofnresults,
	   gofnresults == "" ? "" : ")", gofnresults == "" ? "" : " ")

    loc = gofnname "/" cfnname ":"

    haserr = 0
    if (gofnresults != "") {
	fields = split(gofnresults, goresults, ", *")
	for (goresult = 1; goresults[goresult] != ""; goresult++) {
	    if (split(goresults[goresult], goparam) == 2) {
		if (goparam[1] == "err") {
		    haserr = 1
		    break
		}
	    }
	}
    }

    split(gofnparams, goargs, ", *")
    split(cfnparams, cargs, ", *")
    args = ""
    carg = 1
    for (goarg = 1; goargs[goarg] != ""; goarg++) {
	if (cargs[carg] == "") {
	    print loc, "not enough C parameters"
	}

	if (args != "") {
	    args = args ", "
	}

	if (split(goargs[goarg], a) != 2) {
	    print loc, "bad parameter:", goargs[goarg] | "cat 1>&2"
	    status = 1
	    next
	}

	goname = a[1]
	gotype = a[2]

	if (split(cargs[carg], a) != 2) {
	    print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
	    status = 1
	    next
	}

	ctype = a[2]

	if (gotype ~ /^\*/) {
	    if (gotype != ctype) {
		print loc, "Go/C pointer type mismatch:", gotype, ctype | "cat 1>&2"
		status = 1
		next
	    }
	    args = args goname
	} else if (gotype == "string") {
	    if (ctype != "*byte") {
		print loc, "Go string not matched to C *byte:", gotype, ctype | "cat 1>&2"
		status = 1
		next
	    }
	    printf("\tvar _p%d *byte\n", goarg)
	    if (haserr) {
		printf("\t_p%d, err = BytePtrFromString(%s)\n", goarg, goname)
		printf("\tif err != nil {\n\t\treturn\n\t}\n")
	    } else {
		print loc, "uses string arguments but has no error return" | "cat 1>&2"
		printf("\t_p%d, _ = BytePtrFromString(%s)\n", goarg, goname)
	    }
	    args = sprintf("%s_p%d", args, goarg)
	} else if (gotype ~ /^\[\](.*)/) {
	    if (ctype !~ /^\*/ || cargs[carg + 1] == "") {
		print loc, "bad C type for slice:", gotype, ctype | "cat 1>&2"
		status = 1
		next
	    }

	    # Convert a slice into a pair of pointer, length.
	    # Don't try to take the address of the zeroth element of a
	    # nil slice.
	    printf("\tvar _p%d %s\n", goarg, ctype)
	    printf("\tif len(%s) > 0 {\n", goname)
	    printf("\t\t_p%d = (%s)(unsafe.Pointer(&%s[0]))\n", goarg, ctype, goname)
	    printf("\t} else {\n")
	    printf("\t\t_p%d = (%s)(unsafe.Pointer(&_zero))\n", goarg, ctype)
	    printf("\t}\n")

	    ++carg
	    if (split(cargs[carg], cparam) != 2) {
		print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
		status = 1
		next
	    }

	    args = sprintf("%s_p%d, %s(len(%s))", args, goarg, cparam[2], goname)
	} else if (gotype == "uintptr" && ctype ~ /^\*/) {
	    args = sprintf("%s(%s)(unsafe.Pointer(%s))", args, ctype, goname)
	} else {
	    args = sprintf("%s%s(%s)", args, ctype, goname)
	}

	carg++
    }

    if (cargs[carg] != "") {
	print loc, "too many C parameters" | "cat 1>&2"
	status = 1
	next
    }

    if (blocking) {
	print "\tEntersyscall()"
    }

    printf("\t")
    if (gofnresults != "") {
	printf("_r := ")
    }
    printf("c_%s(%s)\n", cfnname, args)

    seterr = 0
    if (gofnresults != "") {
	fields = split(gofnresults, goresults, ", *")
	if (fields > 2) {
	    print loc, "too many Go results" | "cat 1>&2"
	    status = 1
	    next
	}
	usedr = 0
	for (goresult = 1; goresults[goresult] != ""; goresult++) {
	    if (split(goresults[goresult], goparam) != 2) {
		print loc, "bad result:", goresults[goresult] | "cat 1>&2"
		status = 1
		next
	    }

	    goname = goparam[1]
	    gotype = goparam[2]

	    if (goname == "err") {
		print "\tvar errno Errno"
		print "\tsetErrno := false"
		if (cfnresult ~ /^\*/) {
		    print "\tif _r == nil {"
		} else {
		    print "\tif _r < 0 {"
		}
		print "\t\terrno = GetErrno()"
		print "\t\tsetErrno = true"
		print "\t}"
		seterr = 1
	    } else if (gotype == "uintptr" && cfnresult ~ /^\*/) {
		printf("\t%s = (%s)(unsafe.Pointer(_r))\n", goname, gotype)
	    } else {
		if (usedr) {
		    print loc, "two parameters but no errno parameter" | "cat 1>&2"
		    status = 1
		    next
		}
		printf("\t%s = (%s)(_r)\n", goname, gotype)
		usedr = 1
	    }
	}
    }

    if (blocking) {
	print "\tExitsyscall()"
    }

    if (seterr) {
	print "\tif setErrno {"
	print "\t\terr = errno"
	print "\t}"
    }

    if (gofnresults != "") {
	print "\treturn"
    }

    print "}"

    print ""

    next
}

{ next }

END {
    if (status != 0) {
	print "*** mksyscall.awk failed" | "cat 1>&2"
	exit status
    }
}

# Copyright 2011 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# This AWK script reads a Go file with comments describing syscall
# functions and the C routines they map to.  It generates the Go code
# which calls the C routines.

# The syscall functins are marked by lines beginning with "//sys" and
# read like func declarations if //sys is replaced by func, but:
#	* The parameter lists must give a name for each argument.
#	  This includes return parameters.
#	* The parameter lists must give a type for each argument:
#	   the (x, y, z int) shorthand is not allowed.
#	* If the return parameter is an error, it must be named err.

# A line beginning with //sysnb is like //sys, except that the
# goroutine will not be suspended during the execution of the library
# call.  This must only be used for library calls which can never
# block, as otherwise the library call could cause all goroutines to
# hang.

# After the //sys or //sysnb line comes a second line which describes
# the C function.  The name must be the name of the function in the C
# library, and may be the same as the Go function.  The limitations on
# the argument list are the same as for the //sys line, but there must
# be at most one result parameter, and it must be given as just a
# type, without a name.

BEGIN {
    print "// This file was automatically generated by mksyscall.awk"
    print ""
    print "package syscall"
    print ""
    print "import \"unsafe\""
    print ""
    status = 0
}

/^\/\/sys/ {
    if ($1 == "//sysnb") {
	blocking = 0
    } else {
	blocking = 1
    }

    line = $0

    if (match(line, "//sys(nb)?[ 	]*[a-zA-Z0-9_]+\\([^()]*\\) *(\\(([^()]+)\\))?") == 0) {
	print "unmatched line:", $0 | "cat 1>&2"
	status = 1
	next
    }

    # Sets a[1] = //sysnb, a[2] == function name.
    split(line, a, "[ 	(]+")
    gofnname = a[2]

    off = match(line, "\\([^()]*\\)")
    end = index(substr(line, off, length(line) - off + 1), ")")
    gofnparams = substr(line, off + 1, end - 2)

    line = substr(line, off + end, length(line) - (off + end) + 1)
    off = match(line, "\\([^()]*\\)")
    if (off == 0) {
	gofnresults = ""
    } else {
	end = index(substr(line, off, length(line) - off + 1), ")")
	gofnresults = substr(line, off + 1, end - 2)
    }

    getline
    line = $0

    if (match(line, "//[a-zA-Z0-9_]+\\([^()]*\\)") == 0) {
	print "unmatched C line", $0, "after", gofnname | "cat 1>&2"
	status = 1
	next
    }

    split(line, a, "[ 	(]+")
    cfnname = substr(a[1], 3, length(a[1]) - 2)

    off = match(line, "\\([^()]*\\)")
    end = index(substr(line, off, length(line) - off + 1), ")")
    cfnparams = substr(line, off + 1, end - 2)

    line = substr(line, off + end + 1, length(line) - (off + end) + 1)
    while (substr(line, 1, 1) == " ") {
	line = substr(line, 2, length(line) - 1)
    }
    end = index(line, " ")
    if (end != 0) {
	line = substr(line, 1, end)
    }
    cfnresult = line

    printf("// Automatically generated wrapper for %s/%s\n", gofnname, cfnname)
    printf("//extern %s\n", cfnname)
    printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult)
    printf("func %s(%s) %s%s%s%s{\n",
	   gofnname, gofnparams, gofnresults == "" ? "" : "(", gofnresults,
	   gofnresults == "" ? "" : ")", gofnresults == "" ? "" : " ")

    loc = gofnname "/" cfnname ":"

    haserr = 0
    if (gofnresults != "") {
	fields = split(gofnresults, goresults, ", *")
	for (goresult = 1; goresults[goresult] != ""; goresult++) {
	    if (split(goresults[goresult], goparam) == 2) {
		if (goparam[1] == "err") {
		    haserr = 1
		    break
		}
	    }
	}
    }

    split(gofnparams, goargs, ", *")
    split(cfnparams, cargs, ", *")
    args = ""
    carg = 1
    for (goarg = 1; goargs[goarg] != ""; goarg++) {
	if (cargs[carg] == "") {
	    print loc, "not enough C parameters"
	}

	if (args != "") {
	    args = args ", "
	}

	if (split(goargs[goarg], a) != 2) {
	    print loc, "bad parameter:", goargs[goarg] | "cat 1>&2"
	    status = 1
	    next
	}

	goname = a[1]
	gotype = a[2]

	if (split(cargs[carg], a) != 2) {
	    print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
	    status = 1
	    next
	}

	ctype = a[2]

	if (gotype ~ /^\*/) {
	    if (gotype != ctype) {
		print loc, "Go/C pointer type mismatch:", gotype, ctype | "cat 1>&2"
		status = 1
		next
	    }
	    args = args goname
	} else if (gotype == "string") {
	    if (ctype != "*byte") {
		print loc, "Go string not matched to C *byte:", gotype, ctype | "cat 1>&2"
		status = 1
		next
	    }
	    printf("\tvar _p%d *byte\n", goarg)
	    if (haserr) {
		printf("\t_p%d, err = BytePtrFromString(%s)\n", goarg, goname)
		printf("\tif err != nil {\n\t\treturn\n\t}\n")
	    } else {
		print loc, "uses string arguments but has no error return" | "cat 1>&2"
		printf("\t_p%d, _ = BytePtrFromString(%s)\n", goarg, goname)
	    }
	    args = sprintf("%s_p%d", args, goarg)
	} else if (gotype ~ /^\[\](.*)/) {
	    if (ctype !~ /^\*/ || cargs[carg + 1] == "") {
		print loc, "bad C type for slice:", gotype, ctype | "cat 1>&2"
		status = 1
		next
	    }

	    # Convert a slice into a pair of pointer, length.
	    # Don't try to take the address of the zeroth element of a
	    # nil slice.
	    printf("\tvar _p%d %s\n", goarg, ctype)
	    printf("\tif len(%s) > 0 {\n", goname)
	    printf("\t\t_p%d = (%s)(unsafe.Pointer(&%s[0]))\n", goarg, ctype, goname)
	    printf("\t} else {\n")
	    printf("\t\t_p%d = (%s)(unsafe.Pointer(&_zero))\n", goarg, ctype)
	    printf("\t}\n")

	    ++carg
	    if (split(cargs[carg], cparam) != 2) {
		print loc, "bad C parameter:", cargs[carg] | "cat 1>&2"
		status = 1
		next
	    }

	    args = sprintf("%s_p%d, %s(len(%s))", args, goarg, cparam[2], goname)
	} else if (gotype == "uintptr" && ctype ~ /^\*/) {
	    args = sprintf("%s(%s)(unsafe.Pointer(%s))", args, ctype, goname)
	} else {
	    args = sprintf("%s%s(%s)", args, ctype, goname)
	}

	carg++
    }

    if (cargs[carg] != "") {
	print loc, "too many C parameters" | "cat 1>&2"
	status = 1
	next
    }

    if (blocking) {
	print "\tEntersyscall()"
    }

    printf("\t")
    if (gofnresults != "") {
	printf("_r := ")
    }
    printf("c_%s(%s)\n", cfnname, args)

    seterr = 0
    if (gofnresults != "") {
	fields = split(gofnresults, goresults, ", *")
	if (fields > 2) {
	    print loc, "too many Go results" | "cat 1>&2"
	    status = 1
	    next
	}
	usedr = 0
	for (goresult = 1; goresults[goresult] != ""; goresult++) {
	    if (split(goresults[goresult], goparam) != 2) {
		print loc, "bad result:", goresults[goresult] | "cat 1>&2"
		status = 1
		next
	    }

	    goname = goparam[1]
	    gotype = goparam[2]

	    if (goname == "err") {
		print "\tvar errno Errno"
		print "\tsetErrno := false"
		if (cfnresult ~ /^\*/) {
		    print "\tif _r == nil {"
		} else {
		    print "\tif _r < 0 {"
		}
		print "\t\terrno = GetErrno()"
		print "\t\tsetErrno = true"
		print "\t}"
		seterr = 1
	    } else if (gotype == "uintptr" && cfnresult ~ /^\*/) {
		printf("\t%s = (%s)(unsafe.Pointer(_r))\n", goname, gotype)
	    } else {
		if (usedr) {
		    print loc, "two parameters but no errno parameter" | "cat 1>&2"
		    status = 1
		    next
		}
		printf("\t%s = (%s)(_r)\n", goname, gotype)
		usedr = 1
	    }
	}
    }

    if (blocking) {
	print "\tExitsyscall()"
    }

    if (seterr) {
	print "\tif setErrno {"
	print "\t\terr = errno"
	print "\t}"
    }

    if (gofnresults != "") {
	print "\treturn"
    }

    print "}"

    print ""

    next
}

{ next }

END {
    if (status != 0) {
	print "*** mksyscall.awk failed" | "cat 1>&2"
	exit status
    }
}


Delete silly AWK version.

Delete silly AWK version.

#!/bin/sh
REALLY_UGLY_SHEBANG_HACK==0 "exec" "gawk" "-f" "$0" "$@"

# Awk version of the "csv_project3" program.
BEGIN {
    # Always pick the GNU date function, so we can get nanosec precision.
    # If installed via coreutils with Macports on OS X, it is called gdate.
    "uname" | getline uname
    if (uname == "Darwin")
        date = "gdate"
    else
        date = "date"
    date " +%s%N | cut -b1-13" |& getline start

    regex="^([^,\n]*),([^,\n]*),([^,\n]*),([^,\n]*),([^,\n]*),([^,\n]*)$"
}

match($0, regex, m) {
    print m[2] "\t" m[5]
}
$0 !~ regex {
     printf "match error!\n"
     exit 1
}

END {
    date " +%s%N | cut -b1-13" | getline end
    elaps = end - start
    print "\nmatching (ms): " elaps > "/dev/stderr"

}


Fix tailrecurse test

Fix tailrecurse test

* GoAWK doesn't have non-POSIX length(array) support
* We don't correctly parse "! c--" right now (see other skipped tests)
* Accessing B[""] doesn't set it (right now)

BEGIN {
	abc(2)
}

function array_length(a,   k, n) {
    n = 0
    for (k in a) n++
    return n
}

function abc(c, A, B)
{
	print "abc(" c ", " array_length(A) ")"
	if (!c) {
		return
	}
    c--
	B[""] = 1
	print array_length(B)
	return abc(c, B)
}

BEGIN {
	abc(2)
}

function abc(c, A, B)
{
	print "abc(" c ", " length(A) ")"
	if (! c--) {
		return
	}
	B[""]
	print length(B)
	return abc(c, B)
}


use default encoding (8859-1) for automat-SIP communicatin

BEGIN{
  FS=","
}
{
	print "\t<login id=\""$1"\" password=\""$2"\" delimiter=\"|\" error-detect=\"enabled\" institution=\""$3"\" checked_in_ok=\"1\">"
	print "\t\t<!-- General messages -->"
	print "\t\t<screen_msg_regex find=\"^.*Invalid password.*$\" replace=\"Feil passord\" />"
	print "\t\t<!-- Checkout screen messages we can translate directly -->"
	print "\t\t<screen_msg_regex find=\"Item checked out to another patron.*$\" replace=\"Materialet er lånt ut til en annen låner.\" />"
	print "\t\t<screen_msg_regex find=\"Item already checked out to you: renewing item.\" replace=\"Denne fornyes siden du allerede har lånt den.\" />"
	print "\t\t<screen_msg_regex find=\"Item was reserved for you.\" replace=\"Du hadde reservert denne.\" />"
	print "\t\t<screen_msg_regex find=\"Item is reserved for another patron upon return.\" replace=\"Materialet er reservert av en annen låner.\" />"
	print "\t\t<screen_msg_regex find=\"Item already checked out to another patron.  Please return item for check-in.\" replace=\"Materialet er allerede lånt ut til en annen låner. Vennligst returner det.\" />"
	print "\t\t<screen_msg_regex find=\"Outstanding Fines block issue.*\" replace=\"Du kan ikke låne grunnet utestående gebyrer.\" />"
	print "\t\t<screen_msg_regex find=\"Loan period reduced for high-demand item\" replace=\"Låneperioden er redusert pga stor etterspørsel\" />"
	print "\t\t<screen_msg_regex find=\"Item is on hold shelf for another patron\" replace=\"Materialet står til avhenting av en annen låner\" />"
	print "\t\t<screen_msg_regex find=\"Invalid Item\" replace=\"Ugyldig eksemplar\" />"
	print "\t\t<screen_msg_regex find=\"Invalid Patron\" replace=\"Ugyldig lånekort\" />"
	print "\t\t<screen_msg_regex find=\"Invalid cardnumber\" replace=\"Ugyldig lånekort\" />"
	print "\t\t<screen_msg_regex find=\"^.*Borrower.s card reported lost.*$\" replace=\"Lånekortet er meldt tapt. Vennligst kontakt personalet.\" />"
	print "\t\t<screen_msg_regex find=\"^.*Borrower has no valid address.*$\" replace=\"Feil i adresse. Vennligst kontakt personalet.\" />"
	print "\t\t<!-- Renew -->"
	print "\t\t<screen_msg_regex find=\"Item unavailable due to outstanding holds\" replace=\"Materialet er utilgjengelig pga ventende reservasjoner\" />"
	print "\t\t<screen_msg_regex find=\"Item has reached maximum renewals\" replace=\"Materialet kan ikke lånes flere ganger\" />"
	print "\t\t<screen_msg_regex find=\"NO_MORE_RENEWALS[\\:]*\" replace=\"Maks antall fornyelser oversteget.\" />"
	print "\t\t<!-- Missing screen messages in Koha and other quirks -->"
	print "\t\t<screen_msg_regex find=\"^.*Patron owes.+$\" replace=\"Du har utestående gebyrer - henvend deg til personalet.\" />"
	print "\t\t<screen_msg_regex find=\"^Patron Blocked$\" replace=\"Lånekortet er sperret - henvend deg til personalet.\" />"
	print "\t\t<screen_msg_regex find=\"AGE_RESTRICTION[\\:]*\" replace=\"\" />"
	print "\t\t<screen_msg_regex find=\"TOO_MANY_CHECKOUTS\" replace=\"For mange utlån\" />"
	print "\t\t<screen_msg_regex find=\"NOT_FOR_LOAN.*$\" replace=\"Materialet er ikke til utlån.\" />"
	print "\t\t<screen_msg_regex find=\"item_notforloan.*$\" replace=\"Materialet er ikke til utlån.\" />"
	print "\t\t<!-- Bug 15438 - Checking out an on-hold item sends holder's borrowernumber in AF (screen message) field. -->"
	print "\t\t<!-- gjelder også utlån av samme eksemplar to ganger -->"
	print "\t\t<screen_msg_regex find=\"^\d{1,}$\" replace=\"Materialet er allerede utlånt/reservert.\" />"
	print "\t\t<!-- Last resort -->"
	print "\t\t<screen_msg_regex find=\"Greetings from Koha.\" replace=\"Melding fra biblioteket:\" />"
	print "\t</login>"
}

BEGIN{
  FS=","
}
{
	print "\t<login encoding=\"utf8\" id=\""$1"\" password=\""$2"\" delimiter=\"|\" error-detect=\"enabled\" institution=\""$3"\" checked_in_ok=\"1\">"
	print "\t\t<!-- General messages -->"
	print "\t\t<screen_msg_regex find=\"^.*Invalid password.*$\" replace=\"Feil passord\" />"
	print "\t\t<!-- Checkout screen messages we can translate directly -->"
	print "\t\t<screen_msg_regex find=\"Item checked out to another patron.*$\" replace=\"Materialet er lånt ut til en annen låner.\" />"
	print "\t\t<screen_msg_regex find=\"Item already checked out to you: renewing item.\" replace=\"Denne fornyes siden du allerede har lånt den.\" />"
	print "\t\t<screen_msg_regex find=\"Item was reserved for you.\" replace=\"Du hadde reservert denne.\" />"
	print "\t\t<screen_msg_regex find=\"Item is reserved for another patron upon return.\" replace=\"Materialet er reservert av en annen låner.\" />"
	print "\t\t<screen_msg_regex find=\"Item already checked out to another patron.  Please return item for check-in.\" replace=\"Materialet er allerede lånt ut til en annen låner. Vennligst returner det.\" />"
	print "\t\t<screen_msg_regex find=\"Outstanding Fines block issue.*\" replace=\"Du kan ikke låne grunnet utestående gebyrer.\" />"
	print "\t\t<screen_msg_regex find=\"Loan period reduced for high-demand item\" replace=\"Låneperioden er redusert pga stor etterspørsel\" />"
	print "\t\t<screen_msg_regex find=\"Item is on hold shelf for another patron\" replace=\"Materialet står til avhenting av en annen låner\" />"
	print "\t\t<screen_msg_regex find=\"Invalid Item\" replace=\"Ugyldig eksemplar\" />"
	print "\t\t<screen_msg_regex find=\"Invalid Patron\" replace=\"Ugyldig lånekort\" />"
	print "\t\t<screen_msg_regex find=\"Invalid cardnumber\" replace=\"Ugyldig lånekort\" />"
	print "\t\t<screen_msg_regex find=\"^.*Borrower.s card reported lost.*$\" replace=\"Lånekortet er meldt tapt. Vennligst kontakt personalet.\" />"
	print "\t\t<screen_msg_regex find=\"^.*Borrower has no valid address.*$\" replace=\"Feil i adresse. Vennligst kontakt personalet.\" />"
	print "\t\t<!-- Renew -->"
	print "\t\t<screen_msg_regex find=\"Item unavailable due to outstanding holds\" replace=\"Materialet er utilgjengelig pga ventende reservasjoner\" />"
	print "\t\t<screen_msg_regex find=\"Item has reached maximum renewals\" replace=\"Materialet kan ikke lånes flere ganger\" />"
	print "\t\t<screen_msg_regex find=\"NO_MORE_RENEWALS[\\:]*\" replace=\"Maks antall fornyelser oversteget.\" />"
	print "\t\t<!-- Missing screen messages in Koha and other quirks -->"
	print "\t\t<screen_msg_regex find=\"^.*Patron owes.+$\" replace=\"Du har utestående gebyrer - henvend deg til personalet.\" />"
	print "\t\t<screen_msg_regex find=\"^Patron Blocked$\" replace=\"Lånekortet er sperret - henvend deg til personalet.\" />"
	print "\t\t<screen_msg_regex find=\"AGE_RESTRICTION[\\:]*\" replace=\"\" />"
	print "\t\t<screen_msg_regex find=\"TOO_MANY_CHECKOUTS\" replace=\"For mange utlån\" />"
	print "\t\t<screen_msg_regex find=\"NOT_FOR_LOAN.*$\" replace=\"Materialet er ikke til utlån.\" />"
	print "\t\t<screen_msg_regex find=\"item_notforloan.*$\" replace=\"Materialet er ikke til utlån.\" />"
	print "\t\t<!-- Bug 15438 - Checking out an on-hold item sends holder's borrowernumber in AF (screen message) field. -->"
	print "\t\t<!-- gjelder også utlån av samme eksemplar to ganger -->"
	print "\t\t<screen_msg_regex find=\"^\d{1,}$\" replace=\"Materialet er allerede utlånt/reservert.\" />"
	print "\t\t<!-- Last resort -->"
	print "\t\t<screen_msg_regex find=\"Greetings from Koha.\" replace=\"Melding fra biblioteket:\" />"
	print "\t</login>"
}


POSIX { and delete
TODO: still not POSIX compatible due to "match()"

git-svn-id: 88e1a00e4eab3b0bb0c09889526309a3e2f5bd8a@23 c26eb9a1-5813-0410-bd6c-c2e55f420ca7

#!/usr/bin/awk -f
# vim:ts=4:sw=4
BEGIN {
	brace = 0;
	buffer_len = 0;
}
/^}.*;/ {
	if (instruct) {
		sub(";", "");
		if (instruct == 1 && $2) {
			instruct = $2;
		}
		if (instruct in typedefs) {
			instruct = typedefs[instruct];
		}
		elm = "";
		elms = "";
		for (i = 0; i in buffer; i ++) {
			if (i) elm = elm " + ";
			# elm = elm "sizeof(((`" instruct "'*)NULL)->`" buffer[i] "')";
			# elms = elms " `" buffer[i] "'";
			elm = elm "sizeof(((" instruct "*)NULL)->" buffer[i] ")";

			if (elms == "") {
				elms = buffer[i];
			}
			else {
				elms = elms "," buffer[i];
			}
		}
		printf "define(`ELEMENTSOF_%s', `%s')\n", instruct, elms;
		printf "define(`COUNTOF_%s', `%s')\n", instruct, i;
		printf "define(`SIZEOF_%s', `(  %s  )')\n", instruct, elm;
		print "\n";
		for (i in buffer) {
			delete buffer[i];
		}
		buffer_len = 0;
		instruct = 0;
	}
	next;
}

/.\{/ {
	brace = brace + 1;
}
/.}/ {
	brace = brace - 1;
}

{
	if (brace == 1 && instruct) {
		sub(/.*[{}]/, "");
		gsub(/\[[^\]]+\]/, "");
		gsub(/:[0-9]+/, "");
		str = $0;
		if (match(str, /\([ ]*\*([^)]+)\)/, a)) {
			buffer[buffer_len] = a[1];
			buffer_len ++;
		}
		else {
			while (gsub(/(\([^)]*\))/, "", str)) {
			}
			while (match(str, /([^*() ]+)[ ]*[,;](.*)/, a)) {
				buffer[buffer_len] = a[1];
				buffer_len ++;
				str = a[2];
			}
		}
		next;
	}
}

/^typedef struct [^{]*;/ {
	sub(";", "");
	typedefs[$3] = $4;
	next;
}
/^typedef struct .*\{/ {
	brace = 1;
	instruct = 1;
	next;
}

/^struct .*\{/ {
	instruct = $2;
	brace = 1;
	next;
}

#!/usr/bin/awk -f
# vim:ts=4:sw=4
BEGIN {
	brace = 0;
	delete buffer;
	buffer_len = 0;
}
/^}.*;/ {
	if (instruct) {
		sub(";", "");
		if (instruct == 1 && $2) {
			instruct = $2;
		}
		if (instruct in typedefs) {
			instruct = typedefs[instruct];
		}
		elm = "";
		elms = "";
		for (i = 0; i in buffer; i ++) {
			if (i) elm = elm " + ";
			# elm = elm "sizeof(((`" instruct "'*)NULL)->`" buffer[i] "')";
			# elms = elms " `" buffer[i] "'";
			elm = elm "sizeof(((" instruct "*)NULL)->" buffer[i] ")";

			if (elms == "") {
				elms = buffer[i];
			}
			else {
				elms = elms "," buffer[i];
			}
		}
		printf "define(`ELEMENTSOF_%s', `%s')\n", instruct, elms;
		printf "define(`COUNTOF_%s', `%s')\n", instruct, i;
		printf "define(`SIZEOF_%s', `(  %s  )')\n", instruct, elm;
		print "\n";
		delete buffer;
		buffer_len = 0;
		instruct = 0;
	}
	next;
}

/.{/ {
	brace = brace + 1;
}
/.}/ {
	brace = brace - 1;
}

{
	if (brace == 1 && instruct) {
		sub(/.*[{}]/, "");
		gsub(/\[[^\]]+\]/, "");
		gsub(/:[0-9]+/, "");
		str = $0;
		if (match(str, /\([ ]*\*([^)]+)\)/, a)) {
			buffer[buffer_len] = a[1];
			buffer_len ++;
		}
		else {
			while (gsub(/(\([^)]*\))/, "", str)) {
			}
			while (match(str, /([^*() ]+)[ ]*[,;](.*)/, a)) {
				buffer[buffer_len] = a[1];
				buffer_len ++;
				str = a[2];
			}
		}
		next;
	}
}

/^typedef struct [^{]*;/ {
	sub(";", "");
	typedefs[$3] = $4;
	next;
}
/^typedef struct .*{/ {
	brace = 1;
	instruct = 1;
	next;
}

/^struct .*{/ {
	instruct = $2;
	brace = 1;
	next;
}


Translators/GoogleTranslate: hint for autocorrection and handle -no-autocorrect option

####################################################################
# GoogleTranslate.awk                                              #
####################################################################
#
# Last Updated: 18 Dec 2015
# https://translate.google.com/translate/releases/twsfe_w_20151214_RC03/r/js/desktop_module_main.js
BEGIN { provides("google") }

function genRL(a, x,
               ####
               b, c, d, i, y) {
    tokenize(y, x)
    parseList(b, y)
    i = SUBSEP 0
    for (c = 0; c < length(b[i]) - 2; c += 3) {
        d = b[i][c + 2]
        d = d >= 97 ? d - 87 :
            d - 48 # convert to number
        d = b[i][c + 1] == 43 ? rshift(a, d) : lshift(a, d)
        a = b[i][c] == 43 ? and(a + d, 4294967295) : xor(a, d)
    }
    return a
}

function genTK(text,
               ####
               a, d, dLen, e, tkk, ub, vb) {
    if (TK[text]) return TK[text]

    tkk = systime() / 3600
    ub = "[43,45,51,94,43,98,43,45,102]"
    vb = "[43,45,97,94,43,54]"

    dLen = dump(text, d) # convert to byte array
    a = tkk
    for (e = 1; e <= dLen; e++)
        a = genRL(a + d[e], vb)
    a = genRL(a, ub)
    0 > a && (a = and(a, 2147483647) + 2147483648)
    a %= 1e6
    TK[text] = a "." xor(a, tkk)

    l(text, "text")
    l(tkk, "tkk")
    l(TK[text], "tk")
    return TK[text]
}

function googleInit() {
    HttpProtocol = "http://"
    HttpHost = "translate.googleapis.com"
    HttpPort = 80
}

function googleRequestUrl(text, sl, tl, hl,    qc) {
    qc = Option["no-autocorrect"] ? "qc" : "qca";
    return HttpPathPrefix "/translate_a/single?client=gtx"              \
        "&ie=UTF-8&oe=UTF-8"                                            \
        "&dt=bd&dt=ex&dt=ld&dt=md&dt=rw&dt=rm&dt=ss&dt=t&dt=at"         \
        "&dt=" qc "&sl=" sl "&tl=" tl "&hl=" hl                         \
        "&q=" preprocess(text)
}

function googleTTSUrl(text, tl) {
    return HttpProtocol HttpHost "/translate_tts?ie=UTF-8&client=gtx"	\
        "&tl=" tl "&q=" preprocess(text)
}

function googleWebTranslateUrl(uri, sl, tl, hl) {
    return "https://translate.google.com/translate?"    \
        "hl=" hl "&sl=" sl "&tl=" tl "&u=" uri
}

# Get the translation of a string.
function googleTranslate(text, sl, tl, hl,
                         isVerbose, toSpeech, returnPlaylist, returnIl,
                         ####
                         r,
                         content, tokens, ast,
                         _sl, _tl, _hl, il, ils, isPhonetic,
                         article, example, explanation, ref, word,
                         translation, translations, phonetics,
                         wordClasses, words, segments, altTranslations,
                         original, oPhonetics, oWordClasses, oWords,
                         oRefs, oSynonymClasses, oSynonyms,
                         oExamples, oSeeAlso,
                         wShowOriginal, wShowOriginalPhonetics,
                         wShowTranslation, wShowTranslationPhonetics,
                         wShowPromptMessage, wShowLanguages,
                         wShowOriginalDictionary, wShowDictionary,
                         wShowAlternatives,
                         hasWordClasses, hasAltTranslations,
                         i, j, k, group, temp, saveSortedIn) {
    isPhonetic = match(tl, /^@/)
    tl = substr(tl, 1 + isPhonetic)

    if (!getCode(tl)) {
        # Check if target language is supported
        w("[WARNING] Unknown target language code: " tl)
    } else if (isRTL(tl)) {
        # Check if target language is R-to-L
        if (!FriBidi)
            w("[WARNING] " getName(tl) " is a right-to-left language, but FriBidi is not found.")
    }

    # Convert codes or aliases to standard codes used by Google Translate
    # If the code or alias cannot be found, use as it is
    _sl = getCode(sl); if (!_sl) _sl = sl
    _tl = getCode(tl); if (!_tl) _tl = tl
    _hl = getCode(hl); if (!_hl) _hl = hl
    content = getResponse(text, _sl, _tl, _hl)
    tokenize(tokens, content)
    parseJsonArray(ast, tokens)

    l(content, "content", 1, 1)
    l(tokens, "tokens", 1, 0, 1)
    l(ast, "ast")
    if (!isarray(ast) || !anything(ast)) {
        e("[ERROR] Oops! Something went wrong and I can't translate it for you :(")
        ExitCode = 1
        return
    }

    saveSortedIn = PROCINFO["sorted_in"]
    PROCINFO["sorted_in"] = "@ind_num_asc"
    for (i in ast) {
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "0$")
            append(translations, postprocess(literal(ast[i])))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "1$")
            append(original, literal(ast[i]))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "2$")
            append(phonetics, literal(ast[i]))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "3$")
            append(oPhonetics, literal(ast[i]))

        # 1 - word classes and explanations
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            wordClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "([[:digit:]]+)$", group))
            words[group[1]][group[2]][group[3]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)$", group))
            words[group[1]][group[2]]["1"][group[3]] = literal(ast[i])

        # 5 - alternative translations
        if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) {
            segments[group[1]] = literal(ast[i])
            altTranslations[group[1]][0] = ""
        }
        if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            altTranslations[group[1]][group[2]] = postprocess(literal(ast[i]))

        # 7 - autocorrection
        if (i ~ "^0" SUBSEP "7" SUBSEP "5$")
            w("Showing translation for:  (use -no-auto to disable autocorrect)")

        # 8 - identified source languages
        if (i ~ "^0" SUBSEP "8" SUBSEP "0" SUBSEP "[[:digit:]]+$" ||
            i ~ "^0" SUBSEP "2$")
            append(ils, literal(ast[i]))

        # 11 - (original) word classes and synonyms
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oSynonymClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group))
            if (ast[i]) {
                oRefs[literal(ast[i])][1] = group[1]
                oRefs[literal(ast[i])][2] = group[2]
            }
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0" SUBSEP "([[:digit:]]+)$", group))
            oSynonyms[group[1]][group[2]][group[3]] = literal(ast[i])

        # 12 - (original) word classes and explanations
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oWordClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oWords[group[1]][group[2]][0] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group))
            oWords[group[1]][group[2]][1] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2$", group))
            oWords[group[1]][group[2]][2] = postprocess(literal(ast[i]))

        # 13 - (original) examples
        if (match(i, "^0" SUBSEP "13" SUBSEP "0" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oExamples[group[1]] = postprocess(literal(ast[i]))

        # 14 - (original) see also
        if (match(i, "^0" SUBSEP "14" SUBSEP "0" SUBSEP "([[:digit:]]+)$", group))
            oSeeAlso[group[1]] = literal(ast[i])
    }
    PROCINFO["sorted_in"] = saveSortedIn

    translation = join(translations)

    returnIl[0] = il = !anything(ils) || belongsTo(sl, ils) ? sl : ils[0]
    if (Option["verbose"] < 0)
        return getList(il)

    # Generate output
    if (!isVerbose) {
        # Brief mode

        r = isPhonetic && anything(phonetics) ?
            prettify("brief-translation-phonetics", join(phonetics)) :
            prettify("brief-translation", s(translation, tl))

        if (toSpeech) {
            returnPlaylist[0]["text"] = translation
            returnPlaylist[0]["tl"] = tl
        }

    } else {
        # Verbose mode

        wShowOriginal = Option["show-original"]
        wShowOriginalPhonetics = Option["show-original-phonetics"]
        wShowTranslation = Option["show-translation"]
        wShowTranslationPhonetics = Option["show-translation-phonetics"]
        wShowPromptMessage = Option["show-prompt-message"]
        wShowLanguages = Option["show-languages"]
        wShowOriginalDictionary = Option["show-original-dictionary"]
        wShowDictionary = Option["show-dictionary"]
        wShowAlternatives = Option["show-alternatives"]

        if (!anything(oPhonetics)) wShowOriginalPhonetics = 0
        if (!anything(phonetics)) wShowTranslationPhonetics = 0
        if (getCode(il) == getCode(tl) &&                               \
            (isarray(oWordClasses) || isarray(oSynonymClasses) ||       \
             isarray(oExamples) || isarray(oSeeAlso))) {
            wShowOriginalDictionary = 1
            wShowTranslation = 0
        }
        hasWordClasses = exists(wordClasses)
        hasAltTranslations = exists(altTranslations[0])
        if (!hasWordClasses && !hasAltTranslations)
            wShowPromptMessage = wShowLanguages = 0
        if (!hasWordClasses) wShowDictionary = 0
        if (hasWordClasses || !hasAltTranslations) wShowAlternatives = 0

        if (wShowOriginal) {
            # Display: original text & phonetics
            if (r) r = r RS RS
            r = r m("-- display original text & phonetics")
            r = r prettify("original", s(join(original), il))
            if (wShowOriginalPhonetics)
                r = r RS prettify("original-phonetics", showPhonetics(join(oPhonetics), il))
        }

        if (wShowTranslation) {
            # Display: major translation & phonetics
            if (r) r = r RS RS
            r = r m("-- display major translation & phonetics")
            r = r prettify("translation", s(translation, tl))
            if (wShowTranslationPhonetics)
                r = r RS prettify("translation-phonetics", showPhonetics(join(phonetics), tl))
        }

        if (wShowPromptMessage || wShowLanguages)
            if (r) r = r RS
        if (wShowPromptMessage) {
            if (hasWordClasses) {
                # Display: prompt message (Definitions of ...)
                if (r) r = r RS
                r = r m("-- display prompt message (Definitions of ...)")
                if (isRTL(hl)) # home language is R-to-L
                    r = r prettify("prompt-message", s(showDefinitionsOf(hl, join(original))))
                else { # home language is L-to-R
                    split(showDefinitionsOf(hl, "\0%s\0"), group, "\0")
                    for (i = 1; i <= length(group); i++) {
                        if (group[i] == "%s")
                            r = r prettify("prompt-message-original", show(join(original), il))
                        else
                            r = r prettify("prompt-message", group[i])
                    }
                }
            } else if (hasAltTranslations) {
                # Display: prompt message (Translations of ...)
                if (r) r = r RS
                r = r m("-- display prompt message (Translations of ...)")
                if (isRTL(hl)) # home language is R-to-L
                    r = r prettify("prompt-message", s(showTranslationsOf(hl, join(original))))
                else { # home language is L-to-R
                    split(showTranslationsOf(hl, "\0%s\0"), group, "\0")
                    for (i = 1; i <= length(group); i++) {
                        if (group[i] == "%s")
                            r = r prettify("prompt-message-original", show(join(original), il))
                        else
                            r = r prettify("prompt-message", group[i])
                    }
                }
            }
        }
        if (wShowLanguages) {
            # Display: source language -> target language
            if (r) r = r RS
            r = r m("-- display source language -> target language")
            temp = Option["fmt-languages"]
            if (!temp) temp = "[ %s -> %t ]"
            split(temp, group, /(%s|%S|%t|%T)/)
            r = r prettify("languages", group[1])
            if (temp ~ /%s/)
                r = r prettify("languages-sl", getDisplay(il))
            if (temp ~ /%S/)
                r = r prettify("languages-sl", getName(il))
            r = r prettify("languages", group[2])
            if (temp ~ /%t/)
                r = r prettify("languages-tl", getDisplay(tl))
            if (temp ~ /%T/)
                r = r prettify("languages-tl", getName(tl))
            r = r prettify("languages", group[3])
        }

        if (wShowOriginalDictionary) {
            # Display: original dictionary
            if (exists(oWordClasses)) {
                # Detailed explanations
                if (r) r = r RS
                r = r m("-- display original dictionary (detailed explanations)")
                for (i = 0; i < length(oWordClasses); i++) {
                    r = (i > 0 ? r RS : r) RS prettify("original-dictionary-detailed-word-class", s(oWordClasses[i], hl))
                    for (j = 0; j < length(oWords[i]); j++) {
                        explanation = oWords[i][j][0]
                        ref = oWords[i][j][1]
                        example = oWords[i][j][2]

                        r = (j > 0 ? r RS : r) RS prettify("original-dictionary-detailed-explanation", ins(1, explanation, il))
                        if (example)
                            r = r RS prettify("original-dictionary-detailed-example", ins(2, "- \"" example "\"", il))
                        if (ref && isarray(oRefs[ref])) {
                            temp = prettify("original-dictionary-detailed-synonyms", ins(1, show(showSynonyms(hl), hl) ": "))
                            temp = temp prettify("original-dictionary-detailed-synonyms-item", show(oSynonyms[oRefs[ref][1]][oRefs[ref][2]][0], il))
                            for (k = 1; k < length(oSynonyms[oRefs[ref][1]][oRefs[ref][2]]); k++)
                                temp = temp prettify("original-dictionary-detailed-synonyms", ", ") \
                                    prettify("original-dictionary-detailed-synonyms-item", show(oSynonyms[oRefs[ref][1]][oRefs[ref][2]][k], il))
                            r = r RS temp
                        }
                    }
                }
            }
            if (exists(oSynonymClasses)) {
                # Synonyms
                r = r RS RS
                r = r m("-- display original dictionary (synonyms)")
                r = r prettify("original-dictionary-synonyms", s(showSynonyms(hl), hl))
                for (i = 0; i < length(oSynonymClasses); i++) {
                    r = (i > 0 ? r RS : r) RS prettify("original-dictionary-synonyms-word-class", ins(1, oSynonymClasses[i], hl))
                    for (j = 0; j < length(oSynonyms[i]); j++) {
                        temp = prettify("original-dictionary-synonyms-synonyms", ins(2, "- "))
                        temp = temp prettify("original-dictionary-synonyms-synonyms-item", show(oSynonyms[i][j][0], il))
                        for (k = 1; k < length(oSynonyms[i][j]); k++)
                            temp = temp prettify("original-dictionary-synonyms-synonyms", ", ") \
                                prettify("original-dictionary-synonyms-synonyms-item", show(oSynonyms[i][j][k], il))
                        r = r RS temp
                    }
                }
            }
            if (exists(oExamples)) {
                # Examples
                r = r RS RS
                r = r m("-- display original dictionary (examples)")
                r = r prettify("original-dictionary-examples", s(showExamples(hl), hl))
                for (i = 0; i < length(oExamples); i++) {
                    example = oExamples[i]

                    temp = prettify("original-dictionary-examples-example", ins(1, "- "))
                    split(example, group, /(\u003cb\u003e|\u003c\/b\u003e)/)
                    if (isRTL(il)) # target language is R-to-L
                        temp = temp show(group[1] group[2] group[3], il)
                    else # target language is L-to-R
                        temp = temp prettify("original-dictionary-examples-example", group[1]) \
                            prettify("original-dictionary-examples-original", group[2]) \
                            prettify("original-dictionary-examples-example", group[3])
                    r = (i > 0 ? r RS : r) RS temp
                }
            }
            if (exists(oSeeAlso)) {
                # See also
                r = r RS RS
                r = r m("-- display original dictionary (see also)")
                r = r prettify("original-dictionary-see-also", s(showSeeAlso(hl), hl))
                temp = ins(1, prettify("original-dictionary-see-also-phrases-item", show(oSeeAlso[0], il)))
                for (k = 1; k < length(oSeeAlso); k++)
                    temp = temp prettify("original-dictionary-see-also-phrases", ", ") \
                        prettify("original-dictionary-see-also-phrases-item", show(oSeeAlso[k], il))
                r = r RS temp
            }
        }

        if (wShowDictionary) {
            # Display: dictionary entries
            if (r) r = r RS
            r = r m("-- display dictionary entries")
            for (i = 0; i < length(wordClasses); i++) {
                r = (i > 0 ? r RS : r) RS prettify("dictionary-word-class", s(wordClasses[i], hl))
                for (j = 0; j < length(words[i]); j++) {
                    word = words[i][j][0]
                    article = words[i][j][4]
                    if (isRTL(il))
                        explanation = join(words[i][j][1], ", ")
                    else {
                        explanation = prettify("dictionary-explanation-item", words[i][j][1][0])
                        for (k = 1; k < length(words[i][j][1]); k++)
                            explanation = explanation prettify("dictionary-explanation", ", ") \
                                prettify("dictionary-explanation-item", words[i][j][1][k])
                    }

                    r = r RS prettify("dictionary-word", ins(1, (article ? "(" article ") " : "") word, tl))
                    if (isRTL(il))
                        r = r RS prettify("dictionary-explanation-item", ins(2, explanation, il))
                    else
                        r = r RS ins(2, explanation)
                }
            }
        }

        if (wShowAlternatives) {
            # Display: alternative translations
            if (r) r = r RS RS
            r = r m("-- display alternative translations")
            for (i = 0; i < length(altTranslations); i++) {
                r = (i > 0 ? r RS : r) prettify("alternatives-original", show(segments[i], il))
                if (isRTL(tl)) {
                    temp = join(altTranslations[i], ", ")
                    r = r RS prettify("alternatives-translations-item", ins(1, temp, tl))
                } else {
                    temp = prettify("alternatives-translations-item", altTranslations[i][0])
                    for (j = 1; j < length(altTranslations[i]); j++)
                        temp = temp prettify("alternatives-translations", ", ") \
                            prettify("alternatives-translations-item", altTranslations[i][j])
                    r = r RS ins(1, temp)
                }
            }
        }

        if (toSpeech) {
            if (index(showTranslationsOf(hl, "%s"), "%s") > 2) {
                returnPlaylist[0]["text"] = showTranslationsOf(hl)
                returnPlaylist[0]["tl"] = hl
                returnPlaylist[1]["text"] = join(original)
                returnPlaylist[1]["tl"] = il
            } else {
                returnPlaylist[0]["text"] = join(original)
                returnPlaylist[0]["tl"] = il
                returnPlaylist[1]["text"] = showTranslationsOf(hl)
                returnPlaylist[1]["tl"] = hl
            }
            returnPlaylist[2]["text"] = translation
            returnPlaylist[2]["tl"] = tl
        }
    }

    return r
}

####################################################################
# GoogleTranslate.awk                                              #
####################################################################
#
# Last Updated: 18 Dec 2015
# https://translate.google.com/translate/releases/twsfe_w_20151214_RC03/r/js/desktop_module_main.js
BEGIN { provides("google") }

function genRL(a, x,
               ####
               b, c, d, i, y) {
    tokenize(y, x)
    parseList(b, y)
    i = SUBSEP 0
    for (c = 0; c < length(b[i]) - 2; c += 3) {
        d = b[i][c + 2]
        d = d >= 97 ? d - 87 :
            d - 48 # convert to number
        d = b[i][c + 1] == 43 ? rshift(a, d) : lshift(a, d)
        a = b[i][c] == 43 ? and(a + d, 4294967295) : xor(a, d)
    }
    return a
}

function genTK(text,
               ####
               a, d, dLen, e, tkk, ub, vb) {
    if (TK[text]) return TK[text]

    tkk = systime() / 3600
    ub = "[43,45,51,94,43,98,43,45,102]"
    vb = "[43,45,97,94,43,54]"

    dLen = dump(text, d) # convert to byte array
    a = tkk
    for (e = 1; e <= dLen; e++)
        a = genRL(a + d[e], vb)
    a = genRL(a, ub)
    0 > a && (a = and(a, 2147483647) + 2147483648)
    a %= 1e6
    TK[text] = a "." xor(a, tkk)

    l(text, "text")
    l(tkk, "tkk")
    l(TK[text], "tk")
    return TK[text]
}

function googleInit() {
    HttpProtocol = "http://"
    HttpHost = "translate.googleapis.com"
    HttpPort = 80
}

function googleRequestUrl(text, sl, tl, hl) {
    return HttpPathPrefix "/translate_a/single?client=gtx"              \
        "&ie=UTF-8&oe=UTF-8"                                            \
        "&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&dt=at"  \
        "&sl=" sl "&tl=" tl "&hl=" hl                                   \
        "&q=" preprocess(text)
}

function googleTTSUrl(text, tl) {
    return HttpProtocol HttpHost "/translate_tts?ie=UTF-8&client=gtx"	\
        "&tl=" tl "&q=" preprocess(text)
}

function googleWebTranslateUrl(uri, sl, tl, hl) {
    return "https://translate.google.com/translate?"    \
        "hl=" hl "&sl=" sl "&tl=" tl "&u=" uri
}

# Get the translation of a string.
function googleTranslate(text, sl, tl, hl,
                         isVerbose, toSpeech, returnPlaylist, returnIl,
                         ####
                         r,
                         content, tokens, ast,
                         _sl, _tl, _hl, il, ils, isPhonetic,
                         article, example, explanation, ref, word,
                         translation, translations, phonetics,
                         wordClasses, words, segments, altTranslations,
                         original, oPhonetics, oWordClasses, oWords,
                         oRefs, oSynonymClasses, oSynonyms,
                         oExamples, oSeeAlso,
                         wShowOriginal, wShowOriginalPhonetics,
                         wShowTranslation, wShowTranslationPhonetics,
                         wShowPromptMessage, wShowLanguages,
                         wShowOriginalDictionary, wShowDictionary,
                         wShowAlternatives,
                         hasWordClasses, hasAltTranslations,
                         i, j, k, group, temp, saveSortedIn) {
    isPhonetic = match(tl, /^@/)
    tl = substr(tl, 1 + isPhonetic)

    if (!getCode(tl)) {
        # Check if target language is supported
        w("[WARNING] Unknown target language code: " tl)
    } else if (isRTL(tl)) {
        # Check if target language is R-to-L
        if (!FriBidi)
            w("[WARNING] " getName(tl) " is a right-to-left language, but FriBidi is not found.")
    }

    # Convert codes or aliases to standard codes used by Google Translate
    # If the code or alias cannot be found, use as it is
    _sl = getCode(sl); if (!_sl) _sl = sl
    _tl = getCode(tl); if (!_tl) _tl = tl
    _hl = getCode(hl); if (!_hl) _hl = hl
    content = getResponse(text, _sl, _tl, _hl)
    tokenize(tokens, content)
    parseJsonArray(ast, tokens)

    l(content, "content", 1, 1)
    l(tokens, "tokens", 1, 0, 1)
    l(ast, "ast")
    if (!isarray(ast) || !anything(ast)) {
        e("[ERROR] Oops! Something went wrong and I can't translate it for you :(")
        ExitCode = 1
        return
    }

    saveSortedIn = PROCINFO["sorted_in"]
    PROCINFO["sorted_in"] = "@ind_num_asc"
    for (i in ast) {
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "0$")
            append(translations, postprocess(literal(ast[i])))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "1$")
            append(original, literal(ast[i]))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "2$")
            append(phonetics, literal(ast[i]))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "3$")
            append(oPhonetics, literal(ast[i]))

        # 1 - word classes and explanations
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            wordClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "([[:digit:]]+)$", group))
            words[group[1]][group[2]][group[3]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)$", group))
            words[group[1]][group[2]]["1"][group[3]] = literal(ast[i])

        # 5 - alternative translations
        if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) {
            segments[group[1]] = literal(ast[i])
            altTranslations[group[1]][0] = ""
        }
        if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            altTranslations[group[1]][group[2]] = postprocess(literal(ast[i]))

        # 8 - identified source languages
        if (i ~ "^0" SUBSEP "8" SUBSEP "0" SUBSEP "[[:digit:]]+$" ||
            i ~ "^0" SUBSEP "2$")
            append(ils, literal(ast[i]))

        # 11 - (original) word classes and synonyms
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oSynonymClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group))
            if (ast[i]) {
                oRefs[literal(ast[i])][1] = group[1]
                oRefs[literal(ast[i])][2] = group[2]
            }
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0" SUBSEP "([[:digit:]]+)$", group))
            oSynonyms[group[1]][group[2]][group[3]] = literal(ast[i])

        # 12 - (original) word classes and explanations
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oWordClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oWords[group[1]][group[2]][0] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group))
            oWords[group[1]][group[2]][1] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2$", group))
            oWords[group[1]][group[2]][2] = postprocess(literal(ast[i]))

        # 13 - (original) examples
        if (match(i, "^0" SUBSEP "13" SUBSEP "0" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oExamples[group[1]] = postprocess(literal(ast[i]))

        # 14 - (original) see also
        if (match(i, "^0" SUBSEP "14" SUBSEP "0" SUBSEP "([[:digit:]]+)$", group))
            oSeeAlso[group[1]] = literal(ast[i])
    }
    PROCINFO["sorted_in"] = saveSortedIn

    translation = join(translations)

    returnIl[0] = il = !anything(ils) || belongsTo(sl, ils) ? sl : ils[0]
    if (Option["verbose"] < 0)
        return getList(il)

    # Generate output
    if (!isVerbose) {
        # Brief mode

        r = isPhonetic && anything(phonetics) ?
            prettify("brief-translation-phonetics", join(phonetics)) :
            prettify("brief-translation", s(translation, tl))

        if (toSpeech) {
            returnPlaylist[0]["text"] = translation
            returnPlaylist[0]["tl"] = tl
        }

    } else {
        # Verbose mode

        wShowOriginal = Option["show-original"]
        wShowOriginalPhonetics = Option["show-original-phonetics"]
        wShowTranslation = Option["show-translation"]
        wShowTranslationPhonetics = Option["show-translation-phonetics"]
        wShowPromptMessage = Option["show-prompt-message"]
        wShowLanguages = Option["show-languages"]
        wShowOriginalDictionary = Option["show-original-dictionary"]
        wShowDictionary = Option["show-dictionary"]
        wShowAlternatives = Option["show-alternatives"]

        if (!anything(oPhonetics)) wShowOriginalPhonetics = 0
        if (!anything(phonetics)) wShowTranslationPhonetics = 0
        if (getCode(il) == getCode(tl) &&                               \
            (isarray(oWordClasses) || isarray(oSynonymClasses) ||       \
             isarray(oExamples) || isarray(oSeeAlso))) {
            wShowOriginalDictionary = 1
            wShowTranslation = 0
        }
        hasWordClasses = exists(wordClasses)
        hasAltTranslations = exists(altTranslations[0])
        if (!hasWordClasses && !hasAltTranslations)
            wShowPromptMessage = wShowLanguages = 0
        if (!hasWordClasses) wShowDictionary = 0
        if (hasWordClasses || !hasAltTranslations) wShowAlternatives = 0

        if (wShowOriginal) {
            # Display: original text & phonetics
            if (r) r = r RS RS
            r = r m("-- display original text & phonetics")
            r = r prettify("original", s(join(original), il))
            if (wShowOriginalPhonetics)
                r = r RS prettify("original-phonetics", showPhonetics(join(oPhonetics), il))
        }

        if (wShowTranslation) {
            # Display: major translation & phonetics
            if (r) r = r RS RS
            r = r m("-- display major translation & phonetics")
            r = r prettify("translation", s(translation, tl))
            if (wShowTranslationPhonetics)
                r = r RS prettify("translation-phonetics", showPhonetics(join(phonetics), tl))
        }

        if (wShowPromptMessage || wShowLanguages)
            if (r) r = r RS
        if (wShowPromptMessage) {
            if (hasWordClasses) {
                # Display: prompt message (Definitions of ...)
                if (r) r = r RS
                r = r m("-- display prompt message (Definitions of ...)")
                if (isRTL(hl)) # home language is R-to-L
                    r = r prettify("prompt-message", s(showDefinitionsOf(hl, join(original))))
                else { # home language is L-to-R
                    split(showDefinitionsOf(hl, "\0%s\0"), group, "\0")
                    for (i = 1; i <= length(group); i++) {
                        if (group[i] == "%s")
                            r = r prettify("prompt-message-original", show(join(original), il))
                        else
                            r = r prettify("prompt-message", group[i])
                    }
                }
            } else if (hasAltTranslations) {
                # Display: prompt message (Translations of ...)
                if (r) r = r RS
                r = r m("-- display prompt message (Translations of ...)")
                if (isRTL(hl)) # home language is R-to-L
                    r = r prettify("prompt-message", s(showTranslationsOf(hl, join(original))))
                else { # home language is L-to-R
                    split(showTranslationsOf(hl, "\0%s\0"), group, "\0")
                    for (i = 1; i <= length(group); i++) {
                        if (group[i] == "%s")
                            r = r prettify("prompt-message-original", show(join(original), il))
                        else
                            r = r prettify("prompt-message", group[i])
                    }
                }
            }
        }
        if (wShowLanguages) {
            # Display: source language -> target language
            if (r) r = r RS
            r = r m("-- display source language -> target language")
            temp = Option["fmt-languages"]
            if (!temp) temp = "[ %s -> %t ]"
            split(temp, group, /(%s|%S|%t|%T)/)
            r = r prettify("languages", group[1])
            if (temp ~ /%s/)
                r = r prettify("languages-sl", getDisplay(il))
            if (temp ~ /%S/)
                r = r prettify("languages-sl", getName(il))
            r = r prettify("languages", group[2])
            if (temp ~ /%t/)
                r = r prettify("languages-tl", getDisplay(tl))
            if (temp ~ /%T/)
                r = r prettify("languages-tl", getName(tl))
            r = r prettify("languages", group[3])
        }

        if (wShowOriginalDictionary) {
            # Display: original dictionary
            if (exists(oWordClasses)) {
                # Detailed explanations
                if (r) r = r RS
                r = r m("-- display original dictionary (detailed explanations)")
                for (i = 0; i < length(oWordClasses); i++) {
                    r = (i > 0 ? r RS : r) RS prettify("original-dictionary-detailed-word-class", s(oWordClasses[i], hl))
                    for (j = 0; j < length(oWords[i]); j++) {
                        explanation = oWords[i][j][0]
                        ref = oWords[i][j][1]
                        example = oWords[i][j][2]

                        r = (j > 0 ? r RS : r) RS prettify("original-dictionary-detailed-explanation", ins(1, explanation, il))
                        if (example)
                            r = r RS prettify("original-dictionary-detailed-example", ins(2, "- \"" example "\"", il))
                        if (ref && isarray(oRefs[ref])) {
                            temp = prettify("original-dictionary-detailed-synonyms", ins(1, show(showSynonyms(hl), hl) ": "))
                            temp = temp prettify("original-dictionary-detailed-synonyms-item", show(oSynonyms[oRefs[ref][1]][oRefs[ref][2]][0], il))
                            for (k = 1; k < length(oSynonyms[oRefs[ref][1]][oRefs[ref][2]]); k++)
                                temp = temp prettify("original-dictionary-detailed-synonyms", ", ") \
                                    prettify("original-dictionary-detailed-synonyms-item", show(oSynonyms[oRefs[ref][1]][oRefs[ref][2]][k], il))
                            r = r RS temp
                        }
                    }
                }
            }
            if (exists(oSynonymClasses)) {
                # Synonyms
                r = r RS RS
                r = r m("-- display original dictionary (synonyms)")
                r = r prettify("original-dictionary-synonyms", s(showSynonyms(hl), hl))
                for (i = 0; i < length(oSynonymClasses); i++) {
                    r = (i > 0 ? r RS : r) RS prettify("original-dictionary-synonyms-word-class", ins(1, oSynonymClasses[i], hl))
                    for (j = 0; j < length(oSynonyms[i]); j++) {
                        temp = prettify("original-dictionary-synonyms-synonyms", ins(2, "- "))
                        temp = temp prettify("original-dictionary-synonyms-synonyms-item", show(oSynonyms[i][j][0], il))
                        for (k = 1; k < length(oSynonyms[i][j]); k++)
                            temp = temp prettify("original-dictionary-synonyms-synonyms", ", ") \
                                prettify("original-dictionary-synonyms-synonyms-item", show(oSynonyms[i][j][k], il))
                        r = r RS temp
                    }
                }
            }
            if (exists(oExamples)) {
                # Examples
                r = r RS RS
                r = r m("-- display original dictionary (examples)")
                r = r prettify("original-dictionary-examples", s(showExamples(hl), hl))
                for (i = 0; i < length(oExamples); i++) {
                    example = oExamples[i]

                    temp = prettify("original-dictionary-examples-example", ins(1, "- "))
                    split(example, group, /(\u003cb\u003e|\u003c\/b\u003e)/)
                    if (isRTL(il)) # target language is R-to-L
                        temp = temp show(group[1] group[2] group[3], il)
                    else # target language is L-to-R
                        temp = temp prettify("original-dictionary-examples-example", group[1]) \
                            prettify("original-dictionary-examples-original", group[2]) \
                            prettify("original-dictionary-examples-example", group[3])
                    r = (i > 0 ? r RS : r) RS temp
                }
            }
            if (exists(oSeeAlso)) {
                # See also
                r = r RS RS
                r = r m("-- display original dictionary (see also)")
                r = r prettify("original-dictionary-see-also", s(showSeeAlso(hl), hl))
                temp = ins(1, prettify("original-dictionary-see-also-phrases-item", show(oSeeAlso[0], il)))
                for (k = 1; k < length(oSeeAlso); k++)
                    temp = temp prettify("original-dictionary-see-also-phrases", ", ") \
                        prettify("original-dictionary-see-also-phrases-item", show(oSeeAlso[k], il))
                r = r RS temp
            }
        }

        if (wShowDictionary) {
            # Display: dictionary entries
            if (r) r = r RS
            r = r m("-- display dictionary entries")
            for (i = 0; i < length(wordClasses); i++) {
                r = (i > 0 ? r RS : r) RS prettify("dictionary-word-class", s(wordClasses[i], hl))
                for (j = 0; j < length(words[i]); j++) {
                    word = words[i][j][0]
                    article = words[i][j][4]
                    if (isRTL(il))
                        explanation = join(words[i][j][1], ", ")
                    else {
                        explanation = prettify("dictionary-explanation-item", words[i][j][1][0])
                        for (k = 1; k < length(words[i][j][1]); k++)
                            explanation = explanation prettify("dictionary-explanation", ", ") \
                                prettify("dictionary-explanation-item", words[i][j][1][k])
                    }

                    r = r RS prettify("dictionary-word", ins(1, (article ? "(" article ") " : "") word, tl))
                    if (isRTL(il))
                        r = r RS prettify("dictionary-explanation-item", ins(2, explanation, il))
                    else
                        r = r RS ins(2, explanation)
                }
            }
        }

        if (wShowAlternatives) {
            # Display: alternative translations
            if (r) r = r RS RS
            r = r m("-- display alternative translations")
            for (i = 0; i < length(altTranslations); i++) {
                r = (i > 0 ? r RS : r) prettify("alternatives-original", show(segments[i], il))
                if (isRTL(tl)) {
                    temp = join(altTranslations[i], ", ")
                    r = r RS prettify("alternatives-translations-item", ins(1, temp, tl))
                } else {
                    temp = prettify("alternatives-translations-item", altTranslations[i][0])
                    for (j = 1; j < length(altTranslations[i]); j++)
                        temp = temp prettify("alternatives-translations", ", ") \
                            prettify("alternatives-translations-item", altTranslations[i][j])
                    r = r RS ins(1, temp)
                }
            }
        }

        if (toSpeech) {
            if (index(showTranslationsOf(hl, "%s"), "%s") > 2) {
                returnPlaylist[0]["text"] = showTranslationsOf(hl)
                returnPlaylist[0]["tl"] = hl
                returnPlaylist[1]["text"] = join(original)
                returnPlaylist[1]["tl"] = il
            } else {
                returnPlaylist[0]["text"] = join(original)
                returnPlaylist[0]["tl"] = il
                returnPlaylist[1]["text"] = showTranslationsOf(hl)
                returnPlaylist[1]["tl"] = hl
            }
            returnPlaylist[2]["text"] = translation
            returnPlaylist[2]["tl"] = tl
        }
    }

    return r
}


Commons: add SUPOUT

Commons: add SUPOUT

####################################################################
# Commons.awk                                                      #
#                                                                  #
# Commonly used constants and functions.                           #
####################################################################

# Initialize constants.
function initConst() {
    STDIN  = "/dev/stdin"
    STDOUT = "/dev/stdout"
    STDERR = "/dev/stderr"

    SUPOUT = " > /dev/null "  # suppress output
    SUPERR = " 2> /dev/null " # suppress error
}

# Initialize `UrlEncoding`.
# See: <https://en.wikipedia.org/wiki/Percent-encoding>
function initUrlEncoding() {
    UrlEncoding["\n"] = "%0A"
    UrlEncoding[" "]  = "%20"
    UrlEncoding["!"]  = "%21"
    UrlEncoding["\""] = "%22"
    UrlEncoding["#"]  = "%23"
    UrlEncoding["$"]  = "%24"
    UrlEncoding["%"]  = "%25"
    UrlEncoding["&"]  = "%26"
    UrlEncoding["'"]  = "%27"
    UrlEncoding["("]  = "%28"
    UrlEncoding[")"]  = "%29"
    UrlEncoding["*"]  = "%2A"
    UrlEncoding["+"]  = "%2B"
    UrlEncoding[","]  = "%2C"
    UrlEncoding["-"]  = "%2D"
    UrlEncoding["."]  = "%2E"
    UrlEncoding["/"]  = "%2F"
    UrlEncoding[":"]  = "%3A"
    UrlEncoding[";"]  = "%3B"
    UrlEncoding["<"]  = "%3C"
    UrlEncoding["="]  = "%3D"
    UrlEncoding[">"]  = "%3E"
    UrlEncoding["?"]  = "%3F"
    UrlEncoding["@"]  = "%40"
    UrlEncoding["["]  = "%5B"
    UrlEncoding["\\"] = "%5C"
    UrlEncoding["]"]  = "%5D"
    UrlEncoding["^"]  = "%5E"
    UrlEncoding["_"]  = "%5F"
    UrlEncoding["`"]  = "%60"
    UrlEncoding["{"]  = "%7B"
    UrlEncoding["|"]  = "%7C"
    UrlEncoding["}"]  = "%7D"
    UrlEncoding["~"]  = "%7E"
}

# Return the real character represented by an escape sequence.
# Example: escapeChar("n") returns "\n".
# See: <https://en.wikipedia.org/wiki/Escape_character>
#      <https://en.wikipedia.org/wiki/Escape_sequences_in_C>
function escapeChar(char) {
    switch (char) {
    case "b":
        return "\b" # Backspace
    case "f":
        return "\f" # Formfeed
    case "n":
        return "\n" # Newline (Line Feed)
    case "r":
        return "\r" # Carriage Return
    case "t":
        return "\t" # Horizontal Tab
    case "v":
        return "\v" # Vertical Tab
    default:
        return char
    }
}

# Convert a literal-formatted string into its original string.
function literal(string,
                 ####
                 c, escaping, i, s) {
    if (string !~ /^".*"$/)
        return string

    split(string, s, "")
    string = ""
    escaping = 0
    for (i = 2; i < length(s); i++) {
        c = s[i]
        if (escaping) {
            string = string escapeChar(c)
            escaping = 0 # escape ends
        } else {
            if (c == "\\")
                escaping = 1 # escape begins
            else
                string = string c
        }
    }
    return string
}

# Return the escaped string.
function escape(string) {
    gsub(/"/, "\\\"", string)
    gsub(/\\/, "\\\\", string)
    return string
}

# Return the escaped, quoted string.
function parameterize(string, quotationMark) {
    if (!quotationMark)
        quotationMark = "'"

    if (quotationMark == "'") {
        gsub(/'/, "'\\''", string)
        return "'" string "'"
    } else {
        return "\"" escape(string) "\""
    }
}

# Return the URL-encoded string.
function quote(string,    i, r, s) {
    r = ""
    split(string, s, "")
    for (i = 1; i <= length(s); i++)
        r = r (s[i] in UrlEncoding ? UrlEncoding[s[i]] : s[i])
    return r
}

# Replicate a string.
function replicate(string, len,
                   ####
                   i, temp) {
    temp = ""
    for (i = 0; i < len; i++)
        temp = temp string
    return temp
}

# Squeeze a source line of AWK code.
function squeeze(line, preserveIndent) {
    # Remove preceding spaces if indentation not preserved
    if (!preserveIndent)
        gsub(/^[[:space:]]+/, "", line)
    # Remove comment
    gsub(/^[[:space:]]*#.*$/, "", line)
    # Remove in-line comment
    gsub(/#[^"]*$/, "", line)
    # Remove trailing spaces
    gsub(/[[:space:]]+$/, "", line)
    gsub(/[[:space:]]+\\$/, "\\", line)

    return line
}

# Return 1 if the array contains anything; otherwise return 0.
function anything(array,
                  ####
                  i) {
    for (i in array)
        if (array[i]) return 1
    return 0
}

# Append an element into an array (zero-based).
function append(array, element) {
    array[anything(array) ? length(array) : 0] = element
}

# Return an element if it belongs to the array;
# Otherwise, return a null string.
function belongsTo(element, array,
                   ####
                   i) {
    for (i in array)
        if (element == array[i]) return element
    return ""
}

# Return one of the substrings if the string starts with it;
# Otherwise, return a null string.
function startsWithAny(string, substrings,
                       ####
                       i) {
    for (i in substrings)
        if (index(string, substrings[i]) == 1) return substrings[i]
    return ""
}

# Return one of the patterns if the string matches this pattern at the beginning;
# Otherwise, return a null string.
function matchesAny(string, patterns,
                    ####
                    i) {
    for (i in patterns)
        if (string ~ "^" patterns[i]) return patterns[i]
    return ""
}

# Join an array into one string;
# Return the string.
function join(array, separator, sortedIn, preserveNull,
              ####
              i, j, saveSortedIn, temp) {
    # Default parameters
    if (!separator)
        separator = " "
    if (!sortedIn)
        sortedIn = "@ind_num_asc"

    temp = ""
    j = 0
    saveSortedIn = PROCINFO["sorted_in"]
    if (length(array)) {
        PROCINFO["sorted_in"] = sortedIn
        for (i in array)
            if (preserveNull || array[i] != "")
                temp = j++ ? temp separator array[i] : array[i]
        PROCINFO["sorted_in"] = saveSortedIn
    } else
        temp = array # array is empty string

    return temp
}

# Return 0 if the string starts with '0', 'f' or 'n';
# Otherwise, return 1.
function yn(string) {
    return (tolower(string) ~ /^[0fn]/) ? 0 : 1
}

# Initialize ANSI escape codes for SGR (Select Graphic Rendition).
# (ANSI X3.64 Standard Control Sequences)
# See: <https://en.wikipedia.org/wiki/ANSI_escape_code>
function initAnsiCode() {
    # Dumb terminal: no ANSI escape code whatsoever
    if (ENVIRON["TERM"] == "dumb") return

    AnsiCode["reset"]         = AnsiCode[0] = "\33[0m"

    AnsiCode["bold"]          = "\33[1m"
    AnsiCode["underline"]     = "\33[4m"
    AnsiCode["negative"]      = "\33[7m"
    AnsiCode["no bold"]       = "\33[22m" # SGR code 21 (bold off) not widely supported
    AnsiCode["no underline"]  = "\33[24m"
    AnsiCode["positive"]      = "\33[27m"

    AnsiCode["black"]         = "\33[30m"
    AnsiCode["red"]           = "\33[31m"
    AnsiCode["green"]         = "\33[32m"
    AnsiCode["yellow"]        = "\33[33m"
    AnsiCode["blue"]          = "\33[34m"
    AnsiCode["magenta"]       = "\33[35m"
    AnsiCode["cyan"]          = "\33[36m"
    AnsiCode["gray"]          = "\33[37m"

    AnsiCode["default"]       = "\33[39m"

    AnsiCode["dark gray"]     = "\33[90m"
    AnsiCode["light red"]     = "\33[91m"
    AnsiCode["light green"]   = "\33[92m"
    AnsiCode["light yellow"]  = "\33[93m"
    AnsiCode["light blue"]    = "\33[94m"
    AnsiCode["light magenta"] = "\33[95m"
    AnsiCode["light cyan"]    = "\33[96m"
    AnsiCode["white"]         = "\33[97m"
}

# Return ANSI escaped string.
function ansi(code, text) {
    switch (code) {
    case "bold":
        return AnsiCode[code] text AnsiCode["no bold"]
    case "underline":
        return AnsiCode[code] text AnsiCode["no underline"]
    case "negative":
        return AnsiCode[code] text AnsiCode["positive"]
    default:
        return AnsiCode[code] text AnsiCode[0]
    }
}

# Print warning message.
function w(text) {
    print ansi("yellow", text) > STDERR
}

# Print error message.
function e(text) {
    print ansi("bold", ansi("red", text)) > STDERR
}

# Print debugging message.
function d(text) {
    print ansi("gray", text) > STDERR
}

# Log an array.
function da(array, formatString, sortedIn,
            ####
            i, j, saveSortedIn) {
    # Default parameters
    if (!formatString)
        formatString = "_[%s]='%s'"
    if (!sortedIn)
        sortedIn = "@ind_num_asc"

    saveSortedIn = PROCINFO["sorted_in"]
    PROCINFO["sorted_in"] = sortedIn
    for (i in array) {
        split(i, j, SUBSEP)
        d(sprintf(formatString, join(j, ","), array[i]))
    }
    PROCINFO["sorted_in"] = saveSortedIn
}

# Naive assertion.
function assert(x, message) {
    if (!message)
        message = "[ERROR] Assertion failed."

    if (x)
        return x
    else
        e(message)
}

# Return non-zero if file exists, otherwise return 0.
function fileExists(file) {
    return !system("test -f " file)
}

# Initialize `UriSchemes`.
function initUriSchemes() {
    UriSchemes[0] = "file://"
    UriSchemes[1] = "http://"
    UriSchemes[2] = "https://"
}

BEGIN {
    initConst()

    initUrlEncoding()
    initAnsiCode()
    initUriSchemes()
}

####################################################################
# Commons.awk                                                      #
#                                                                  #
# Commonly used constants and functions.                           #
####################################################################

# Initialize constants.
function initConst() {
    STDIN  = "/dev/stdin"
    STDOUT = "/dev/stdout"
    STDERR = "/dev/stderr"

    SUPERR = " 2> /dev/null" # suppress errors
}

# Initialize `UrlEncoding`.
# See: <https://en.wikipedia.org/wiki/Percent-encoding>
function initUrlEncoding() {
    UrlEncoding["\n"] = "%0A"
    UrlEncoding[" "]  = "%20"
    UrlEncoding["!"]  = "%21"
    UrlEncoding["\""] = "%22"
    UrlEncoding["#"]  = "%23"
    UrlEncoding["$"]  = "%24"
    UrlEncoding["%"]  = "%25"
    UrlEncoding["&"]  = "%26"
    UrlEncoding["'"]  = "%27"
    UrlEncoding["("]  = "%28"
    UrlEncoding[")"]  = "%29"
    UrlEncoding["*"]  = "%2A"
    UrlEncoding["+"]  = "%2B"
    UrlEncoding[","]  = "%2C"
    UrlEncoding["-"]  = "%2D"
    UrlEncoding["."]  = "%2E"
    UrlEncoding["/"]  = "%2F"
    UrlEncoding[":"]  = "%3A"
    UrlEncoding[";"]  = "%3B"
    UrlEncoding["<"]  = "%3C"
    UrlEncoding["="]  = "%3D"
    UrlEncoding[">"]  = "%3E"
    UrlEncoding["?"]  = "%3F"
    UrlEncoding["@"]  = "%40"
    UrlEncoding["["]  = "%5B"
    UrlEncoding["\\"] = "%5C"
    UrlEncoding["]"]  = "%5D"
    UrlEncoding["^"]  = "%5E"
    UrlEncoding["_"]  = "%5F"
    UrlEncoding["`"]  = "%60"
    UrlEncoding["{"]  = "%7B"
    UrlEncoding["|"]  = "%7C"
    UrlEncoding["}"]  = "%7D"
    UrlEncoding["~"]  = "%7E"
}

# Return the real character represented by an escape sequence.
# Example: escapeChar("n") returns "\n".
# See: <https://en.wikipedia.org/wiki/Escape_character>
#      <https://en.wikipedia.org/wiki/Escape_sequences_in_C>
function escapeChar(char) {
    switch (char) {
    case "b":
        return "\b" # Backspace
    case "f":
        return "\f" # Formfeed
    case "n":
        return "\n" # Newline (Line Feed)
    case "r":
        return "\r" # Carriage Return
    case "t":
        return "\t" # Horizontal Tab
    case "v":
        return "\v" # Vertical Tab
    default:
        return char
    }
}

# Convert a literal-formatted string into its original string.
function literal(string,
                 ####
                 c, escaping, i, s) {
    if (string !~ /^".*"$/)
        return string

    split(string, s, "")
    string = ""
    escaping = 0
    for (i = 2; i < length(s); i++) {
        c = s[i]
        if (escaping) {
            string = string escapeChar(c)
            escaping = 0 # escape ends
        } else {
            if (c == "\\")
                escaping = 1 # escape begins
            else
                string = string c
        }
    }
    return string
}

# Return the escaped string.
function escape(string) {
    gsub(/"/, "\\\"", string)
    gsub(/\\/, "\\\\", string)
    return string
}

# Return the escaped, quoted string.
function parameterize(string, quotationMark) {
    if (!quotationMark)
        quotationMark = "'"

    if (quotationMark == "'") {
        gsub(/'/, "'\\''", string)
        return "'" string "'"
    } else {
        return "\"" escape(string) "\""
    }
}

# Return the URL-encoded string.
function quote(string,    i, r, s) {
    r = ""
    split(string, s, "")
    for (i = 1; i <= length(s); i++)
        r = r (s[i] in UrlEncoding ? UrlEncoding[s[i]] : s[i])
    return r
}

# Replicate a string.
function replicate(string, len,
                   ####
                   i, temp) {
    temp = ""
    for (i = 0; i < len; i++)
        temp = temp string
    return temp
}

# Squeeze a source line of AWK code.
function squeeze(line, preserveIndent) {
    # Remove preceding spaces if indentation not preserved
    if (!preserveIndent)
        gsub(/^[[:space:]]+/, "", line)
    # Remove comment
    gsub(/^[[:space:]]*#.*$/, "", line)
    # Remove in-line comment
    gsub(/#[^"]*$/, "", line)
    # Remove trailing spaces
    gsub(/[[:space:]]+$/, "", line)
    gsub(/[[:space:]]+\\$/, "\\", line)

    return line
}

# Return 1 if the array contains anything; otherwise return 0.
function anything(array,
                  ####
                  i) {
    for (i in array)
        if (array[i]) return 1
    return 0
}

# Append an element into an array (zero-based).
function append(array, element) {
    array[anything(array) ? length(array) : 0] = element
}

# Return an element if it belongs to the array;
# Otherwise, return a null string.
function belongsTo(element, array,
                   ####
                   i) {
    for (i in array)
        if (element == array[i]) return element
    return ""
}

# Return one of the substrings if the string starts with it;
# Otherwise, return a null string.
function startsWithAny(string, substrings,
                       ####
                       i) {
    for (i in substrings)
        if (index(string, substrings[i]) == 1) return substrings[i]
    return ""
}

# Return one of the patterns if the string matches this pattern at the beginning;
# Otherwise, return a null string.
function matchesAny(string, patterns,
                    ####
                    i) {
    for (i in patterns)
        if (string ~ "^" patterns[i]) return patterns[i]
    return ""
}

# Join an array into one string;
# Return the string.
function join(array, separator, sortedIn, preserveNull,
              ####
              i, j, saveSortedIn, temp) {
    # Default parameters
    if (!separator)
        separator = " "
    if (!sortedIn)
        sortedIn = "@ind_num_asc"

    temp = ""
    j = 0
    saveSortedIn = PROCINFO["sorted_in"]
    if (length(array)) {
        PROCINFO["sorted_in"] = sortedIn
        for (i in array)
            if (preserveNull || array[i] != "")
                temp = j++ ? temp separator array[i] : array[i]
        PROCINFO["sorted_in"] = saveSortedIn
    } else
        temp = array # array is empty string

    return temp
}

# Return 0 if the string starts with '0', 'f' or 'n';
# Otherwise, return 1.
function yn(string) {
    return (tolower(string) ~ /^[0fn]/) ? 0 : 1
}

# Initialize ANSI escape codes for SGR (Select Graphic Rendition).
# (ANSI X3.64 Standard Control Sequences)
# See: <https://en.wikipedia.org/wiki/ANSI_escape_code>
function initAnsiCode() {
    # Dumb terminal: no ANSI escape code whatsoever
    if (ENVIRON["TERM"] == "dumb") return

    AnsiCode["reset"]         = AnsiCode[0] = "\33[0m"

    AnsiCode["bold"]          = "\33[1m"
    AnsiCode["underline"]     = "\33[4m"
    AnsiCode["negative"]      = "\33[7m"
    AnsiCode["no bold"]       = "\33[22m" # SGR code 21 (bold off) not widely supported
    AnsiCode["no underline"]  = "\33[24m"
    AnsiCode["positive"]      = "\33[27m"

    AnsiCode["black"]         = "\33[30m"
    AnsiCode["red"]           = "\33[31m"
    AnsiCode["green"]         = "\33[32m"
    AnsiCode["yellow"]        = "\33[33m"
    AnsiCode["blue"]          = "\33[34m"
    AnsiCode["magenta"]       = "\33[35m"
    AnsiCode["cyan"]          = "\33[36m"
    AnsiCode["gray"]          = "\33[37m"

    AnsiCode["default"]       = "\33[39m"

    AnsiCode["dark gray"]     = "\33[90m"
    AnsiCode["light red"]     = "\33[91m"
    AnsiCode["light green"]   = "\33[92m"
    AnsiCode["light yellow"]  = "\33[93m"
    AnsiCode["light blue"]    = "\33[94m"
    AnsiCode["light magenta"] = "\33[95m"
    AnsiCode["light cyan"]    = "\33[96m"
    AnsiCode["white"]         = "\33[97m"
}

# Return ANSI escaped string.
function ansi(code, text) {
    switch (code) {
    case "bold":
        return AnsiCode[code] text AnsiCode["no bold"]
    case "underline":
        return AnsiCode[code] text AnsiCode["no underline"]
    case "negative":
        return AnsiCode[code] text AnsiCode["positive"]
    default:
        return AnsiCode[code] text AnsiCode[0]
    }
}

# Print warning message.
function w(text) {
    print ansi("yellow", text) > STDERR
}

# Print error message.
function e(text) {
    print ansi("bold", ansi("red", text)) > STDERR
}

# Print debugging message.
function d(text) {
    print ansi("gray", text) > STDERR
}

# Log an array.
function da(array, formatString, sortedIn,
            ####
            i, j, saveSortedIn) {
    # Default parameters
    if (!formatString)
        formatString = "_[%s]='%s'"
    if (!sortedIn)
        sortedIn = "@ind_num_asc"

    saveSortedIn = PROCINFO["sorted_in"]
    PROCINFO["sorted_in"] = sortedIn
    for (i in array) {
        split(i, j, SUBSEP)
        d(sprintf(formatString, join(j, ","), array[i]))
    }
    PROCINFO["sorted_in"] = saveSortedIn
}

# Naive assertion.
function assert(x, message) {
    if (!message)
        message = "[ERROR] Assertion failed."

    if (x)
        return x
    else
        e(message)
}

# Return non-zero if file exists, otherwise return 0.
function fileExists(file) {
    return !system("test -f " file)
}

# Initialize `UriSchemes`.
function initUriSchemes() {
    UriSchemes[0] = "file://"
    UriSchemes[1] = "http://"
    UriSchemes[2] = "https://"
}

BEGIN {
    initConst()

    initUrlEncoding()
    initAnsiCode()
    initUriSchemes()
}


Better output flushing, maybe?

Better output flushing, maybe?

# Exit statuses:
#
# 0 - No errors found.
# 1 - Build or test failure. Errors will be logged automatically.
# 2 - Untestable target. Retry with the "build" action.

BEGIN {
    status = 0;
}

{
    print;
    fflush(stdout);
}

/is not valid for Testing/ {
    exit 2;
}

/[0-9]+: (error|warning):/ {
    errors = errors $0 "\n";
    status = 1;
}

/(TEST|BUILD) FAILED/ {
    status = 1;
}

END {
    if (length(errors) > 0) {
        print "\n*** All errors:\n" errors;
    }

    fflush(stdout);
    exit status;
}

# Exit statuses:
#
# 0 - No errors found.
# 1 - Build or test failure. Errors will be logged automatically.
# 2 - Untestable target. Retry with the "build" action.

{
    print;
    fflush(stdout);
}

/is not valid for Testing/ {
    exit 2;
}

/[0-9]+: (error|warning):/ {
    errors = errors $0 "\n";
}

/(TEST|BUILD) FAILED/ {
    if (length(errors) > 0) {
        print "\n*** All errors:\n" errors;
    }

    fflush(stdout);
    exit 1;
}


Explicitly discard refSink() result

Explicitly discard refSink() result

#!/usr/bin/awk
#
# Patch the generated wrapper Swift code to handle special cases
#
BEGIN { unowned_init = 0 ; unowned = 0 }
/open .* InitiallyUnowned:/ {
    unowned_init = 1
}
/override public.* init._/ {
  if (unowned_init) {
    unowned_init = 0
    unowned = 1
  }
}
/super.init/ {
  if (unowned) {
    unowned = 0
    print
    print "        _ = refSink()"
    next
  }
}
// { print }

#!/usr/bin/awk
#
# Patch the generated wrapper Swift code to handle special cases
#
BEGIN { unowned_init = 0 ; unowned = 0 }
/open .* InitiallyUnowned:/ {
    unowned_init = 1
}
/override public.* init._/ {
  if (unowned_init) {
    unowned_init = 0
    unowned = 1
  }
}
/super.init/ {
  if (unowned) {
    unowned = 0
    print
    print "        refSink()"
    next
  }
}
// { print }