Mark the generated output as 'DO NOT EDIT'

#!/usr/bin/awk -f

# ProtobufRuntime/Sources/Protobuf/ProtobufBinaryEncoding.swift - Binary encoding support
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See http://swift.org/LICENSE.txt for license information
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# -----------------------------------------------------------------------------
#
# The Linux version of XCTest cannot automatically
# discover tests at run-time.  So you can either manually
# maintain lists of tests or collect them at build time.
#
# This script is used by the Makefile to do the latter:
#  = Scans each XCTest source file for 'class Foo: XCTestCase'
#  = Looks for 'func test*' within those classes
#  = Emits a class extension with the necessary 'allTests' property
#  = Emits an XCTMain invocation to run all the classes
#
# The macOS version of XCTest has another mechanism for
# finding tests at run-time, so this is not needed there.
#
# -----------------------------------------------------------------------------

BEGIN {
    CLASS=""
    TESTCASES=""
    TESTCASE_separator=""
    printf("//\n")
    printf("// GENERATED FILE\n")
    printf("// DO NOT EDIT\n")
    printf("//\n")
    printf("\n")
    printf("import XCTest\n")
    printf("@testable import SwiftProtobufTests\n")
    printf("\n")
    printf("private func run_test(test:() -> ()) throws {\n")
    printf("    test()\n")
    printf("}\n")
    printf("\n")
    printf("private func run_test(test:() throws -> ()) throws {\n")
    printf("    try test()\n")
    printf("}\n")
    printf("\n")
    printf("\n")
}

/class .*:.* XCTestCase/ {
    if (CLASS != "") {
	printf("        ]\n")
	printf("    }\n")
	printf("}\n")
    }
    split($0, a, ":")
    split(a[1], words, " ")
    CLASS=words[2]
    TESTCASES = TESTCASES TESTCASE_separator "\n" "        (testCaseClass: " CLASS ".self, allTests: " CLASS ".allTests)"
    TESTCASE_separator = ","
    printf("\n")
    printf("extension %s {\n", CLASS)
    printf("    static var allTests: [(String, (XCTestCase) throws -> ())] {\n")
    printf("        return [")
    FUNC_separator=""
}

/ *func *test.*/ {
    split($0, a, "(")
    split(a[1], words, " ")
    FUNC=words[2]
    printf("")
    printf("%s\n            (\"%s\", {try run_test(test:($0 as! %s).%s)})", FUNC_separator, FUNC, CLASS, FUNC)
    FUNC_separator = ","
}

END {
    if (CLASS != "") {
	printf("\n        ]\n")
	printf("    }\n")
	printf("}\n")
    }
    printf("\n")

    printf("XCTMain(\n")
    printf("    [")
    printf(TESTCASES)
    printf("\n    ]\n)\n")
}

#!/usr/bin/awk -f

# ProtobufRuntime/Sources/Protobuf/ProtobufBinaryEncoding.swift - Binary encoding support
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See http://swift.org/LICENSE.txt for license information
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# -----------------------------------------------------------------------------
#
# The Linux version of XCTest cannot automatically
# discover tests at run-time.  So you can either manually
# maintain lists of tests or collect them at build time.
#
# This script is used by the Makefile to do the latter:
#  = Scans each XCTest source file for 'class Foo: XCTestCase'
#  = Looks for 'func test*' within those classes
#  = Emits a class extension with the necessary 'allTests' property
#  = Emits an XCTMain invocation to run all the classes
#
# The macOS version of XCTest has another mechanism for
# finding tests at run-time, so this is not needed there.
#
# -----------------------------------------------------------------------------

BEGIN {
    CLASS=""
    TESTCASES=""
    TESTCASE_separator=""
    printf("import XCTest\n")
    printf("@testable import SwiftProtobufTests\n")
    printf("\n")
    printf("private func run_test(test:() -> ()) throws {\n")
    printf("    test()\n")
    printf("}\n")
    printf("\n")
    printf("private func run_test(test:() throws -> ()) throws {\n")
    printf("    try test()\n")
    printf("}\n")
    printf("\n")
    printf("\n")
}

/class .*:.* XCTestCase/ {
    if (CLASS != "") {
	printf("        ]\n")
	printf("    }\n")
	printf("}\n")
    }
    split($0, a, ":")
    split(a[1], words, " ")
    CLASS=words[2]
    TESTCASES = TESTCASES TESTCASE_separator "\n" "        (testCaseClass: " CLASS ".self, allTests: " CLASS ".allTests)"
    TESTCASE_separator = ","
    printf("\n")
    printf("extension %s {\n", CLASS)
    printf("    static var allTests: [(String, (XCTestCase) throws -> ())] {\n")
    printf("        return [")
    FUNC_separator=""
}

/ *func *test.*/ {
    split($0, a, "(")
    split(a[1], words, " ")
    FUNC=words[2]
    printf("")
    printf("%s\n            (\"%s\", {try run_test(test:($0 as! %s).%s)})", FUNC_separator, FUNC, CLASS, FUNC)
    FUNC_separator = ","
}

END {
    if (CLASS != "") {
	printf("\n        ]\n")
	printf("    }\n")
	printf("}\n")
    }
    printf("\n")

    printf("XCTMain(\n")
    printf("    [")
    printf(TESTCASES)
    printf("\n    ]\n)\n")
}


revise a bit

revise a bit

# argv: n (Original number)
BEGIN{
    pi  = 3.141;
    idc = 0;
}
{
    id    = $1;
    istar = $2;
    mass  = $3;
    px    = $4;
    py    = $5;
    pz    = $6;
    vx    = $7;
    vy    = $8;
    vz    = $9;
    ue    = $13;
    alph  = $14;
    alphu = $15;
    ksr   = $17;
    for(k = 0; k < 13; k++) {
        cmps[k] = $(32+k);
    }

    phi = pi * (2. * rand() - 1.);
    cth = 2. * rand() - 1.;
    sth = sqrt(1. - cth**2);
    dr  = (1./2.)**(1/3.) * (ksr * 0.1);
    dx  = dr * sth * cos(phi);
    dy  = dr * sth * sin(phi);
    dz  = dr * cth;
    dvx = 0. * sth * cos(phi);
    dvy = 0. * sth * sin(phi);
    dvz = 0. * cth;

    id0    = idc;
    istar0 = istar;
    mass0  = 0.5 * mass;
    px0    = px + dx;
    py0    = py + dy;
    pz0    = pz + dz;
    vx0    = vx + dvx;
    vy0    = vy + dvy;
    vz0    = vz + dvz;
    ue0    = ue;
    alph0  = alph;
    alphu0 = alphu;
    ksr0   = ksr;
    for(k = 0; k < 13; k++) {
        cmps0[k] = cmps[k]
    }
    idc++;

    id1    = idc;
    istar1 = istar;
    mass1  = 0.5 * mass;
    px1    = px - dx;
    py1    = py - dy;
    pz1    = pz - dz;
    vx1    = vx - dvx;
    vy1    = vy - dvy;
    vz1    = vz - dvz;
    ue1    = ue;
    alph1  = alph;
    alphu1 = alphu;
    ksr1   = ksr;
    for(k = 0; k < 13; k++) {
        cmps1[k] = cmps[k]
    }
    idc++;

    printf("%10d %2d %+e", id0, istar0, mass0);
    printf(" %+e %+e %+e", px0, py0, pz0);
    printf(" %+e %+e %+e", vx0, vy0, vz0);
    printf(" %+e %+e %+e", ue0, alph0, alphu0);
    printf(" %+e", ksr0);
    for(k = 0; k < 13; k++) {
        printf(" %+.3e", cmps0[k]);
    }
    printf("\n");

    printf("%10d %2d %+e", id1, istar1, mass1);
    printf(" %+e %+e %+e", px1, py1, pz1);
    printf(" %+e %+e %+e", vx1, vy1, vz1);
    printf(" %+e %+e %+e", ue1, alph1, alphu1);
    printf(" %+e", ksr1);
    for(k = 0; k < 13; k++) {
        printf(" %+.3e", cmps1[k]);
    }
    printf("\n");
}


Fix an issue with fzn2py.awk where no output variables are specified in the mzn model.

# translate flatzinc format to python/Numberjack

BEGIN {
	MAXINT = 10000000;
	print "#! /usr/bin/env python"
	print "import time"
	print "from Numberjack import *"
	system("cat " MZNNJ_DIR "/fzn2py.py");
	print "";
	print "def get_model():"
	print "    model = Model()";
	parameter = 1;
	error = 0;
}

# { print $0 } # for debugging purposes only

/::_output_var/ {
	gsub("::_output_var","");
	$0 = $0 " ::_output_";
}

/::_output_array/ {
	regexp = "::_output_array[(][[](range[(][0-9]+,1[+][0-9]+[)][ ,]*)+[]][)]";
	if (match($0,regexp)) {
	  array = substr($0, RSTART, RLENGTH);
	  sub(regexp,"");
	  gsub("[[]","",array);
	  gsub("[]]","",array);
	  gsub(" ","",array);
	  gsub("range[(]","",array);
	  gsub(",1[+]","..",array);
	  gsub("[)]","",array);
	  nbdim = array;
	  gsub("[^,]","",nbdim);
	  dim = length(nbdim)+1;
	  sub("::_output_array", "array" dim "d",array);
	  $0 = $0 " ::_output_" array;
	} else {
		print "ERROR WRONG OUTPUT ARRAY DEFINITION",$0;
		error = 3;
		exit(2);
	}
}

/^var / {
	parameter = 0;
}

/ of var / {
	parameter = 0;
}

parameter {
	sub(".*: ","");
	if ($2 == "=") print "    " $0; # it might be a predicate instead if no =
}

/^var bool:/{
	print "    " $3 " = Variable('" $3 "')";
	if (match($0,"::_output_")) output[$3] = 1;
	if ($4 == "=") print "    model.add(" $3 " == " $5 ")";
}

/^var int:/{
	print "    " $3 " = Variable(-" MAXINT "," MAXINT ",'" $3 "')";
	if (match($0,"::_output_")) output[$3] = 1;
	if ($4 == "=") print "    model.add(" $3 " == " $5 ")";
}

/^var range[(][-]*[0-9]+,1[+][-]*[0-9]+[)]:/{
	sub("range[(]","",$2);
	sub("[)]:","",$2);
	sub(",1[+]",",",$2);
	print "    " $3 " = Variable(" $2 ",'" $3 "')";
	if (match($0,"::_output_")) output[$3] = 1;
	if ($4 == "=") print "    model.add(" $3 " == " $5 ")";
}

/^var {[-]*[0-9]+(,[-]*[0-9]+)*}:/{
	sub("{","[",$2);
	sub("}:","]",$2);
	print "    " $3 " = Variable(" $2 ",'" $3 "')";
	if (match($0,"::_output_")) output[$3] = 1;
	if ($4 == "=") print "    model.add(" $3 " == " $5 ")";
}

/^array [[]range[(][-]*[0-9]+,1[+][-]*[0-9]+[)][]] of var bool:/{
	sub("[[]range[(]","",$2);
	sub("[)][]]","",$2);
	sub(",1[+]",",",$2);
	iinf = $2;
	sub(",.*","",iinf);
	if (iinf != 1) {
		print "ERROR ASSUMING MINIMUM INDEX VALUE EQUAL TO ONE IN ARRAY DEFINITION",$0;
		error = 1;
		exit(1);
	}
	isup = $2;
	sub(".*,","",isup);
	if (isup < iinf) {
		print "ERROR WRONG RANGE INDEX VALUE IN ARRAY DEFINITION",$0;
		error = 2;
		exit(2);
	}
	name = $6;
	print "    " name " = VarArray(" isup ",'" name "')";
	if (match($0,"::_output_")) {
		output[ name ] = isup;
		outputstring[ name ] = substr($0, RSTART+RLENGTH);
	}
	if ($7 == "=") {
		sub(".*= ","");
		sub("::_output_.*","");
		gsub(" ","");
		for (i=0; i<isup; i++) {
			print "    model.add(" name "[" i "] == " $0 "[" i "])";
		}
	}
}

/^array [[]range[(][-]*[0-9]+,1[+][-]*[0-9]+[)][]] of var int:/{
	sub("[[]range[(]","",$2);
	sub("[)][]]","",$2);
	sub(",1[+]",",",$2);
	iinf = $2;
	sub(",.*","",iinf);
	if (iinf != 1) {
		print "ERROR ASSUMING MINIMUM INDEX VALUE EQUAL TO ONE IN ARRAY DEFINITION",$0;
		error = 1;
		exit(1);
	}
	isup = $2;
	sub(".*,","",isup);
	if (isup < iinf) {
		print "ERROR WRONG RANGE INDEX VALUE IN ARRAY DEFINITION",$0;
		error = 2;
		exit(2);
	}
	name = $6;
	print "    " name " = VarArray(" isup ",-" MAXINT "," MAXINT ",'" name "')";
	if (match($0,"::_output_")) {
		output[ name ] = isup;
		outputstring[ name ] = substr($0, RSTART+RLENGTH);
	}
	if ($7 == "=") {
		sub(".*= ","");
		sub("::_output_.*","");
		gsub(" ","");
		for (i=0; i<isup; i++) {
			print "    model.add(" name "[" i "] == " $0 "[" i "])";
		}
	}
}

/^array [[]range[(][-]*[0-9]+,1[+][-]*[0-9]+[)][]] of var range[(][-]*[0-9]+,1[+][-]*[0-9]+[)]:/{
	sub("[[]range[(]","",$2);
	sub("[)][]]","",$2);
	sub(",1[+]",",",$2);
	iinf = $2;
	sub(",.*","",iinf);
	if (iinf != 1) {
		print "ERROR ASSUMING MINIMUM INDEX VALUE EQUAL TO ONE IN ARRAY DEFINITION",$0;
		error = 1;
		exit(1);
	}
	isup = $2;
	sub(".*,","",isup);
	if (isup < iinf) {
		print "ERROR WRONG RANGE INDEX VALUE IN ARRAY DEFINITION",$0;
		error = 2;
		exit(2);
	}
	sub("range[(]","",$5);
	sub("[)]:","",$5);
	sub(",1[+]",",",$5);
	name = $6;
	print "    " name " = VarArray(" isup "," $5 ",'" name "')";
	if (match($0,"::_output_")) {
		output[ name ] = isup;
		outputstring[ name ] = substr($0, RSTART+RLENGTH);
	}
	if ($7 == "=") {
		sub(".*= ","");
		sub("::_output_.*","");
		gsub(" ","");
		for (i=0; i<isup; i++) {
			print "    model.add(" name "[" i "] == " $0 "[" i "])";
		}
	}
}

/^array [[]range[(][-]*[0-9]+,1[+][-]*[0-9]+[)][]] of var {[-]*[0-9]+(,[-]*[0-9]+)*}:/{
	sub("[[]range[(]","",$2);
	sub("[)][]]","",$2);
	sub(",1[+]",",",$2);
	iinf = $2;
	sub(",.*","",iinf);
	if (iinf != 1) {
		print "ERROR ASSUMING MINIMUM INDEX VALUE EQUAL TO ONE IN ARRAY DEFINITION",$0;
		error = 1;
		exit(1);
	}
	isup = $2;
	sub(".*,","",isup);
	if (isup < iinf) {
		print "ERROR WRONG RANGE INDEX VALUE IN ARRAY DEFINITION",$0;
		error = 2;
		exit(2);
	}
	sub("{","[",$5);
	sub("}:","]",$5);
	name = $6;
	print "    " name " = [Variable(" $5 ",'" name "_" i "') for i in range(" isup ")]";
	if (match($0,"::_output_")) {
		output[ name ] = isup;
		outputstring[ name ] = substr($0, RSTART+RLENGTH);
	}
	if ($7 == "=") {
		sub(".*= ","");
		sub("::_output_.*","");
		gsub(" ","");
		for (i=0; i<isup; i++) {
			print "    model.add(" name "[" i "] == " $0 "[" i "])";
		}
	}
}

/^constraint /{
	$1 = "    model.add(";
    	$NF = $NF " )";
	print $0;
}

/^solve / && / minimize /{
	print "    model.add(Minimize(" $NF "))";
	objective = $NF;
}

/^solve / && / maximize /{
	print "    model.add(Maximize(" $NF "))";
	objective = $NF;
}

END {
	if (!error) {
	output_vars = "";
	if(objective) output_vars = objective;

	n = asorti(output,varnames);
	for (i=1; i<=n; i++) {
		e = varnames[i];
		if(e != objective) {
			if(length(output_vars) > 0) output_vars = output_vars ", ";
			output_vars = output_vars e;
		}
	}
	print "    output_vars = (" output_vars ")";
	print "    return model, output_vars";

	print "";
	print "model, output_vars = get_model()";
	if(output_vars) print output_vars " = output_vars";
	print "solvers = ['Mistral', 'SCIP', 'MiniSat', 'Toulbar2', 'Gurobi']";
	print "default = dict([('solver', 'Mistral'), ('verbose', 0), ('tcutoff', 900), ('var', 'DomainOverWDegree'), ('val', 'Lex'), ('rand', 2), ('threads', 1), ('restart', GEOMETRIC), ('base', 256), ('factor', 1.3)])";
	print "param = input(default)";
	print "solver = model.load(param['solver'])";
	print "solver.setVerbosity(param['verbose'])";
	print "solver.setTimeLimit(param['tcutoff'] - int(time.clock()+0.5))";
	print "solver.setHeuristic(param['var'], param['val'], param['rand'])";
	print "if param['solver'] == 'Gurobi':";
	print "    solver.setThreadCount(param['threads'])";
	print "if param['solver'] == 'Mistral':";
	print "    # LUBY, GEOMETRIC = 0, 1"
	print "    # print 'running %d %d %.1f' % (param['restart'], param['base'], param['factor'])";
	#print "    solver.solveAndRestart(GEOMETRIC, 256, 1.3)";
	print "    solver.solveAndRestart(param['restart'], param['base'], param['factor'])";
	print "else:";
	print "    solver.solve()";
	print "if solver.is_sat():"
	for (i=1; i<=n; i++) {
		e = varnames[i];
		if (output[e]==1) {
			if (e != objective && e != "objective" && e != "obj") print "    print '" e " = '," e ".get_value(),';'";
			else print "    print '" e " = ', (solver.getOptimum() if param['solver'] == 'Toulbar2' else " e ".get_value()),';'";
		} else {
			print "    print '" e " = " outputstring[e] ",',str(" e "),');'";
		}
	}
	print "    print '----------'";
	if (objective){
		print "    if solver.is_opt():"
		print "        print '=========='"
	} else {
		print "    print '=========='"
	}
	print "elif solver.is_unsat():"
	print "    print '=====UNSATISFIABLE====='"
    print "else:"
	print "    print '=====UNKNOWN====='"
	print "print '% SolveTime', solver.getTime()";
	print "print '% Nodes', solver.getNodes()";
	print "print '% Failures', solver.getFailures()";
	if (objective) print "if solver.is_sat(): print '% Objective', (solver.getOptimum() if param['solver'] == 'Toulbar2' else " objective ".get_value())";
	}
}

# translate flatzinc format to python/Numberjack

BEGIN {
	MAXINT = 10000000;
	print "#! /usr/bin/env python"
	print "import time"
	print "from Numberjack import *"
	system("cat " MZNNJ_DIR "/fzn2py.py");
	print "";
	print "def get_model():"
	print "    model = Model()";
	parameter = 1;
	error = 0;
}

# { print $0 } # for debugging purposes only

/::_output_var/ {
	gsub("::_output_var","");
	$0 = $0 " ::_output_";
}

/::_output_array/ {
	regexp = "::_output_array[(][[](range[(][0-9]+,1[+][0-9]+[)][ ,]*)+[]][)]";
	if (match($0,regexp)) {
	  array = substr($0, RSTART, RLENGTH);
	  sub(regexp,"");
	  gsub("[[]","",array);
	  gsub("[]]","",array);
	  gsub(" ","",array);
	  gsub("range[(]","",array);
	  gsub(",1[+]","..",array);
	  gsub("[)]","",array);
	  nbdim = array;
	  gsub("[^,]","",nbdim);
	  dim = length(nbdim)+1;
	  sub("::_output_array", "array" dim "d",array);
	  $0 = $0 " ::_output_" array;
	} else {
		print "ERROR WRONG OUTPUT ARRAY DEFINITION",$0;
		error = 3;
		exit(2);
	}
}

/^var / {
	parameter = 0;
}

/ of var / {
	parameter = 0;
}

parameter {
	sub(".*: ","");
	if ($2 == "=") print "    " $0; # it might be a predicate instead if no =
}

/^var bool:/{
	print "    " $3 " = Variable('" $3 "')";
	if (match($0,"::_output_")) output[$3] = 1;
	if ($4 == "=") print "    model.add(" $3 " == " $5 ")";
}

/^var int:/{
	print "    " $3 " = Variable(-" MAXINT "," MAXINT ",'" $3 "')";
	if (match($0,"::_output_")) output[$3] = 1;
	if ($4 == "=") print "    model.add(" $3 " == " $5 ")";
}

/^var range[(][-]*[0-9]+,1[+][-]*[0-9]+[)]:/{
	sub("range[(]","",$2);
	sub("[)]:","",$2);
	sub(",1[+]",",",$2);
	print "    " $3 " = Variable(" $2 ",'" $3 "')";
	if (match($0,"::_output_")) output[$3] = 1;
	if ($4 == "=") print "    model.add(" $3 " == " $5 ")";
}

/^var {[-]*[0-9]+(,[-]*[0-9]+)*}:/{
	sub("{","[",$2);
	sub("}:","]",$2);
	print "    " $3 " = Variable(" $2 ",'" $3 "')";
	if (match($0,"::_output_")) output[$3] = 1;
	if ($4 == "=") print "    model.add(" $3 " == " $5 ")";
}

/^array [[]range[(][-]*[0-9]+,1[+][-]*[0-9]+[)][]] of var bool:/{
	sub("[[]range[(]","",$2);
	sub("[)][]]","",$2);
	sub(",1[+]",",",$2);
	iinf = $2;
	sub(",.*","",iinf);
	if (iinf != 1) {
		print "ERROR ASSUMING MINIMUM INDEX VALUE EQUAL TO ONE IN ARRAY DEFINITION",$0;
		error = 1;
		exit(1);
	}
	isup = $2;
	sub(".*,","",isup);
	if (isup < iinf) {
		print "ERROR WRONG RANGE INDEX VALUE IN ARRAY DEFINITION",$0;
		error = 2;
		exit(2);
	}
	name = $6;
	print "    " name " = VarArray(" isup ",'" name "')";
	if (match($0,"::_output_")) {
		output[ name ] = isup;
		outputstring[ name ] = substr($0, RSTART+RLENGTH);
	}
	if ($7 == "=") {
		sub(".*= ","");
		sub("::_output_.*","");
		gsub(" ","");
		for (i=0; i<isup; i++) {
			print "    model.add(" name "[" i "] == " $0 "[" i "])";
		}
	}
}

/^array [[]range[(][-]*[0-9]+,1[+][-]*[0-9]+[)][]] of var int:/{
	sub("[[]range[(]","",$2);
	sub("[)][]]","",$2);
	sub(",1[+]",",",$2);
	iinf = $2;
	sub(",.*","",iinf);
	if (iinf != 1) {
		print "ERROR ASSUMING MINIMUM INDEX VALUE EQUAL TO ONE IN ARRAY DEFINITION",$0;
		error = 1;
		exit(1);
	}
	isup = $2;
	sub(".*,","",isup);
	if (isup < iinf) {
		print "ERROR WRONG RANGE INDEX VALUE IN ARRAY DEFINITION",$0;
		error = 2;
		exit(2);
	}
	name = $6;
	print "    " name " = VarArray(" isup ",-" MAXINT "," MAXINT ",'" name "')";
	if (match($0,"::_output_")) {
		output[ name ] = isup;
		outputstring[ name ] = substr($0, RSTART+RLENGTH);
	}
	if ($7 == "=") {
		sub(".*= ","");
		sub("::_output_.*","");
		gsub(" ","");
		for (i=0; i<isup; i++) {
			print "    model.add(" name "[" i "] == " $0 "[" i "])";
		}
	}
}

/^array [[]range[(][-]*[0-9]+,1[+][-]*[0-9]+[)][]] of var range[(][-]*[0-9]+,1[+][-]*[0-9]+[)]:/{
	sub("[[]range[(]","",$2);
	sub("[)][]]","",$2);
	sub(",1[+]",",",$2);
	iinf = $2;
	sub(",.*","",iinf);
	if (iinf != 1) {
		print "ERROR ASSUMING MINIMUM INDEX VALUE EQUAL TO ONE IN ARRAY DEFINITION",$0;
		error = 1;
		exit(1);
	}
	isup = $2;
	sub(".*,","",isup);
	if (isup < iinf) {
		print "ERROR WRONG RANGE INDEX VALUE IN ARRAY DEFINITION",$0;
		error = 2;
		exit(2);
	}
	sub("range[(]","",$5);
	sub("[)]:","",$5);
	sub(",1[+]",",",$5);
	name = $6;
	print "    " name " = VarArray(" isup "," $5 ",'" name "')";
	if (match($0,"::_output_")) {
		output[ name ] = isup;
		outputstring[ name ] = substr($0, RSTART+RLENGTH);
	}
	if ($7 == "=") {
		sub(".*= ","");
		sub("::_output_.*","");
		gsub(" ","");
		for (i=0; i<isup; i++) {
			print "    model.add(" name "[" i "] == " $0 "[" i "])";
		}
	}
}

/^array [[]range[(][-]*[0-9]+,1[+][-]*[0-9]+[)][]] of var {[-]*[0-9]+(,[-]*[0-9]+)*}:/{
	sub("[[]range[(]","",$2);
	sub("[)][]]","",$2);
	sub(",1[+]",",",$2);
	iinf = $2;
	sub(",.*","",iinf);
	if (iinf != 1) {
		print "ERROR ASSUMING MINIMUM INDEX VALUE EQUAL TO ONE IN ARRAY DEFINITION",$0;
		error = 1;
		exit(1);
	}
	isup = $2;
	sub(".*,","",isup);
	if (isup < iinf) {
		print "ERROR WRONG RANGE INDEX VALUE IN ARRAY DEFINITION",$0;
		error = 2;
		exit(2);
	}
	sub("{","[",$5);
	sub("}:","]",$5);
	name = $6;
	print "    " name " = [Variable(" $5 ",'" name "_" i "') for i in range(" isup ")]";
	if (match($0,"::_output_")) {
		output[ name ] = isup;
		outputstring[ name ] = substr($0, RSTART+RLENGTH);
	}
	if ($7 == "=") {
		sub(".*= ","");
		sub("::_output_.*","");
		gsub(" ","");
		for (i=0; i<isup; i++) {
			print "    model.add(" name "[" i "] == " $0 "[" i "])";
		}
	}
}

/^constraint /{
	$1 = "    model.add(";
    	$NF = $NF " )";
	print $0;
}

/^solve / && / minimize /{
	print "    model.add(Minimize(" $NF "))";
	objective = $NF;
}

/^solve / && / maximize /{
	print "    model.add(Maximize(" $NF "))";
	objective = $NF;
}

END {
	if (!error) {
	output_vars = "";
	if(objective) output_vars = objective;

	n = asorti(output,varnames);
	for (i=1; i<=n; i++) {
		e = varnames[i];
		if(e != objective) {
			if(length(output_vars) > 0) output_vars = output_vars ", ";
			output_vars = output_vars e;
		}
	}
	print "    output_vars = (" output_vars ",)";
	print "    return model, output_vars";

	print "";
	print "model, output_vars = get_model()";
	print output_vars " = output_vars";
	print "solvers = ['Mistral', 'SCIP', 'MiniSat', 'Toulbar2', 'Gurobi']";
	print "default = dict([('solver', 'Mistral'), ('verbose', 0), ('tcutoff', 900), ('var', 'DomainOverWDegree'), ('val', 'Lex'), ('rand', 2), ('threads', 1), ('restart', GEOMETRIC), ('base', 256), ('factor', 1.3)])";
	print "param = input(default)";
	print "solver = model.load(param['solver'])";
	print "solver.setVerbosity(param['verbose'])";
	print "solver.setTimeLimit(param['tcutoff'] - int(time.clock()+0.5))";
	print "solver.setHeuristic(param['var'], param['val'], param['rand'])";
	print "if param['solver'] == 'Gurobi':";
	print "    solver.setThreadCount(param['threads'])";
	print "if param['solver'] == 'Mistral':";
	print "    # LUBY, GEOMETRIC = 0, 1"
	print "    # print 'running %d %d %.1f' % (param['restart'], param['base'], param['factor'])";
	#print "    solver.solveAndRestart(GEOMETRIC, 256, 1.3)";
	print "    solver.solveAndRestart(param['restart'], param['base'], param['factor'])";
	print "else:";
	print "    solver.solve()";
	print "if solver.is_sat():"
	for (i=1; i<=n; i++) {
		e = varnames[i];
		if (output[e]==1) {
			if (e != objective && e != "objective" && e != "obj") print "    print '" e " = '," e ".get_value(),';'";
			else print "    print '" e " = ', (solver.getOptimum() if param['solver'] == 'Toulbar2' else " e ".get_value()),';'";
		} else {
			print "    print '" e " = " outputstring[e] ",',str(" e "),');'";
		}
	}
	print "    print '----------'";
	if (objective){
		print "    if solver.is_opt():"
		print "        print '=========='"
	} else {
		print "    print '=========='"
	}
	print "elif solver.is_unsat():"
	print "    print '=====UNSATISFIABLE====='"
    print "else:"
	print "    print '=====UNKNOWN====='"
	print "print '% SolveTime', solver.getTime()";
	print "print '% Nodes', solver.getNodes()";
	print "print '% Failures', solver.getFailures()";
	if (objective) print "if solver.is_sat(): print '% Objective', (solver.getOptimum() if param['solver'] == 'Toulbar2' else " objective ".get_value())";
	}
}


Tidy code

Tidy code

#!/usr/bin/awk -f
##########
#The MIT License (MIT)
#
# Copyright (c) 2015 Aiden Lab
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
##########

# Dedup script that submits deduping jobs after splitting at known
# non-duplicates
# Juicer version 1.5

BEGIN{
	tot=0;
	name=0;
}
{
	if (tot >= 1000000) {
		if (p1 != $1 || p2 != $2 || p4 != $4 || p5 != $5 || p8 != $8) {
			print "this is the beginging part of split rmdups awk";
			cmd=sprintf("qstat | grep osplit%s |cut -c 1-8", groupname);
			cmd |& getline jID_osplit;
			sname=sprintf("%s_msplit%04d_", groupname, name);
			sysstring1=sprintf("qsub -l %s -o %s_%s.log -j oe -W group_list=cu_10027 -A cu_10027 -q %s -N DDuP%s%s -l mem=4gb -l nodes=1:ppn=1:thinnode -W depend=afterok:%s <<-EOF\nawk -f  %s/scripts/dups.awk -v name=%s/%s %s/split%04d;\nEOF\n", walltime, outfile, sname, queue, name, groupname, jID_osplit ,juicedir, dir, sname, dir, name, dir, name);
			system(sysstring1);
			cmd1=sprintf("qstat | grep DDuP%s%s | cut -d ' ' -f 1 | cut -d '.' -f 1-2",name,groupname);
			cmd1 |& getline jID;

			close(cmd1);
			if (name==0){
				waitstring=sprintf("%s",jID );
				waitstring2=sprintf("%s",jID)
			}
		  else {
				waitstring=sprintf("%s:%s",waitstring,jID);
				waitstring2=sprintf("%s %s",waitstring2,jID)
		  }

		  name++;
			tot=0;
		}
	}
	outname = sprintf("%s/split%04d", dir, name);
	print > outname;
	p1=$1;p2=$2;p4=$4;p5=$5;p6=$6;p8=$8;
	tot++;
}
END {
   	sname=sprintf("%s_msplit%04d_", groupname, name);
    print "This is the begining of END step, submitting _dedup job in END step";
	sysstring2=sprintf("qsub -l %s -o %s_%s_dedup%s.log -j oe -q %s -N DDuP%s%s -W depend=afterok:%s <<-EOF\nawk -f %s/scripts/dups.awk -v name=%s/%s %s/split%04d;\nEOF\n", walltime, outfile, sname, name, queue, name, groupname, jID_osplit ,juicedir, dir, sname, dir, name, dir, name);
    system(sysstring2);
	sname=sprintf("%s_msplit%04d_", groupname, name);
	system(sysstring2);

	cmd2=sprintf("qstat | grep DDuP%s%s | cut -d ' ' -f 1 | cut -d '.' -f 1-2",name,groupname);
	cmd2 |& getline jID;
	close(cmd2);
	if ( name==0 ){
		waitstring=sprintf("%s",jID );
		waitstring2=sprintf("%s",jID);
	}
	else {
		waitstring=sprintf("%s:%s",waitstring,jID);
		waitstring2=sprintf("%s %s",waitstring2,jID);
	}
	cmd3=sprintf("qstat %s",waitstring2);
	cmd3 |& getline waitedjobstatus;
	close(cmd3)
	print "below is the waitingstring1 and waitingstring2";
	print waitstring;
	sysstring = sprintf("qsub -l %s -o %s_catsplit.log -j oe -q %s -N CtSplt%s -W depend=afterok:%s <<-EOF\ncat %s/%s_msplit*_optdups.txt > %s/opt_dups.txt;  cat %s/%s_msplit*_dups.txt > %s/dups.txt; cat %s/%s_msplit*_merged_nodups.txt > %s/merged_nodups.txt; \nEOF\n", walltime, outfile, queue, groupname, waitstring, dir, groupname, dir, dir, groupname, dir, dir, groupname, dir, dir);
	print waitstring2;
	print "below is the waited job status before qsub"
	print waitedjobstatus;
	print "submitting _catsplit jobs";
	system(sysstring);
	cmd4=sprintf("qstat | grep CtSplt%s | cut -d ' ' -f 1 | cut -d '.' -f 1-2",groupname);
	cmd4 |& getline jID_catsplit;
	close(cmd4);
	print "below is the _catsplit id";
	print jID_catsplit;
	sysstring=sprintf("qsub -l %s -o %s_rmsplit.log -j oe -q %s -N RmSplt%s -W depend=afterok:%s <<-EOF\n rm %s/*_msplit*_optdups.txt; rm %s/*_msplit*_dups.txt; rm %s/*_msplit*_merged_nodups.txt; rm %s/split*;\nEOF", walltime, outfile, queue, groupname,jID_catsplit, dir, dir, dir, dir);
	print "submitting _rmsplit jobs";
	system(sysstring);
	cmd=sprintf("qstat | grep RmSplt%s | cut -d ' ' -f 1 | cut -d '.' -f 1-2",groupname);
	cmd |& getline jID_rmsplit;
	print "below is the jID_rmsplit:";
	print jID_rmsplit;
}

#!/usr/bin/awk -f
##########
#The MIT License (MIT)
#
# Copyright (c) 2015 Aiden Lab
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
##########

# Dedup script that submits deduping jobs after splitting at known
# non-duplicates
# Juicer version 1.5

BEGIN{
	tot=0;
	name=0;
}
{
	if (tot >= 1000000) {
		if (p1 != $1 || p2 != $2 || p4 != $4 || p5 != $5 || p8 != $8) {
	        print "this is the beginging part of split rmdups awk";
            cmd=sprintf("qstat | grep osplit%s |cut -c 1-7", groupname);
            cmd |& getline jID_osplit;
    		sname=sprintf("%s_msplit%04d_", groupname, name);
			sysstring1=sprintf("qsub -l %s -o %s_%s.log -j oe -q %s -N DDuP%s%s -l mem=4gb -l nodes=1:ppn=1:AMD -W depend=afterok:%s <<-EOF\nawk -f  %s/scripts/dups.awk -v name=%s/%s %s/split%04d;\nEOF\n", walltime, outfile, sname, queue, name, groupname, jID_osplit ,juicedir, dir, sname, dir, name, dir, name);
			system(sysstring1);
            cmd1=sprintf("qstat | grep DDuP%s%s | cut -d ' ' -f 1",name,groupname);
            cmd1 |& getline jID;
            close(cmd1);
            if (name==0){
            waitstring=sprintf("%s",jID );
            waitstring2=sprintf("%s",jID)
            }
		    else {
            waitstring=sprintf("%s:%s",waitstring,jID);
            waitstring2=sprintf("%s %s",waitstring2,jID)
            }

            name++;
			tot=0;
		}
	}
	outname = sprintf("%s/split%04d", dir, name);
	print > outname;
	p1=$1;p2=$2;p4=$4;p5=$5;p6=$6;p8=$8;
	tot++;
}
END {
   	sname=sprintf("%s_msplit%04d_", groupname, name);
    print "This is the begining of END step, submitting _dedup job in END step";
	sysstring2=sprintf("qsub -l %s -o %s_%s_dedup%s.log -j oe -q %s -N DDuP%s%s -W depend=afterok:%s <<-EOF\nawk -f %s/scripts/dups.awk -v name=%s/%s %s/split%04d;\nEOF\n", walltime, outfile, sname, name, queue, name, groupname, jID_osplit ,juicedir, dir, sname, dir, name, dir, name);
    system(sysstring2);

    cmd2=sprintf("qstat | grep DDuP%s%s | cut -d ' ' -f 1",name,groupname);
    cmd2 |& getline jID;
    close(cmd2);
    if ( name==0 ){
    waitstring=sprintf("%s",jID );
    waitstring2=sprintf("%s",jID);
    }
    else {
    waitstring=sprintf("%s:%s",waitstring,jID);
    waitstring2=sprintf("%s %s",waitstring2,jID);
    }
    cmd3=sprintf("qstat %s",waitstring2);
    cmd3 |& getline waitedjobstatus;
    close(cmd3)
    print "below is the waitingstring1 and waitingstring2";
	print waitstring;
    print waitstring2;
    print "below is te waited job status before qsub"
    print $waitedjobstatus;
    print "submitting _catsplit jobs";
	sysstring = sprintf("qsub -l %s -o %s_catsplit.log -j oe -q %s -N CtSplt%s -W depend=afterok:%s <<-EOF\ncat %s/%s_msplit*_optdups.txt > %s/opt_dups.txt;  cat %s/%s_msplit*_dups.txt > %s/dups.txt; cat %s/%s_msplit*_merged_nodups.txt > %s/merged_nodups.txt; \nEOF\n", walltime, outfile, queue, groupname, waitstring, dir, groupname, dir, dir, groupname, dir, dir, groupname, dir, dir);
    system(sysstring);
    cmd4=sprintf("qstat | grep CtSplt%s | cut -d ' ' -f 1",groupname);
    cmd4 |& getline jID_catsplit;
    close(cmd4);
    print "below is the _catsplit id";
	print jID_catsplit;
    print "submitting _rmsplit jobs";
	sysstring=sprintf("qsub -l %s -o %s_rmsplit.log -j oe -q %s -N RmSplt%s -W depend=afterok:%s <<-EOF\n rm %s/*_msplit*_optdups.txt; rm %s/*_msplit*_dups.txt; rm %s/*_msplit*_merged_nodups.txt; rm %s/split*;\nEOF", walltime, outfile, queue, groupname,jID_catsplit, dir, dir, dir, dir);
  system(sysstring);
    cmd=sprintf("qstat | grep RmSplt%s | cut -d ' ' -f 1",groupname);
    cmd |& getline jID_rmsplit;
    print "below is the jID_rmsplit:";
    print jID_rmsplit;
}


Added awk to parse config file

Added awk to parse config file

# awk library to parse config file

# if we are in find_sec look for things that match brackets
match($0, /\[([[:alnum:]_]).*\]/) {
  section = substr($0, (RSTART + 1), (RLENGTH - 2))

  # if we have encountered a new rule
  if (section != "RENDERERS") {
	  if (section in section_names) {
		  print "Error Parsing config @ line", FNR ": encountered section", section, "multiple times"
		exit -1
	  } else {
		  section_names[section] = 1
	  }
  }
  next
}

# if we detect a setting of a key value
/.*=.*/ {
	n = split($0, kval, "=")
	if (n != 2) {
		print "Error Parsing config @ line", FNR ": Bad key val", $0
		exit -1
	}

	key = kval[1]
	val = kval[2]

	# special exception for renderer: we use this to store converters
	if (section == "RENDERERS") {
		renderers[key] = val
	} else { 		# we are parsing a rule
		rules[section,key] = val
	}
}

# helper function to print all of the rules identified during the configuration
function dump_rules() {
	print "RULES"
	for (r in rules) {
		split(r,sep,SUBSEP)
		print "PATH",sep[1] ",", sep[2], "->", rules[r]

	}
}


Help: show web browser in getVersion

Help: show web browser in getVersion

####################################################################
# Help.awk                                                         #
####################################################################

# Return version as a string.
function getVersion(    build, gitHead) {
    initAudioPlayer()
    initPager()
    Platform = Platform ? Platform : detectProgram("uname", "-s", 1)
    if (ENVIRON["TRANS_BUILD"])
        build = "-" ENVIRON["TRANS_BUILD"]
    else {
        gitHead = getGitHead()
        build = gitHead ? "-git:" gitHead : ""
    }

    return ansi("bold", sprintf("%-22s%s%s\n\n", Name, Version, build)) \
        sprintf("%-22s%s\n", "platform", Platform)                      \
        sprintf("%-22s%s\n", "terminal type", ENVIRON["TERM"])          \
        sprintf("%-22s%s\n", "bi-di emulator", BiDiTerm ? BiDiTerm :
                "[N/A]")                                                \
        sprintf("%-22s%s\n", "gawk (GNU Awk)", PROCINFO["version"])     \
        sprintf("%s\n", FriBidi ? FriBidi :
                "fribidi (GNU FriBidi) [NOT INSTALLED]")                \
        sprintf("%-22s%s\n", "audio player", AudioPlayer ? AudioPlayer :
                "[NOT INSTALLED]")                                      \
        sprintf("%-22s%s\n", "terminal pager", Pager ? Pager :
                "[NOT INSTALLED]")                                      \
        sprintf("%-22s%s\n", "web browser", Option["browser"] != NONE ?
                Option["browser"] :"[NONE]")                            \
        sprintf("%-22s%s (%s)\n", "user locale", UserLocale, getName(UserLang)) \
        sprintf("%-22s%s\n", "home language", Option["hl"])             \
        sprintf("%-22s%s\n", "source language", join(Option["sls"], "+")) \
        sprintf("%-22s%s\n", "target language", join(Option["tl"], "+")) \
        sprintf("%-22s%s\n", "translation engine", Option["engine"])    \
        sprintf("%-22s%s\n", "proxy", Option["proxy"] ? Option["proxy"] :
                "[NONE]")                                               \
        sprintf("%-22s%s\n", "user-agent", Option["user-agent"] ? Option["user-agent"] :
                "[NONE]")                                               \
        sprintf("%-22s%s\n", "ip version", Option["ip-version"] ? Option["ip-version"] :
                "[DEFAULT]")                                            \
        sprintf("%-22s%s\n", "theme", Option["theme"])                  \
        sprintf("%-22s%s\n", "init file", InitScript ? InitScript : "[NONE]") \
        sprintf("\n%-22s%s", "Report bugs to:", "https://github.com/soimort/translate-shell/issues")
}

# Return help message as a string.
function getHelp() {
    return "Usage:  " ansi("bold", Command)                             \
        " [" ansi("underline", "OPTIONS") "]"                           \
        " [" ansi("underline", "SOURCES") "]"                           \
        ":[" ansi("underline", "TARGETS") "]"                           \
        " [" ansi("underline", "TEXT") "]..." RS                        \
        RS "Information options:" RS                                    \
        ins(1, ansi("bold", "-V") ", " ansi("bold", "-version")) RS     \
        ins(2, "Print version and exit.") RS                            \
        ins(1, ansi("bold", "-H") ", " ansi("bold", "-help")) RS        \
        ins(2, "Print help message and exit.") RS                       \
        ins(1, ansi("bold", "-M") ", " ansi("bold", "-man")) RS         \
        ins(2, "Show man page and exit.") RS                            \
        ins(1, ansi("bold", "-T") ", " ansi("bold", "-reference")) RS   \
        ins(2, "Print reference table of languages and exit.") RS       \
        ins(1, ansi("bold", "-R") ", " ansi("bold", "-reference-english")) RS \
        ins(2, "Print reference table of languages (in English names) and exit.") RS \
        ins(1, ansi("bold", "-L ") ansi("underline", "CODES")           \
            ", " ansi("bold", "-list ") ansi("underline", "CODES")) RS  \
        ins(2, "Print details of languages and exit.") RS               \
        ins(1, ansi("bold", "-S") ", " ansi("bold", "-list-engines")) RS \
        ins(2, "List available translation engines and exit.") RS       \
        ins(1, ansi("bold", "-U") ", " ansi("bold", "-upgrade")) RS     \
        ins(2, "Check for upgrade of this program.") RS                 \
        RS "Translator options:" RS                                     \
        ins(1, ansi("bold", "-e ") ansi("underline", "ENGINE")          \
            ", " ansi("bold", "-engine ") ansi("underline", "ENGINE")) RS \
        ins(2, "Specify the translation engine to use.") RS             \
        RS "Display options:" RS                                        \
        ins(1, ansi("bold", "-verbose")) RS                             \
        ins(2, "Verbose mode. (default)") RS                            \
        ins(1, ansi("bold", "-b") ", " ansi("bold", "-brief")) RS       \
        ins(2, "Brief mode.") RS                                        \
        ins(1, ansi("bold", "-d") ", " ansi("bold", "-dictionary")) RS  \
        ins(2, "Dictionary mode.") RS                                   \
        ins(1, ansi("bold", "-identify")) RS                            \
        ins(2, "Language identification.") RS                           \
        ins(1, ansi("bold", "-show-original ") ansi("underline", "Y/n")) RS \
        ins(2, "Show original text or not.") RS                         \
        ins(1, ansi("bold", "-show-original-phonetics ") ansi("underline", "Y/n")) RS \
        ins(2, "Show phonetic notation of original text or not.") RS    \
        ins(1, ansi("bold", "-show-translation ") ansi("underline", "Y/n")) RS \
        ins(2, "Show translation or not.") RS                           \
        ins(1, ansi("bold", "-show-translation-phonetics ") ansi("underline", "Y/n")) RS \
        ins(2, "Show phonetic notation of translation or not.") RS      \
        ins(1, ansi("bold", "-show-prompt-message ") ansi("underline", "Y/n")) RS \
        ins(2, "Show prompt message or not.") RS                        \
        ins(1, ansi("bold", "-show-languages ") ansi("underline", "Y/n")) RS \
        ins(2, "Show source and target languages or not.") RS           \
        ins(1, ansi("bold", "-show-original-dictionary ") ansi("underline", "y/N")) RS \
        ins(2, "Show dictionary entry of original text or not.") RS     \
        ins(1, ansi("bold", "-show-dictionary ") ansi("underline", "Y/n")) RS \
        ins(2, "Show dictionary entry of translation or not.") RS       \
        ins(1, ansi("bold", "-show-alternatives ") ansi("underline", "Y/n")) RS \
        ins(2, "Show alternative translations or not.") RS              \
        ins(1, ansi("bold", "-w ") ansi("underline", "NUM")             \
            ", " ansi("bold", "-width ") ansi("underline", "NUM")) RS   \
        ins(2, "Specify the screen width for padding.") RS              \
        ins(1, ansi("bold", "-indent ") ansi("underline", "NUM")) RS    \
        ins(2, "Specify the size of indent (number of spaces).") RS     \
        ins(1, ansi("bold", "-theme ") ansi("underline", "FILENAME")) RS \
        ins(2, "Specify the theme to use.") RS                          \
        ins(1, ansi("bold", "-no-theme")) RS                            \
        ins(2, "Do not use any other theme than default.") RS           \
        ins(1, ansi("bold", "-no-ansi")) RS                             \
        ins(2, "Do not use ANSI escape codes.") RS                      \
        ins(1, ansi("bold", "-no-autocorrect")) RS                      \
        ins(2, "Do not autocorrect. (if defaulted by the translation engine)") RS \
        ins(1, ansi("bold", "-no-bidi")) RS                             \
        ins(2, "Do not convert bidirectional texts.") RS                \
        ins(1, ansi("bold", "-bidi")) RS                                \
        ins(2, "Always convert bidirectional texts.") RS                \
        ins(1, ansi("bold", "-no-warn")) RS                             \
        ins(2, "Do not write warning messages to stderr.") RS           \
        ins(1, ansi("bold", "-dump")) RS                                \
        ins(2, "Print raw API response instead.") RS                    \
        RS "Audio options:" RS                                          \
        ins(1, ansi("bold", "-p, -play")) RS                            \
        ins(2, "Listen to the translation.") RS                         \
        ins(1, ansi("bold", "-speak")) RS                               \
        ins(2, "Listen to the original text.") RS                       \
        ins(1, ansi("bold", "-n ") ansi("underline", "VOICE")           \
            ", " ansi("bold", "-narrator ") ansi("underline", "VOICE")) RS \
        ins(2, "Specify the narrator, and listen to the translation.") RS \
        ins(1, ansi("bold", "-player ") ansi("underline", "PROGRAM")) RS \
        ins(2, "Specify the audio player to use, and listen to the translation.") RS \
        ins(1, ansi("bold", "-no-play")) RS                             \
        ins(2, "Do not listen to the translation.") RS                  \
        ins(1, ansi("bold", "-no-translate")) RS                        \
        ins(2, "Do not translate anything when using -speak.") RS       \
        ins(1, ansi("bold", "-download-audio")) RS                      \
        ins(2, "Download the audio to the current directory.") RS       \
        ins(1, ansi("bold", "-download-audio-as ") ansi("underline", "FILENAME")) RS \
        ins(2, "Download the audio to the specified file.") RS          \
        RS "Terminal paging and browsing options:" RS                   \
        ins(1, ansi("bold", "-v") ", " ansi("bold", "-view")) RS        \
        ins(2, "View the translation in a terminal pager.") RS          \
        ins(1, ansi("bold", "-pager ") ansi("underline", "PROGRAM")) RS \
        ins(2, "Specify the terminal pager to use, and view the translation.") RS \
        ins(1, ansi("bold", "-no-view") ", " ansi("bold", "-no-pager")) RS \
        ins(2, "Do not view the translation in a terminal pager.") RS   \
        ins(1, ansi("bold", "-browser ") ansi("underline", "PROGRAM")) RS \
        ins(2, "Specify the web browser to use.") RS                    \
        RS "Networking options:" RS                                     \
        ins(1, ansi("bold", "-x ") ansi("underline", "HOST:PORT")       \
            ", " ansi("bold", "-proxy ") ansi("underline", "HOST:PORT")) RS \
        ins(2, "Use HTTP proxy on given port.") RS                      \
        ins(1, ansi("bold", "-u ") ansi("underline", "STRING")          \
            ", " ansi("bold", "-user-agent ") ansi("underline", "STRING")) RS \
        ins(2, "Specify the User-Agent to identify as.") RS             \
        ins(1, ansi("bold", "-4") ", " ansi("bold", "-ipv4")            \
            ", " ansi("bold", "-inet4-only")) RS                        \
        ins(2, "Connect only to IPv4 addresses.") RS                    \
        ins(1, ansi("bold", "-6") ", " ansi("bold", "-ipv6")            \
            ", " ansi("bold", "-inet6-only")) RS                        \
        ins(2, "Connect only to IPv6 addresses.") RS                    \
        RS "Interactive shell options:" RS                              \
        ins(1, ansi("bold", "-I") ", " ansi("bold", "-interactive") ", " ansi("bold", "-shell")) RS \
        ins(2, "Start an interactive shell.") RS                        \
        ins(1, ansi("bold", "-E") ", " ansi("bold", "-emacs")) RS       \
        ins(2, "Start the GNU Emacs front-end for an interactive shell.") RS \
        ins(1, ansi("bold", "-no-rlwrap")) RS                           \
        ins(2, "Do not invoke rlwrap when starting an interactive shell.") RS \
        RS "I/O options:" RS                                            \
        ins(1, ansi("bold", "-i ") ansi("underline", "FILENAME")        \
            ", " ansi("bold", "-input ") ansi("underline", "FILENAME")) RS \
        ins(2, "Specify the input file.") RS                            \
        ins(1, ansi("bold", "-o ") ansi("underline", "FILENAME")        \
            ", " ansi("bold", "-output ") ansi("underline", "FILENAME")) RS \
        ins(2, "Specify the output file.") RS                           \
        RS "Language preference options:" RS                            \
        ins(1, ansi("bold", "-l ") ansi("underline", "CODE")            \
            ", " ansi("bold", "-hl ") ansi("underline", "CODE")         \
            ", " ansi("bold", "-lang ") ansi("underline", "CODE")) RS   \
        ins(2, "Specify your home language.") RS                        \
        ins(1, ansi("bold", "-s ") ansi("underline", "CODES")           \
            ", " ansi("bold", "-sl ") ansi("underline", "CODES")        \
            ", " ansi("bold", "-source ") ansi("underline", "CODES")    \
            ", " ansi("bold", "-from ") ansi("underline", "CODES")) RS  \
        ins(2, "Specify the source language(s), joined by '+'.") RS     \
        ins(1, ansi("bold", "-t ") ansi("underline", "CODES")           \
            ", " ansi("bold", "-tl ") ansi("underline", "CODES")        \
            ", " ansi("bold", "-target ") ansi("underline", "CODES")    \
            ", " ansi("bold", "-to ") ansi("underline", "CODES")) RS    \
        ins(2, "Specify the target language(s), joined by '+'.") RS     \
        RS "Other options:" RS                                          \
        ins(1, ansi("bold", "-no-init")) RS                             \
        ins(2, "Do not load any initialization script.") RS             \
        RS "See the man page " Command "(1) for more information."
}

# Show man page.
function showMan(    temp) {
    if (ENVIRON["TRANS_MANPAGE"]) {
        initPager()
        Groff = detectProgram("groff", "--version")
        if (Pager && Groff) {
            temp = "echo -E \"${TRANS_MANPAGE}\""
            temp = temp PIPE                                            \
                Groff " -Wall -mtty-char -mandoc -Tutf8 "               \
                "-rLL=" Option["width"] "n -rLT=" Option["width"] "n"
            switch (Pager) {
            case "less":
                temp = temp PIPE                                        \
                    Pager " -s -P\"\\ \\Manual page " Command "(1) line %lt (press h for help or q to quit)\""
                break
            case "most":
                temp = temp PIPE Pager " -Cs"
                break
            default: # more
                temp = temp PIPE Pager
            }
            system(temp)
            return
        }
    }
    if (fileExists(ENVIRON["TRANS_DIR"] "/man/" Command ".1"))
        system("man " parameterize(ENVIRON["TRANS_DIR"] "/man/" Command ".1") SUPERR)
    else if (system("man " Command SUPERR))
        print getHelp()
}

# Return a reference table of languages as a string.
# Parameters:
#     displayName = "endonym" or "name"
function getReference(displayName,
                      ####
                      code, col, cols, i, j, name, num, r, rows, saveSortedIn,
                      t1, t2) {
    # number of language codes with stable support
    num = 0
    for (code in Locale)
        if (Locale[code]["support"] != "unstable")
            num++
    rows = int(num / 3) + (num % 3 ? 1 : 0)
    cols[0][0] = cols[1][0] = cols[2][0] = NULLSTR
    i = 0
    saveSortedIn = PROCINFO["sorted_in"]
    PROCINFO["sorted_in"] = displayName == "endonym" ? "@ind_num_asc" :
        "compName"
    for (code in Locale) {
        # show languages only with stable support
        if (Locale[code]["support"] != "unstable") {
            col = int(i / rows)
            append(cols[col], code)
            i++
        }
    }
    PROCINFO["sorted_in"] = saveSortedIn

    if (displayName == "endonym") {
        r = "┌" replicate("─", 23) "┬" replicate("─", 23) "┬" replicate("─", 23) "┐" RS
        for (i = 0; i < rows; i++) {
            r = r "│"
            for (j = 0; j < 3; j++) {
                if (cols[j][i]) {
                    t1 = getDisplay(cols[j][i])
                    switch (cols[j][i]) { # fix rendered text width
                    case "he":
                        t1 = sprintf(" %-18s", t1)
                        break
                    case "ur":
                        t1 = sprintf(" %-17s", t1)
                        break
                    case "hi": case "gu": case "km": case "kn":
                    case "my": case "ne": case "pa": case "si":
                    case "ta": case "te": case "yi":
                        t1 = sprintf(" %-16s", t1)
                        break
                    case "yue":
                        t1 = sprintf(" %-13s", t1)
                        break
                    case "ja": case "ko":
                        t1 = sprintf(" %-12s", t1)
                        break
                    case "zh-CN": case "zh-TW":
                        t1 = sprintf(" %-11s", t1)
                        break
                    default:
                        if (length(t1) <= 15)
                            t1 = sprintf(" %-15s", t1)
                    }
                    switch (length(cols[j][i])) {
                    case 1: case 2: case 3: case 4:
                        t2 = sprintf("- %s │", ansi("bold", sprintf("%4s", cols[j][i])))
                        break
                    case 5:
                        t2 = sprintf("- %s│", ansi("bold", cols[j][i]))
                        break
                    case 6:
                        t2 = sprintf("-%s│", ansi("bold", cols[j][i]))
                        break
                    case 7:
                        t2 = sprintf("-%s", ansi("bold", cols[j][i]))
                        break
                    default:
                        t2 = ansi("bold", cols[j][i])
                    }
                    r = r t1 t2
                } else
                    r = r sprintf("%23s│", NULLSTR)
            }
            r = r RS
        }
        r = r "└" replicate("─", 23) "┴" replicate("─", 23) "┴" replicate("─", 23) "┘"
    } else {
        r = "┌" replicate("─", 23) "┬" replicate("─", 23) "┬" replicate("─", 23) "┐" RS
        for (i = 0; i < rows; i++) {
            r = r "│"
            for (j = 0; j < 3; j++) {
                if (cols[j][i]) {
                    t1 = getName(cols[j][i])
                    if (length(t1) > 15)
                        t1 = substr(t1, 1, 12) "..."
                    t1 = sprintf(" %-15s", t1)
                    switch (length(cols[j][i])) {
                    case 1: case 2: case 3: case 4:
                        t2 = sprintf("- %s │", ansi("bold", sprintf("%4s", cols[j][i])))
                        break
                    case 5:
                        t2 = sprintf("- %s│", ansi("bold", cols[j][i]))
                        break
                    case 6:
                        t2 = sprintf("-%s│", ansi("bold", cols[j][i]))
                        break
                    case 7:
                        t2 = sprintf("-%s", ansi("bold", cols[j][i]))
                        break
                    default:
                        t2 = ansi("bold", cols[j][i])
                    }
                    r = r t1 t2
                } else
                    r = r sprintf("%23s│", NULLSTR)
            }
            r = r RS
        }
        r = r "└" replicate("─", 23) "┴" replicate("─", 23) "┴" replicate("─", 23) "┘"
    }
    return r
}

# Return detailed information of languages as a string.
function getList(codes,    code, i, r, saveSortedIn) {
    r = NULLSTR
    if (!isarray(codes))
        r = getDetails(codes)
    else if (anything(codes)) {
        saveSortedIn = PROCINFO["sorted_in"]
        PROCINFO["sorted_in"] = "@ind_num_asc"
        for (i in codes)
            r = (r ? r RS prettify("target-seperator", replicate(Option["chr-target-seperator"], Option["width"])) RS \
                 : r) getDetails(codes[i])
        PROCINFO["sorted_in"] = saveSortedIn
    } else
        r = getDetails(Option["hl"])
    return r
}

####################################################################
# Help.awk                                                         #
####################################################################

# Return version as a string.
function getVersion(    build, gitHead) {
    initAudioPlayer()
    initPager()
    Platform = Platform ? Platform : detectProgram("uname", "-s", 1)
    if (ENVIRON["TRANS_BUILD"])
        build = "-" ENVIRON["TRANS_BUILD"]
    else {
        gitHead = getGitHead()
        build = gitHead ? "-git:" gitHead : ""
    }

    return ansi("bold", sprintf("%-22s%s%s\n\n", Name, Version, build)) \
        sprintf("%-22s%s\n", "platform", Platform)                      \
        sprintf("%-22s%s\n", "terminal type", ENVIRON["TERM"])          \
        sprintf("%-22s%s\n", "bi-di emulator", BiDiTerm ? BiDiTerm :
                "[N/A]")                                                \
        sprintf("%-22s%s\n", "gawk (GNU Awk)", PROCINFO["version"])     \
        sprintf("%s\n", FriBidi ? FriBidi :
                "fribidi (GNU FriBidi) [NOT INSTALLED]")                \
        sprintf("%-22s%s\n", "audio player", AudioPlayer ? AudioPlayer :
                "[NOT INSTALLED]")                                      \
        sprintf("%-22s%s\n", "terminal pager", Pager ? Pager :
                "[NOT INSTALLED]")                                      \
        sprintf("%-22s%s (%s)\n", "user locale", UserLocale, getName(UserLang)) \
        sprintf("%-22s%s\n", "home language", Option["hl"])             \
        sprintf("%-22s%s\n", "source language", join(Option["sls"], "+")) \
        sprintf("%-22s%s\n", "target language", join(Option["tl"], "+")) \
        sprintf("%-22s%s\n", "translation engine", Option["engine"])    \
        sprintf("%-22s%s\n", "proxy", Option["proxy"] ? Option["proxy"] :
                "[NONE]")                                               \
        sprintf("%-22s%s\n", "user-agent", Option["user-agent"] ? Option["user-agent"] :
                "[NONE]")                                               \
        sprintf("%-22s%s\n", "ip version", Option["ip-version"] ? Option["ip-version"] :
                "[DEFAULT]")                                            \
        sprintf("%-22s%s\n", "theme", Option["theme"])                  \
        sprintf("%-22s%s\n", "init file", InitScript ? InitScript : "[NONE]") \
        sprintf("\n%-22s%s", "Report bugs to:", "https://github.com/soimort/translate-shell/issues")
}

# Return help message as a string.
function getHelp() {
    return "Usage:  " ansi("bold", Command)                             \
        " [" ansi("underline", "OPTIONS") "]"                           \
        " [" ansi("underline", "SOURCES") "]"                           \
        ":[" ansi("underline", "TARGETS") "]"                           \
        " [" ansi("underline", "TEXT") "]..." RS                        \
        RS "Information options:" RS                                    \
        ins(1, ansi("bold", "-V") ", " ansi("bold", "-version")) RS     \
        ins(2, "Print version and exit.") RS                            \
        ins(1, ansi("bold", "-H") ", " ansi("bold", "-help")) RS        \
        ins(2, "Print help message and exit.") RS                       \
        ins(1, ansi("bold", "-M") ", " ansi("bold", "-man")) RS         \
        ins(2, "Show man page and exit.") RS                            \
        ins(1, ansi("bold", "-T") ", " ansi("bold", "-reference")) RS   \
        ins(2, "Print reference table of languages and exit.") RS       \
        ins(1, ansi("bold", "-R") ", " ansi("bold", "-reference-english")) RS \
        ins(2, "Print reference table of languages (in English names) and exit.") RS \
        ins(1, ansi("bold", "-L ") ansi("underline", "CODES")           \
            ", " ansi("bold", "-list ") ansi("underline", "CODES")) RS  \
        ins(2, "Print details of languages and exit.") RS               \
        ins(1, ansi("bold", "-S") ", " ansi("bold", "-list-engines")) RS \
        ins(2, "List available translation engines and exit.") RS       \
        ins(1, ansi("bold", "-U") ", " ansi("bold", "-upgrade")) RS     \
        ins(2, "Check for upgrade of this program.") RS                 \
        RS "Translator options:" RS                                     \
        ins(1, ansi("bold", "-e ") ansi("underline", "ENGINE")          \
            ", " ansi("bold", "-engine ") ansi("underline", "ENGINE")) RS \
        ins(2, "Specify the translation engine to use.") RS             \
        RS "Display options:" RS                                        \
        ins(1, ansi("bold", "-verbose")) RS                             \
        ins(2, "Verbose mode. (default)") RS                            \
        ins(1, ansi("bold", "-b") ", " ansi("bold", "-brief")) RS       \
        ins(2, "Brief mode.") RS                                        \
        ins(1, ansi("bold", "-d") ", " ansi("bold", "-dictionary")) RS  \
        ins(2, "Dictionary mode.") RS                                   \
        ins(1, ansi("bold", "-identify")) RS                            \
        ins(2, "Language identification.") RS                           \
        ins(1, ansi("bold", "-show-original ") ansi("underline", "Y/n")) RS \
        ins(2, "Show original text or not.") RS                         \
        ins(1, ansi("bold", "-show-original-phonetics ") ansi("underline", "Y/n")) RS \
        ins(2, "Show phonetic notation of original text or not.") RS    \
        ins(1, ansi("bold", "-show-translation ") ansi("underline", "Y/n")) RS \
        ins(2, "Show translation or not.") RS                           \
        ins(1, ansi("bold", "-show-translation-phonetics ") ansi("underline", "Y/n")) RS \
        ins(2, "Show phonetic notation of translation or not.") RS      \
        ins(1, ansi("bold", "-show-prompt-message ") ansi("underline", "Y/n")) RS \
        ins(2, "Show prompt message or not.") RS                        \
        ins(1, ansi("bold", "-show-languages ") ansi("underline", "Y/n")) RS \
        ins(2, "Show source and target languages or not.") RS           \
        ins(1, ansi("bold", "-show-original-dictionary ") ansi("underline", "y/N")) RS \
        ins(2, "Show dictionary entry of original text or not.") RS     \
        ins(1, ansi("bold", "-show-dictionary ") ansi("underline", "Y/n")) RS \
        ins(2, "Show dictionary entry of translation or not.") RS       \
        ins(1, ansi("bold", "-show-alternatives ") ansi("underline", "Y/n")) RS \
        ins(2, "Show alternative translations or not.") RS              \
        ins(1, ansi("bold", "-w ") ansi("underline", "NUM")             \
            ", " ansi("bold", "-width ") ansi("underline", "NUM")) RS   \
        ins(2, "Specify the screen width for padding.") RS              \
        ins(1, ansi("bold", "-indent ") ansi("underline", "NUM")) RS    \
        ins(2, "Specify the size of indent (number of spaces).") RS     \
        ins(1, ansi("bold", "-theme ") ansi("underline", "FILENAME")) RS \
        ins(2, "Specify the theme to use.") RS                          \
        ins(1, ansi("bold", "-no-theme")) RS                            \
        ins(2, "Do not use any other theme than default.") RS           \
        ins(1, ansi("bold", "-no-ansi")) RS                             \
        ins(2, "Do not use ANSI escape codes.") RS                      \
        ins(1, ansi("bold", "-no-autocorrect")) RS                      \
        ins(2, "Do not autocorrect. (if defaulted by the translation engine)") RS \
        ins(1, ansi("bold", "-no-bidi")) RS                             \
        ins(2, "Do not convert bidirectional texts.") RS                \
        ins(1, ansi("bold", "-bidi")) RS                                \
        ins(2, "Always convert bidirectional texts.") RS                \
        ins(1, ansi("bold", "-no-warn")) RS                             \
        ins(2, "Do not write warning messages to stderr.") RS           \
        ins(1, ansi("bold", "-dump")) RS                                \
        ins(2, "Print raw API response instead.") RS                    \
        RS "Audio options:" RS                                          \
        ins(1, ansi("bold", "-p, -play")) RS                            \
        ins(2, "Listen to the translation.") RS                         \
        ins(1, ansi("bold", "-speak")) RS                               \
        ins(2, "Listen to the original text.") RS                       \
        ins(1, ansi("bold", "-n ") ansi("underline", "VOICE")           \
            ", " ansi("bold", "-narrator ") ansi("underline", "VOICE")) RS \
        ins(2, "Specify the narrator, and listen to the translation.") RS \
        ins(1, ansi("bold", "-player ") ansi("underline", "PROGRAM")) RS \
        ins(2, "Specify the audio player to use, and listen to the translation.") RS \
        ins(1, ansi("bold", "-no-play")) RS                             \
        ins(2, "Do not listen to the translation.") RS                  \
        ins(1, ansi("bold", "-no-translate")) RS                        \
        ins(2, "Do not translate anything when using -speak.") RS       \
        ins(1, ansi("bold", "-download-audio")) RS                      \
        ins(2, "Download the audio to the current directory.") RS       \
        ins(1, ansi("bold", "-download-audio-as ") ansi("underline", "FILENAME")) RS \
        ins(2, "Download the audio to the specified file.") RS          \
        RS "Terminal paging and browsing options:" RS                   \
        ins(1, ansi("bold", "-v") ", " ansi("bold", "-view")) RS        \
        ins(2, "View the translation in a terminal pager.") RS          \
        ins(1, ansi("bold", "-pager ") ansi("underline", "PROGRAM")) RS \
        ins(2, "Specify the terminal pager to use, and view the translation.") RS \
        ins(1, ansi("bold", "-no-view") ", " ansi("bold", "-no-pager")) RS \
        ins(2, "Do not view the translation in a terminal pager.") RS   \
        ins(1, ansi("bold", "-browser ") ansi("underline", "PROGRAM")) RS \
        ins(2, "Specify the web browser to use.") RS                    \
        RS "Networking options:" RS                                     \
        ins(1, ansi("bold", "-x ") ansi("underline", "HOST:PORT")       \
            ", " ansi("bold", "-proxy ") ansi("underline", "HOST:PORT")) RS \
        ins(2, "Use HTTP proxy on given port.") RS                      \
        ins(1, ansi("bold", "-u ") ansi("underline", "STRING")          \
            ", " ansi("bold", "-user-agent ") ansi("underline", "STRING")) RS \
        ins(2, "Specify the User-Agent to identify as.") RS             \
        ins(1, ansi("bold", "-4") ", " ansi("bold", "-ipv4")            \
            ", " ansi("bold", "-inet4-only")) RS                        \
        ins(2, "Connect only to IPv4 addresses.") RS                    \
        ins(1, ansi("bold", "-6") ", " ansi("bold", "-ipv6")            \
            ", " ansi("bold", "-inet6-only")) RS                        \
        ins(2, "Connect only to IPv6 addresses.") RS                    \
        RS "Interactive shell options:" RS                              \
        ins(1, ansi("bold", "-I") ", " ansi("bold", "-interactive") ", " ansi("bold", "-shell")) RS \
        ins(2, "Start an interactive shell.") RS                        \
        ins(1, ansi("bold", "-E") ", " ansi("bold", "-emacs")) RS       \
        ins(2, "Start the GNU Emacs front-end for an interactive shell.") RS \
        ins(1, ansi("bold", "-no-rlwrap")) RS                           \
        ins(2, "Do not invoke rlwrap when starting an interactive shell.") RS \
        RS "I/O options:" RS                                            \
        ins(1, ansi("bold", "-i ") ansi("underline", "FILENAME")        \
            ", " ansi("bold", "-input ") ansi("underline", "FILENAME")) RS \
        ins(2, "Specify the input file.") RS                            \
        ins(1, ansi("bold", "-o ") ansi("underline", "FILENAME")        \
            ", " ansi("bold", "-output ") ansi("underline", "FILENAME")) RS \
        ins(2, "Specify the output file.") RS                           \
        RS "Language preference options:" RS                            \
        ins(1, ansi("bold", "-l ") ansi("underline", "CODE")            \
            ", " ansi("bold", "-hl ") ansi("underline", "CODE")         \
            ", " ansi("bold", "-lang ") ansi("underline", "CODE")) RS   \
        ins(2, "Specify your home language.") RS                        \
        ins(1, ansi("bold", "-s ") ansi("underline", "CODES")           \
            ", " ansi("bold", "-sl ") ansi("underline", "CODES")        \
            ", " ansi("bold", "-source ") ansi("underline", "CODES")    \
            ", " ansi("bold", "-from ") ansi("underline", "CODES")) RS  \
        ins(2, "Specify the source language(s), joined by '+'.") RS     \
        ins(1, ansi("bold", "-t ") ansi("underline", "CODES")           \
            ", " ansi("bold", "-tl ") ansi("underline", "CODES")        \
            ", " ansi("bold", "-target ") ansi("underline", "CODES")    \
            ", " ansi("bold", "-to ") ansi("underline", "CODES")) RS    \
        ins(2, "Specify the target language(s), joined by '+'.") RS     \
        RS "Other options:" RS                                          \
        ins(1, ansi("bold", "-no-init")) RS                             \
        ins(2, "Do not load any initialization script.") RS             \
        RS "See the man page " Command "(1) for more information."
}

# Show man page.
function showMan(    temp) {
    if (ENVIRON["TRANS_MANPAGE"]) {
        initPager()
        Groff = detectProgram("groff", "--version")
        if (Pager && Groff) {
            temp = "echo -E \"${TRANS_MANPAGE}\""
            temp = temp PIPE                                            \
                Groff " -Wall -mtty-char -mandoc -Tutf8 "               \
                "-rLL=" Option["width"] "n -rLT=" Option["width"] "n"
            switch (Pager) {
            case "less":
                temp = temp PIPE                                        \
                    Pager " -s -P\"\\ \\Manual page " Command "(1) line %lt (press h for help or q to quit)\""
                break
            case "most":
                temp = temp PIPE Pager " -Cs"
                break
            default: # more
                temp = temp PIPE Pager
            }
            system(temp)
            return
        }
    }
    if (fileExists(ENVIRON["TRANS_DIR"] "/man/" Command ".1"))
        system("man " parameterize(ENVIRON["TRANS_DIR"] "/man/" Command ".1") SUPERR)
    else if (system("man " Command SUPERR))
        print getHelp()
}

# Return a reference table of languages as a string.
# Parameters:
#     displayName = "endonym" or "name"
function getReference(displayName,
                      ####
                      code, col, cols, i, j, name, num, r, rows, saveSortedIn,
                      t1, t2) {
    # number of language codes with stable support
    num = 0
    for (code in Locale)
        if (Locale[code]["support"] != "unstable")
            num++
    rows = int(num / 3) + (num % 3 ? 1 : 0)
    cols[0][0] = cols[1][0] = cols[2][0] = NULLSTR
    i = 0
    saveSortedIn = PROCINFO["sorted_in"]
    PROCINFO["sorted_in"] = displayName == "endonym" ? "@ind_num_asc" :
        "compName"
    for (code in Locale) {
        # show languages only with stable support
        if (Locale[code]["support"] != "unstable") {
            col = int(i / rows)
            append(cols[col], code)
            i++
        }
    }
    PROCINFO["sorted_in"] = saveSortedIn

    if (displayName == "endonym") {
        r = "┌" replicate("─", 23) "┬" replicate("─", 23) "┬" replicate("─", 23) "┐" RS
        for (i = 0; i < rows; i++) {
            r = r "│"
            for (j = 0; j < 3; j++) {
                if (cols[j][i]) {
                    t1 = getDisplay(cols[j][i])
                    switch (cols[j][i]) { # fix rendered text width
                    case "he":
                        t1 = sprintf(" %-18s", t1)
                        break
                    case "ur":
                        t1 = sprintf(" %-17s", t1)
                        break
                    case "hi": case "gu": case "km": case "kn":
                    case "my": case "ne": case "pa": case "si":
                    case "ta": case "te": case "yi":
                        t1 = sprintf(" %-16s", t1)
                        break
                    case "yue":
                        t1 = sprintf(" %-13s", t1)
                        break
                    case "ja": case "ko":
                        t1 = sprintf(" %-12s", t1)
                        break
                    case "zh-CN": case "zh-TW":
                        t1 = sprintf(" %-11s", t1)
                        break
                    default:
                        if (length(t1) <= 15)
                            t1 = sprintf(" %-15s", t1)
                    }
                    switch (length(cols[j][i])) {
                    case 1: case 2: case 3: case 4:
                        t2 = sprintf("- %s │", ansi("bold", sprintf("%4s", cols[j][i])))
                        break
                    case 5:
                        t2 = sprintf("- %s│", ansi("bold", cols[j][i]))
                        break
                    case 6:
                        t2 = sprintf("-%s│", ansi("bold", cols[j][i]))
                        break
                    case 7:
                        t2 = sprintf("-%s", ansi("bold", cols[j][i]))
                        break
                    default:
                        t2 = ansi("bold", cols[j][i])
                    }
                    r = r t1 t2
                } else
                    r = r sprintf("%23s│", NULLSTR)
            }
            r = r RS
        }
        r = r "└" replicate("─", 23) "┴" replicate("─", 23) "┴" replicate("─", 23) "┘"
    } else {
        r = "┌" replicate("─", 23) "┬" replicate("─", 23) "┬" replicate("─", 23) "┐" RS
        for (i = 0; i < rows; i++) {
            r = r "│"
            for (j = 0; j < 3; j++) {
                if (cols[j][i]) {
                    t1 = getName(cols[j][i])
                    if (length(t1) > 15)
                        t1 = substr(t1, 1, 12) "..."
                    t1 = sprintf(" %-15s", t1)
                    switch (length(cols[j][i])) {
                    case 1: case 2: case 3: case 4:
                        t2 = sprintf("- %s │", ansi("bold", sprintf("%4s", cols[j][i])))
                        break
                    case 5:
                        t2 = sprintf("- %s│", ansi("bold", cols[j][i]))
                        break
                    case 6:
                        t2 = sprintf("-%s│", ansi("bold", cols[j][i]))
                        break
                    case 7:
                        t2 = sprintf("-%s", ansi("bold", cols[j][i]))
                        break
                    default:
                        t2 = ansi("bold", cols[j][i])
                    }
                    r = r t1 t2
                } else
                    r = r sprintf("%23s│", NULLSTR)
            }
            r = r RS
        }
        r = r "└" replicate("─", 23) "┴" replicate("─", 23) "┴" replicate("─", 23) "┘"
    }
    return r
}

# Return detailed information of languages as a string.
function getList(codes,    code, i, r, saveSortedIn) {
    r = NULLSTR
    if (!isarray(codes))
        r = getDetails(codes)
    else if (anything(codes)) {
        saveSortedIn = PROCINFO["sorted_in"]
        PROCINFO["sorted_in"] = "@ind_num_asc"
        for (i in codes)
            r = (r ? r RS prettify("target-seperator", replicate(Option["chr-target-seperator"], Option["width"])) RS \
                 : r) getDetails(codes[i])
        PROCINFO["sorted_in"] = saveSortedIn
    } else
        r = getDetails(Option["hl"])
    return r
}


Fix seasons in c3

Fix seasons in c3

# Print the processed "Episode" lines from a WebScraper csv file saved in tsv format

# INVOCATION:
#       awk -v EPISODE_INFO_FILE=$EPISODE_INFO_FILE -v ERROR_FILE=$ERROR_FILE \
#           -f getBBoxEpisodesFrom-webscraper.awk $EPISODES_SORTED_FILE >$EPISODES_SPREADSHEET_FILE

# Field numbers
#    1 web-scraper-start-url  2 SsnURL     3 SsnURL-href    4 URL        5 Program_Title
#    6 Episode_Title          7 Year       8 Duration       9 Rating    10 Description

BEGIN {
    FS="\t"
    OFS="\t"
    print "Sortkey\tTitle\tSeasons\tEpisodes\tDuration\tYear(s)\tRating\tDescription"
    # For debugging variations in seasons and episodes format
    str = "date +%y%m%d.%H%M%S"
    str | getline longdate
    close str
    for ( i = 1; i <= 4; i++ ) {
        outfile = "BBox-scrapes/c" i "-" longdate ".csv"
        print "Type\t#\tSortkey\tURL\tshowTitle\tepisodeTitle\tYear(s)" > outfile
    }
}

{
    for ( i = 1; i <= NF; i++ ) {
        if ($i == "null")
            $i = ""
    }
}

/\/us\/movie\/|\/us\/episode\// {
    baseURL = $1
    URL = $4
    showTitle = $5
    episodeTitle = $6
    Years = $7
    Duration = $8
    Rating = $9
    Description = $10
    showtype = "S"

    shortURL = URL
    episodeSeason = ""
    # Season 3, Episode 8
    if (match (episodeTitle, /^Season [[:digit:]]+|^Series [[:digit:]]+/))
        episodeSeason = substr(episodeTitle,8,RLENGTH-7)

    # Extract sortkey from URL
    nflds = split (URL,fld,"_")
    if (URL ~ /_S[[:digit:]]*_E[[:digit:]]*_[[:digit:]]*$/) {
        # /us/episode/35_Days_S3_E8_23851
        seasonNumber = substr(fld[nflds-2], 2)
        episodeNumber = substr(fld[nflds-1], 2)
        if (baseURL ~ /The_Edinburgh_Show_23924$/) {
            episodeSeason = Years
        }
        # Give precedence to season number in episodeTitle over season number in URL
        if (episodeSeason != "" && seasonNumber+0 != episodeSeason+0) {
            revisedSeasons1 += 1
            sub (/^\/us\/episode\//,"",shortURL)
            printf ("==> Fixed c1 season: %02d-%02d\t%s\t%s\n", \
                    seasonNumber, episodeSeason, shortURL, episodeTitle) >> ERROR_FILE
            seasonNumber = episodeSeason
        }
        sortkey = sprintf ("%s%02dE%03d", showtype, seasonNumber, episodeNumber)
        c1Num += 1
        outfile = "BBox-scrapes/c1-" longdate ".csv"
        printf ("c1\t%d\t%s\t%s\t%s\t%s\t%s\n",c1Num,sortkey,URL,showTitle,episodeTitle,Years) >> outfile
    } else if (URL ~ /_E[[:digit:]]*_[[:digit:]]*$/) {
        # /us/episode/35_Hours_E1_26129
        revisedSeasons2 += 1
        episodeSeason = Years
        if (episodeSeason != "" && seasonNumber+0 != episodeSeason+0) {
            printf ("==> Fixed c2 season: %02d-%02d\t%s\t%s\n", \
                    seasonNumber, episodeSeason, shortURL, episodeTitle) >> ERROR_FILE
            seasonNumber = episodeSeason
        }
        episodeNumber = substr(fld[nflds-1], 2)
        sortkey = sprintf ("%s%02dE%03d", showtype, seasonNumber, episodeNumber)
        c2Num += 1
        outfile = "BBox-scrapes/c2-" longdate ".csv"
        printf ("c2\t%d\t%s\t%s\t%s\t%s\t%s\n",c2Num,sortkey,URL,showTitle,episodeTitle,Years) >> outfile
    } else if (URL ~ /Episode_[[:digit:]]*_[[:digit:]]*$/) {
        # /us/episode/Episode_5_26089
        revisedSeasons3 += 1
        seasonNumber = Years
        if (episodeSeason != "" && seasonNumber+0 != episodeSeason+0) {
            printf ("==> Fixed c3 season: %02d-%02d\t%s\t%s\n", \
                    seasonNumber, episodeSeason, shortURL, episodeTitle) >> ERROR_FILE
            seasonNumber = episodeSeason
        }
        episodeNumber = substr(fld[nflds-1], 1)
        sortkey = sprintf ("%s%02dE%03d", showtype, seasonNumber, episodeNumber)
        c3Num += 1
        outfile = "BBox-scrapes/c3-" longdate ".csv"
        printf ("c3\t%d\t%s\t%s\t%s\t%s\t%s\n",c3Num,sortkey,URL,showTitle,episodeTitle,Years) >> outfile
    } else {
        revisedSeasons4 += 1
        URL ~ /^\/us\/movie\// ? showtype = "M" : showtype = "E"
        # /us/episode/Orkneys_Stone_Age_Temple_7144
        # A History of Ancient Britain Special, Orkney's Stone Age Temple
        sortkey = sprintf ("%s%05d", showtype, fld[nflds])
        c4Num += 1
        outfile = "BBox-scrapes/c4-" longdate ".csv"
        printf ("c4\t%d\t%s\t%s\t%s\t%s\t%s\n",c4Num,sortkey,URL,showTitle,episodeTitle,Years) >> outfile
    }

    # Convert duration from minutes to HMS
    sub( / min/,"",Duration)
    secs = 0
    mins = Duration % 60
    hrs = int(Duration / 60)
    HMS = sprintf ("%02d:%02d:%02d", hrs, mins, secs)
    if (HMS == "00:00:00")
        HMS = ""

    # Special processing for some shows is needed in all getBBox*From-webscraper.awk scripts.
    # "Changed" message and counting revisedTitles are only in getBBoxProgramsFrom-webscraper.awk
    # so they are not repeated for each episode and each season.
    if (baseURL ~ /Maigret_15974$/) {
        showTitle = "Maigret (2016)"
    }
    if (baseURL ~ /Maigret_\(1992\)_15928$/) {
        showTitle = "Maigret (1992)"
    }
    if (baseURL ~ /Porridge_9509$/) {
        showTitle = "Porridge (1974-1977)"
    }
    if (baseURL ~ /Porridge_14747$/) {
        showTitle = "Porridge (2016-2017)"
    }

    # Get rid of redundant "Series #" or "Series #" from episodeTitle
    if (match (episodeTitle, /^Season [[:digit:]]*, |^Series [[:digit:]]*, /))
        episodeTitle = substr(episodeTitle,RLENGTH+1)

    # Get rid of initial/trailing quotes in showTitle
    # "BBC Three's ""Murdered By..."" Collection Trailer"
    if (showTitle ~ /^".*"$/) {
        revisedTitles += 1
        printf ("==> Fixed quoted title: www.britbox.com%s\n", URL) >> ERROR_FILE
        # printf ("    %s\n", showTitle) >> ERROR_FILE
        sub (/^"/,"",showTitle)
        sub (/"$/,"",showTitle)
        # printf ("    %s\n", showTitle) >> ERROR_FILE
    }

    # Non-existent fields in movies or episodes
    if (URL ~ /^\/us\/movie\//) {
        depth = "1"
        numSeasons = 1
        numEpisodes = 1
        fullTitle = showTitle
    } else {
        depth = "2"
        numSeasons = ""
        numEpisodes = ""
        fullTitle = showTitle ", " sortkey ", " episodeTitle
    }

    # Fix two consecutive double quotes in showTitle, but leave in fullTitle
    gsub ("\"\"","\"",showTitle)

    # Fix HEX quotes in Description
    gsub ("\xc2\x91","\"",Description)
    gsub ("\xc2\x92","\"",Description)

    # Create spreadsheet row in common format
    savedLine = sprintf \
        ("%s (%s) %s %s\t=HYPERLINK(\"https://www.britbox.com%s\";\"%s\"\)\t%s\t%s\t%s\t%s\t%s\t%s",\
         showTitle, depth, Years, sortkey, URL, fullTitle, numSeasons, numEpisodes, \
         HMS, Years, Rating, Description)

    # Make sure line doesn't start with a single quote so it sorts correctly in Open Office
    sub (/^'/,"",savedLine)

    print savedLine
    next
}

/\/us\/show\// {
    # Shouldn't get here
    badEpisodes += 1
    URL = $4
    nflds = split (URL,URLflds,"/")
    printf ("==> Upstream error in %s\n", FILENAME)  >> ERROR_FILE
    print "==> Found /us/show/ in episodes: " URLflds[nflds]  >> ERROR_FILE
}

END {
    printf ("In getBBoxEpisodesFrom-webscraper.awk\n") > "/dev/stderr"
    if (revisedTitles > 0 ) {
        revisedTitles == 1 ? field = "title" : field = "titles"
        printf ("    %2d %s revised in %s\n", revisedTitles, field, FILENAME) > "/dev/stderr"
    }
    if (revisedSeasons1 > 0 ) {
        revisedSeasons1 == 1 ? field = "season" : field = "seasons"
        printf ("    %3d c1 %s revised in %s\n", revisedSeasons1, field, FILENAME) > "/dev/stderr"
    }
    if (revisedSeasons2 > 0 ) {
        revisedSeasons2 == 1 ? field = "season" : field = "seasons"
        printf ("    %3d c2 %s revised in %s\n", revisedSeasons2, field, FILENAME) > "/dev/stderr"
    }
    if (revisedSeasons3 > 0 ) {
        revisedSeasons3 == 1 ? field = "season" : field = "seasons"
        printf ("    %3d c3 %s revised in %s\n", revisedSeasons3, field, FILENAME) > "/dev/stderr"
    }
    if (revisedSeasons4 > 0 ) {
        revisedSeasons4 == 1 ? field = "season" : field = "seasons"
        printf ("    %3d c4 %s revised in %s\n", revisedSeasons4, field, FILENAME) > "/dev/stderr"
    }
    if (badEpisodes > 0 ) {
        badEpisodes == 1 ? field = "URL" : field = "URLs"
        printf ("    %2d extra /show/ %s in %s\n", badEpisodes, field, FILENAME) > "/dev/stderr"
    }
}

# Print the processed "Episode" lines from a WebScraper csv file saved in tsv format

# INVOCATION:
#       awk -v EPISODE_INFO_FILE=$EPISODE_INFO_FILE -v ERROR_FILE=$ERROR_FILE \
#           -f getBBoxEpisodesFrom-webscraper.awk $EPISODES_SORTED_FILE >$EPISODES_SPREADSHEET_FILE

# Field numbers
#    1 web-scraper-start-url  2 SsnURL     3 SsnURL-href    4 URL        5 Program_Title
#    6 Episode_Title          7 Year       8 Duration       9 Rating    10 Description

BEGIN {
    FS="\t"
    OFS="\t"
    print "Sortkey\tTitle\tSeasons\tEpisodes\tDuration\tYear(s)\tRating\tDescription"
    # For debugging variations in seasons and episodes format
    str = "date +%y%m%d.%H%M%S"
    str | getline longdate
    close str
    for ( i = 1; i <= 4; i++ ) {
        outfile = "BBox-scrapes/c" i "-" longdate ".csv"
        print "Type\t#\tSortkey\tURL\tshowTitle\tepisodeTitle\tYear(s)" > outfile
    }
}

{
    for ( i = 1; i <= NF; i++ ) {
        if ($i == "null")
            $i = ""
    }
}

/\/us\/movie\/|\/us\/episode\// {
    baseURL = $1
    URL = $4
    showTitle = $5
    episodeTitle = $6
    Years = $7
    Duration = $8
    Rating = $9
    Description = $10
    showtype = "S"

    shortURL = URL
    episodeSeason = ""
    # Season 3, Episode 8
    if (match (episodeTitle, /^Season [[:digit:]]+|^Series [[:digit:]]+/))
        episodeSeason = substr(episodeTitle,8,RLENGTH-7)

    # Extract sortkey from URL
    nflds = split (URL,fld,"_")
    if (URL ~ /_S[[:digit:]]*_E[[:digit:]]*_[[:digit:]]*$/) {
        # /us/episode/35_Days_S3_E8_23851
        seasonNumber = substr(fld[nflds-2], 2)
        episodeNumber = substr(fld[nflds-1], 2)
        if (baseURL ~ /The_Edinburgh_Show_23924$/) {
            episodeSeason = Years
        }
        # Give precedence to season number in episodeTitle over season number in URL
        if (episodeSeason != "" && seasonNumber+0 != episodeSeason+0) {
            revisedSeasons1 += 1
            sub (/^\/us\/episode\//,"",shortURL)
            printf ("==> Fixed c1 season: %02d-%02d\t%s\t%s\n", \
                    seasonNumber, episodeSeason, shortURL, episodeTitle) >> ERROR_FILE
            seasonNumber = episodeSeason
        }
        sortkey = sprintf ("%s%02dE%03d", showtype, seasonNumber, episodeNumber)
        c1Num += 1
        outfile = "BBox-scrapes/c1-" longdate ".csv"
        printf ("c1\t%d\t%s\t%s\t%s\t%s\t%s\n",c1Num,sortkey,URL,showTitle,episodeTitle,Years) >> outfile
    } else if (URL ~ /_E[[:digit:]]*_[[:digit:]]*$/) {
        # /us/episode/35_Hours_E1_26129
        revisedSeasons2 += 1
        episodeSeason = Years
        if (episodeSeason != "" && seasonNumber+0 != episodeSeason+0) {
            printf ("==> Fixed c2 season: %02d-%02d\t%s\t%s\n", \
                    seasonNumber, episodeSeason, shortURL, episodeTitle) >> ERROR_FILE
            seasonNumber = episodeSeason
        }
        episodeNumber = substr(fld[nflds-1], 2)
        sortkey = sprintf ("%s%02dE%03d", showtype, seasonNumber, episodeNumber)
        c2Num += 1
        outfile = "BBox-scrapes/c2-" longdate ".csv"
        printf ("c2\t%d\t%s\t%s\t%s\t%s\t%s\n",c2Num,sortkey,URL,showTitle,episodeTitle,Years) >> outfile
    } else if (URL ~ /Episode_[[:digit:]]*_[[:digit:]]*$/) {
        # /us/episode/Episode_5_26089
        revisedSeasons3 += 1
        seasonNumber = "98"
        episodeNumber = substr(fld[nflds-1], 1)
        sortkey = sprintf ("%s%02dE%03d", showtype, seasonNumber, episodeNumber)
        c3Num += 1
        outfile = "BBox-scrapes/c3-" longdate ".csv"
        printf ("c3\t%d\t%s\t%s\t%s\t%s\t%s\n",c3Num,sortkey,URL,showTitle,episodeTitle,Years) >> outfile
    } else {
        revisedSeasons4 += 1
        URL ~ /^\/us\/movie\// ? showtype = "M" : showtype = "E"
        # /us/episode/Orkneys_Stone_Age_Temple_7144
        # A History of Ancient Britain Special, Orkney's Stone Age Temple
        sortkey = sprintf ("%s%05d", showtype, fld[nflds])
        c4Num += 1
        outfile = "BBox-scrapes/c4-" longdate ".csv"
        printf ("c4\t%d\t%s\t%s\t%s\t%s\t%s\n",c4Num,sortkey,URL,showTitle,episodeTitle,Years) >> outfile
    }

    # Convert duration from minutes to HMS
    sub( / min/,"",Duration)
    secs = 0
    mins = Duration % 60
    hrs = int(Duration / 60)
    HMS = sprintf ("%02d:%02d:%02d", hrs, mins, secs)
    if (HMS == "00:00:00")
        HMS = ""

    # Special processing for some shows is needed in all getBBox*From-webscraper.awk scripts.
    # "Changed" message and counting revisedTitles are only in getBBoxProgramsFrom-webscraper.awk
    # so they are not repeated for each episode and each season.
    if (baseURL ~ /Maigret_15974$/) {
        showTitle = "Maigret (2016)"
    }
    if (baseURL ~ /Maigret_\(1992\)_15928$/) {
        showTitle = "Maigret (1992)"
    }
    if (baseURL ~ /Porridge_9509$/) {
        showTitle = "Porridge (1974-1977)"
    }
    if (baseURL ~ /Porridge_14747$/) {
        showTitle = "Porridge (2016-2017)"
    }

    # Get rid of redundant "Series #" or "Series #" from episodeTitle
    if (match (episodeTitle, /^Season [[:digit:]]*, |^Series [[:digit:]]*, /))
        episodeTitle = substr(episodeTitle,RLENGTH+1)

    # Get rid of initial/trailing quotes in showTitle
    # "BBC Three's ""Murdered By..."" Collection Trailer"
    if (showTitle ~ /^".*"$/) {
        revisedTitles += 1
        printf ("==> Fixed quoted title: www.britbox.com%s\n", URL) >> ERROR_FILE
        # printf ("    %s\n", showTitle) >> ERROR_FILE
        sub (/^"/,"",showTitle)
        sub (/"$/,"",showTitle)
        # printf ("    %s\n", showTitle) >> ERROR_FILE
    }

    # Non-existent fields in movies or episodes
    if (URL ~ /^\/us\/movie\//) {
        depth = "1"
        numSeasons = 1
        numEpisodes = 1
        fullTitle = showTitle
    } else {
        depth = "2"
        numSeasons = ""
        numEpisodes = ""
        fullTitle = showTitle ", " sortkey ", " episodeTitle
    }

    # Fix two consecutive double quotes in showTitle, but leave in fullTitle
    gsub ("\"\"","\"",showTitle)

    # Fix HEX quotes in Description
    gsub ("\xc2\x91","\"",Description)
    gsub ("\xc2\x92","\"",Description)

    # Create spreadsheet row in common format
    savedLine = sprintf \
        ("%s (%s) %s %s\t=HYPERLINK(\"https://www.britbox.com%s\";\"%s\"\)\t%s\t%s\t%s\t%s\t%s\t%s",\
         showTitle, depth, Years, sortkey, URL, fullTitle, numSeasons, numEpisodes, \
         HMS, Years, Rating, Description)

    # Make sure line doesn't start with a single quote so it sorts correctly in Open Office
    sub (/^'/,"",savedLine)

    print savedLine
    next
}

/\/us\/show\// {
    # Shouldn't get here
    badEpisodes += 1
    URL = $4
    nflds = split (URL,URLflds,"/")
    printf ("==> Upstream error in %s\n", FILENAME)  >> ERROR_FILE
    print "==> Found /us/show/ in episodes: " URLflds[nflds]  >> ERROR_FILE
}

END {
    printf ("In getBBoxEpisodesFrom-webscraper.awk\n") > "/dev/stderr"
    if (revisedTitles > 0 ) {
        revisedTitles == 1 ? field = "title" : field = "titles"
        printf ("    %2d %s revised in %s\n", revisedTitles, field, FILENAME) > "/dev/stderr"
    }
    if (revisedSeasons1 > 0 ) {
        revisedSeasons1 == 1 ? field = "season" : field = "seasons"
        printf ("    %3d c1 %s revised in %s\n", revisedSeasons1, field, FILENAME) > "/dev/stderr"
    }
    if (revisedSeasons2 > 0 ) {
        revisedSeasons2 == 1 ? field = "season" : field = "seasons"
        printf ("    %3d c2 %s revised in %s\n", revisedSeasons2, field, FILENAME) > "/dev/stderr"
    }
    if (revisedSeasons3 > 0 ) {
        revisedSeasons3 == 1 ? field = "season" : field = "seasons"
        printf ("    %3d c3 %s revised in %s\n", revisedSeasons3, field, FILENAME) > "/dev/stderr"
    }
    if (revisedSeasons4 > 0 ) {
        revisedSeasons4 == 1 ? field = "season" : field = "seasons"
        printf ("    %3d c4 %s revised in %s\n", revisedSeasons4, field, FILENAME) > "/dev/stderr"
    }
    if (badEpisodes > 0 ) {
        badEpisodes == 1 ? field = "URL" : field = "URLs"
        printf ("    %2d extra /show/ %s in %s\n", badEpisodes, field, FILENAME) > "/dev/stderr"
    }
}


ahrf.awk: allow backticks at the beginning of the word

#!/usr/bin/awk -f
# Script by Ypnose - http://ywstd.fr

BEGIN { FS = "\n"; RS = "" }

{
	# Common shell symbols to HTML
	# Two backslashes for nawk(1) and OpenBSD awk(1)
	gsub(/\&/,"\\&")
	gsub(/</,"\\<")
	gsub(/>/,"\\>")
}

# h1, h2, h3, h4, h5, h6
/^[\t ]*:/ {
	# Count ':' and match the valid "level"
	match($0,":+")
	cnt = RLENGTH
	gsub(/^[\t ]*:+[\t ]*|[\t ]*:+[\t ]*$/,"")
	# Create the anchor
	anc = tolower($0)
	gsub(/ +/,"-",anc)
	# length($0) would also work
	if (cnt <= 6 && $0 != "")
		printf("<h%d id=\"%s\">%s</h%d>\n", cnt, anc, $0, cnt)
	next
}

# Paragraph
/^[A-Za-z0-9_("`]+/ {
	printf("
")
	for (p=1; p<=NF; p++) {
		# Line break
		gsub(/ +$/,"
\n",$p)
		x = split($p,word," ")
		for (w=1; w<=x; w++) {
			if (word[w] ~ /^``/) {
				split(word[w],code,"``")
				printf("%s%s%s", code[1], code[2], code[3])
			}
			else
				printf("%s", word[w])
			# If EOL is not reached, add a space
			if (w != x)
				printf(" ")
		}
		# If it's the last paragraph line, close the paragraph
		if (p == NF)
			printf("
")
		printf("\n")
	}
	next
}

# Code
/^====+/ {
	if (NF > 2 && $NF ~ /====+/) {
		gsub(/^====+[\t ]*\n|\n[\t ]*====+$/,"")
		printf("
")
		for (c=1; c<NF; c++) {
			gsub(/^ +$/,"",$c)
			printf("%s\n", $c)
		}
		printf("%s
\n", $NF)
	}
	next
}

# Tables
/^%%%%+/ {
	if (NF > 2 && $NF ~ /%%%%+/) {
		gsub(/^%%%%+[\t ]*\n|\n[\t ]*%%%%+$/,"")
		printf("
\n")
		for (t=1; t<=NF; t++) {
			printf("\t
\n")
			y = split($t,column,"%%%")
			for (c=1; c<=y; c++) {
				gsub(/^[\t ]+|[\t ]+$/,"",column[c])
				printf("\t%s	\n", column[c])
			}
			printf("\t
\n")
		}
		printf("
\n")
	}
}

# List
/^[\t ]*\* +/ {
	printf("
\n")
	for (l=1; l<=NF; l++) {
		gsub(/^[\t ]*/,"",$l)
		if ($l ~ /\* +/) {
			# Only match the text
			match($l,"\\* +")
			str = substr($l,RSTART+RLENGTH)
			printf("\t
%s
\n", str)
		}
	}
	printf("
\n")
	next
}

# End links
/^[\t ]*\[[01]/ {
	printf("
\n")
	for (u=1; u<=NF; u++) {
		gsub(/^[\t ]*/,"",$u)
		if (match($u,"\\[[0-9]+\\]")) {
			# RSTART can be replaced by 1, because we already removed
			# useless tabs and/or spaces
			num = substr($u,RSTART,RLENGTH)
			url = substr($u,RSTART+RLENGTH+1)
			# Do not print the entire link if chars > 100
			if (length(url) > 100)
				printf("\t
%s %.100s…
\n", num, url, url)
			else
				printf("\t
%s %s
\n", num, url, url)
		}
	}
	printf("
\n")
	next
}

#!/usr/bin/awk -f
# Script by Ypnose - http://ywstd.fr

BEGIN { FS = "\n"; RS = "" }

{
	# Common shell symbols to HTML
	# Two backslashes for nawk(1) and OpenBSD awk(1)
	gsub(/\&/,"\\&")
	gsub(/</,"\\<")
	gsub(/>/,"\\>")
}

# h1, h2, h3, h4, h5, h6
/^[\t ]*:/ {
	# Count ':' and match the valid "level"
	match($0,":+")
	cnt = RLENGTH
	gsub(/^[\t ]*:+[\t ]*|[\t ]*:+[\t ]*$/,"")
	# Create the anchor
	anc = tolower($0)
	gsub(/ +/,"-",anc)
	# length($0) would also work
	if (cnt <= 6 && $0 != "")
		printf("<h%d id=\"%s\">%s</h%d>\n", cnt, anc, $0, cnt)
	next
}

# Paragraph
/^[A-Za-z0-9_("`]+/ {
	printf("
")
	for (p=1; p<=NF; p++) {
		# Line break
		gsub(/ +$/,"
\n",$p)
		x = split($p,word," ")
		for (w=1; w<=x; w++) {
			if (word[w] ~ /``/) {
				split(word[w],code,"``")
				printf("%s%s%s", code[1], code[2], code[3])
			}
			else
				printf("%s", word[w])
			# If EOL is not reached, add a space
			if (w != x)
				printf(" ")
		}
		# If it's the last paragraph line, close the paragraph
		if (p == NF)
			printf("
")
		printf("\n")
	}
	next
}

# Code
/^====+/ {
	if (NF > 2 && $NF ~ /====+/) {
		gsub(/^====+[\t ]*\n|\n[\t ]*====+$/,"")
		printf("
")
		for (c=1; c<NF; c++) {
			gsub(/^ +$/,"",$c)
			printf("%s\n", $c)
		}
		printf("%s
\n", $NF)
	}
	next
}

# Tables
/^%%%%+/ {
	if (NF > 2 && $NF ~ /%%%%+/) {
		gsub(/^%%%%+[\t ]*\n|\n[\t ]*%%%%+$/,"")
		printf("
\n")
		for (t=1; t<=NF; t++) {
			printf("\t
\n")
			y = split($t,column,"%%%")
			for (c=1; c<=y; c++) {
				gsub(/^[\t ]+|[\t ]+$/,"",column[c])
				printf("\t%s	\n", column[c])
			}
			printf("\t
\n")
		}
		printf("
\n")
	}
}

# List
/^[\t ]*\* +/ {
	printf("
\n")
	for (l=1; l<=NF; l++) {
		gsub(/^[\t ]*/,"",$l)
		if ($l ~ /\* +/) {
			# Only match the text
			match($l,"\\* +")
			str = substr($l,RSTART+RLENGTH)
			printf("\t
%s
\n", str)
		}
	}
	printf("
\n")
	next
}

# End links
/^[\t ]*\[[01]/ {
	printf("
\n")
	for (u=1; u<=NF; u++) {
		gsub(/^[\t ]*/,"",$u)
		if (match($u,"\\[[0-9]+\\]")) {
			# RSTART can be replaced by 1, because we already removed
			# useless tabs and/or spaces
			num = substr($u,RSTART,RLENGTH)
			url = substr($u,RSTART+RLENGTH+1)
			# Do not print the entire link if chars > 100
			if (length(url) > 100)
				printf("\t
%s %.100s…
\n", num, url, url)
			else
				printf("\t
%s %s
\n", num, url, url)
		}
	}
	printf("
\n")
	next
}


vector extraction script fixed

vector extraction script fixed