-discontinuity mode

-discontinuity mode

BEGIN{
    if(!maxInterval)
        maxInterval=60
    if(!maxChunkDuration)
        maxChunkDuration=12000
    if(!minChunkDuration)
        minChunkDuration=1000
    state = "waitChunk"
    if(!verbose)
        verbose=1
}

function addStats(caption,data){
    cnts[caption] = cnts[caption] + 1
    sums[caption] = sums[caption] + data
    sums2[caption] = sums2[caption] + data*data
}

function printStats(caption){
    cnt = cnts[caption]
    if(cnt){
        sum = sums[caption]
        sum2 = sums2[caption]
        stddev = 0
        if((cnt > 1)){
         stddev = sqrt( (sum2*cnt -sum*sum) / (cnt*(cnt-1)))
        }
        printf "%s avg request interval: %.2f stddev: %.2f #: %d\n", caption,sum/cnt,stddev,cnt
    } else {
        print "couldn't find stats for "caption
    }
}

$0 ~ /\[debug\]/ && $0 ~ /GET \/hls\/(.*)\/playlist.json\/seg/ {
    split($10,b,"-");
    lastChunkPath=$10
    if(verbose){
        print $2 " "lastChunkPath;
    }

    if(length(b) == 6){
        lastChunkId = b[4]
    } else {
        lastChunkId =  b[2]
    }
    if(lastChunk && lastChunk+1 != lastChunkId){
        print $2" "lastChunkPath" error: expected chunk "lastChunk+1" got: "lastChunkId
        delete __lastDTS[0]
    }
    lastChunk=lastChunkId;
    split($2,a,":");
    time=a[3]+a[2]*60+a[1]*3600;
    if(lastTime){
        diff=time-lastTime
        if(diff>maxInterval){
            print $2" "lastChunkPath" error: requested chunk after "diff" sec."
        }
        if(diff>0){
            addStats("chunkInterval",diff)
        }
    }
    lastTime = time
    state = "checkDTS"
}

verbose && state == "checkDTS" && $0 ~ /parsed clip source/ {
    print $2" "$11" "$12" "$13
}

state == "checkDTS" && $0 ~ /first frame dts/ {
    state = "waitChunk"
    if( __lastDTS[0]){
        chunkDuration = $11 -  __lastDTS[0]

        addStats("chunkDuration",chunkDuration)
        if(chunkDuration > maxChunkDuration || chunkDuration < minChunkDuration){
            print $2" "lastChunkPath" bad chunk duration "chunkDuration
        }
    }
     __lastDTS[0] = $11
}

$0 ~ /media_set_parse_json: produced segment/ {
    tmp1 = $9
    tmp2=$11
    tmp3=$13
    if(segment_index){
        if(segment_index == tmp1 - 1){
            if(segment_start_time+segment_duration != tmp2){
                printf (" chunk %d adjucent chunks  differ: diff: %d prev={ %d  %d}  cur={%d %d}\n",tmp1,
                (tmp2-segment_start_time+segment_duration),
                segment_start_time,
                segment_duration,
                tmp2,
                tmp3)
            }
        } else {
            print "segment discontinuity: cur: "tmp1" prev: "segment_index
        }
    }
    segment_index = tmp1
    segment_start_time=tmp2
    segment_duration=tmp3
}

END {
    printStats("chunkInterval")
    printStats("chunkDuration")
}

BEGIN{
    if(!maxInterval)
        maxInterval=60
    if(!maxChunkDuration)
        maxChunkDuration=12000
    if(!minChunkDuration)
        minChunkDuration=1000
    state = "waitChunk"
    if(!verbose)
        verbose=1
}

function addStats(caption,data){
    cnts[caption] = cnts[caption] + 1
    sums[caption] = sums[caption] + data
    sums2[caption] = sums2[caption] + data*data
}

function printStats(caption){
    cnt = cnts[caption]
    if(cnt){
        sum = sums[caption]
        sum2 = sums2[caption]
        stddev = 0
        if((cnt > 1)){
         stddev = sqrt( (sum2*cnt -sum*sum) / (cnt*(cnt-1)))
        }
        printf "%s avg request interval: %.2f stddev: %.2f #: %d\n", caption,sum/cnt,stddev,cnt
    } else {
        print "couldn't find stats for "caption
    }
}

$0 ~ /\[debug\]/ && $0 ~ /GET \/hls\/(.*)\/playlist.json\/seg/ {
    split($10,b,"-");
    lastChunkPath=$10
    if(verbose){
        print $2 " "lastChunkPath;
    }

    if(length(b) == 6){
        lastChunkId = b[4]
    } else {
        lastChunkId =  b[2]
    }
    if(lastChunk && lastChunk+1 != lastChunkId){
        print $2" "lastChunkPath" error: expected chunk "lastChunk+1" got: "lastChunkId
        delete __lastDTS[0]
    }
    lastChunk=lastChunkId;
    split($2,a,":");
    time=a[3]+a[2]*60+a[1]*3600;
    if(lastTime){
        diff=time-lastTime
        if(diff>maxInterval){
            print $2" "lastChunkPath" error: requested chunk after "diff" sec."
        }
        if(diff>0){
            addStats("chunkInterval",diff)
        }
    }
    lastTime = time
    state = "checkDTS"
}

verbose && state == "checkDTS" && $0 ~ /parsed clip source/ {
    print $2" "$11" "$12" "$13
}

state == "checkDTS" && $0 ~ /first frame dts/ {
    state = "waitChunk"
    if( __lastDTS[0]){
        chunkDuration = $11 -  __lastDTS[0]

        addStats("chunkDuration",chunkDuration)
        if(chunkDuration > maxChunkDuration || chunkDuration < minChunkDuration){
            print $2" "lastChunkPath" bad chunk duration "chunkDuration
        }
    }
     __lastDTS[0] = $11
}

$0 ~ /media_set_parse_json: produced segment/ {
    tmp1 = $9
    tmp2=$11
    tmp3=$13
    if(segment_index){
        if(segment_index == tmp1 - 1){
            if(segment_start_time+segment_duration != tmp2){
                printf (" chunk %d adjucent chunks  differ: diff: %d prev={ %d  %d}  cur={%d %d}",tmp1,
                (tmp2-segment_start_time+segment_duration),
                segment_start_time,
                segment_duration,
                tmp2,
                tmp3)
            }
        } else {
            print "segment discontinuity: cur: "tmp1" prev: "segment_index
        }
    }
    segment_index = tmp1
    segment_start_time=tmp2
    segment_duration=tmp3
}

END {
    printStats("chunkInterval")
    printStats("chunkDuration")
}


Enable the generated fzn-python file to take different restart parameters.

# 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 (output[e]!=1 || e == "objective") {
			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 '----------'";
	print "if solver.is_unsat():"
	print "    print '=====UNSATISFIABLE====='"
	if (objective){
		print "elif solver.is_opt():"
		print "    print '=========='"
	} else {
		print "elif solver.is_sat():"
		print "    print '=========='"
	}
        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 (output[e]!=1 || e == "objective") {
			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)])";
	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 "    solver.solveAndRestart(GEOMETRIC, 256, 1.3)";
	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 '----------'";
	print "if solver.is_unsat():"
	print "    print '=====UNSATISFIABLE====='"
	if (objective){
		print "elif solver.is_opt():"
		print "    print '=========='"
	} else {
		print "elif solver.is_sat():"
		print "    print '=========='"
	}
        print "else:"
	print "    print '=====UNKNOWN====='"
	print "print '% SolveTime', solver.getTime()";
	print "print '% Nodes', solver.getNodes()";
	if (objective) print "if solver.is_sat(): print '% Objective', (solver.getOptimum() if param['solver'] == 'Toulbar2' else " objective ".get_value())";
	}
}


fix stringize.awk to work with gawk-4.0.0 and gawk-3.1.8 - fix suggested by arnold@skeeve.com

#
# /*************************************************************************
# * Copyright (c) 2011 AT&T Intellectual Property
# * All rights reserved. This program and the accompanying materials
# * are made available under the terms of the Eclipse Public License v1.0
# * which accompanies this distribution, and is available at
# * http://www.eclipse.org/legal/epl-v10.html
# *
# * Contributors: See CVS logs. Details at http://www.graphviz.org/
# *************************************************************************/

BEGIN	{ s = ARGV[1]; gsub (".*/", "", s); gsub("\\.","_",s); printf("const char *%s[] = {\n",s); }
/^#/	{ print $0; next; }
		{ gsub("\\\\","&&",$0); printf("\"%s\",\n",$0); }
END		{ printf("(char*)0 };\n"); }

#
# /*************************************************************************
# * Copyright (c) 2011 AT&T Intellectual Property
# * All rights reserved. This program and the accompanying materials
# * are made available under the terms of the Eclipse Public License v1.0
# * which accompanies this distribution, and is available at
# * http://www.eclipse.org/legal/epl-v10.html
# *
# * Contributors: See CVS logs. Details at http://www.graphviz.org/
# *************************************************************************/

BEGIN	{ s = ARGV[1]; gsub (".*/", "", s); gsub("\\.","_",s); printf("const char *%s[] = {\n",s); }
/^#/	{ print $0; next; }
		{ gsub("\\\\","\\\\",$0); printf("\"%s\",\n",$0); }
END		{ printf("(char*)0 };\n"); }


Put decent prefixes in the symbolic constants for GIO IDs in the generated files, for them to become useful.

#! /usr/bin/awk -f
#	$OpenBSD: devlist2h.awk,v 1.2 2012/04/18 17:18:10 miod Exp $
#	$NetBSD: devlist2h.awk,v 1.5 2008/05/02 18:11:05 martin Exp $
#
# Copyright (c) 1998 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Christos Zoulas.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Copyright (c) 1995, 1996 Christopher G. Demetriou
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#      This product includes software developed by Christopher G. Demetriou.
#      This product includes software developed by Christos Zoulas
# 4. The name of the author(s) may not be used to endorse or promote products
#    derived from this software without specific prior written permission
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
function collectline(_f, _line) {
	_oparen = 0
	_line = ""
	while (_f <= NF) {
		if ($_f == "#") {
			_line = _line "("
			_oparen = 1
			_f++
			continue
		}
		if (_oparen) {
			_line = _line $_f
			if (_f < NF)
				_line = _line " "
			_f++
			continue
		}
		_line = _line $_f
		if (_f < NF)
			_line = _line " "
		_f++
	}
	if (_oparen)
		_line = _line ")"
	return _line
}
BEGIN {
	nproducts = nvendors = blanklines = 0
	dfile="giodevs_data.h"
	hfile="giodevs.h"
	line=""
}
NR == 1 {
	VERSION = $0
	gsub("\\$", "", VERSION)

	printf("/*\n") > hfile
	printf(" * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.\n") \
	    > hfile
	printf(" *\n") > hfile
	printf(" * generated from:\n") > hfile
	printf(" *\t%s\n", VERSION) > hfile
	printf(" */\n\n") > hfile

	printf("/*\n") > dfile
	printf(" * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.\n") \
	    > dfile
	printf(" *\n") > dfile
	printf(" * generated from:\n") > dfile
	printf(" *\t%s\n", VERSION) > dfile
	printf(" */\n\n") > dfile

	next
}
NF > 0 && $1 == "product" {
	nproducts++

	products[nproducts, 1] = $2;
	products[nproducts, 2] = $3
	products[nproducts, 3] = collectline(4, line)

	next
}
{
	if ($0 == "")
		blanklines++
	if (blanklines < 2)
		print $0 > dfile
}
END {
	# print out the match tables

	printf("\n") > dfile

	printf("struct gio_knowndev {\n") > dfile
	printf("\tint productid;\n") > dfile
	printf("\tconst char *product;\n") > dfile
	printf("};\n") > dfile
	printf("\nstruct gio_knowndev gio_knowndevs[] = {\n") > dfile

	printf("\n") > hfile
	for (i = 1; i <= nproducts; i++) {
		printf("#define GIO_PRODUCT_%s\t%s\t/* %s */\n",
		    products[i, 1], products[i,2], products[i, 3]) > hfile

		printf("\t{ GIO_PRODUCT_%s, \"%s\" },\n",
		    products[i, 1], products[i, 3]) > dfile
	}
	printf("\t{ 0, NULL }\n") > dfile
	printf("};\n") > dfile
	close(dfile)
	close(hfile)
}

#! /usr/bin/awk -f
#	$OpenBSD: devlist2h.awk,v 1.1 2012/03/28 20:44:23 miod Exp $
#	$NetBSD: devlist2h.awk,v 1.5 2008/05/02 18:11:05 martin Exp $
#
# Copyright (c) 1998 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Christos Zoulas.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Copyright (c) 1995, 1996 Christopher G. Demetriou
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#      This product includes software developed by Christopher G. Demetriou.
#      This product includes software developed by Christos Zoulas
# 4. The name of the author(s) may not be used to endorse or promote products
#    derived from this software without specific prior written permission
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
function collectline(_f, _line) {
	_oparen = 0
	_line = ""
	while (_f <= NF) {
		if ($_f == "#") {
			_line = _line "("
			_oparen = 1
			_f++
			continue
		}
		if (_oparen) {
			_line = _line $_f
			if (_f < NF)
				_line = _line " "
			_f++
			continue
		}
		_line = _line $_f
		if (_f < NF)
			_line = _line " "
		_f++
	}
	if (_oparen)
		_line = _line ")"
	return _line
}
BEGIN {
	nproducts = nvendors = blanklines = 0
	dfile="giodevs_data.h"
	hfile="giodevs.h"
	line=""
}
NR == 1 {
	VERSION = $0
	gsub("\\$", "", VERSION)

	printf("/*\n") > hfile
	printf(" * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.\n") \
	    > hfile
	printf(" *\n") > hfile
	printf(" * generated from:\n") > hfile
	printf(" *\t%s\n", VERSION) > hfile
	printf(" */\n\n") > hfile

	printf("/*\n") > dfile
	printf(" * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.\n") \
	    > dfile
	printf(" *\n") > dfile
	printf(" * generated from:\n") > dfile
	printf(" *\t%s\n", VERSION) > dfile
	printf(" */\n\n") > dfile

	next
}
NF > 0 && $1 == "product" {
	nproducts++

	products[nproducts, 1] = $2;
	products[nproducts, 2] = $3
	products[nproducts, 3] = collectline(4, line)

	next
}
{
	if ($0 == "")
		blanklines++
	if (blanklines < 2)
		print $0 > dfile
}
END {
	# print out the match tables

	printf("\n") > dfile

	printf("struct gio_knowndev {\n") > dfile
	printf("\tint productid;\n") > dfile
	printf("\tconst char *product;\n") > dfile
	printf("};\n") > dfile
	printf("\nstruct gio_knowndev gio_knowndevs[] = {\n") > dfile

	printf("\n") > hfile
	for (i = 1; i <= nproducts; i++) {
		printf("#define %s\t%s\t/* %s */\n", products[i, 1], products[i,2], products[i, 3]) > hfile

		printf("\t{ %s, \"%s\" },\n",
		    products[i, 2], products[i, 3]) > dfile
	}
	printf("\t{ 0, NULL }\n") > dfile
	printf("};\n") > dfile
	close(dfile)
	close(hfile)
}


Fix a problem with recent wireshark versions.  Those seem to add
a column after the frame number.

git-svn-id: 392d0e5ce652024192c571322d40dcc23d6d83b0@120 8a65f31f-a56f-4bd6-98e8-2755f64920ec

BEGIN{
  first=1;
}
#/^Frame [0-9]+/ {
#  filename = destDir "/frames/Frame" $2 ".html";
#  printf "\n" >filename;
#  printf "
\n" >filename;
#  discard = 0;
#}
/^Frame [0-9]+: (.*)/ {
  # New frame, closing
 and html> from previous frame before compute new filename
  if (first==0){
    print "
" >filename;
  }
  else{
    first=0;
  }
  nbr = $2
  sub (":", "", nbr)
  filename = destDir "/frames/Frame" nbr ".html";
  printf "\n" >filename;
  printf "
\n" >filename;
  print $0 >filename;
  # Print time
  getline
  gsub("^ *", "")
  print $0 >filename;
  discard = 1;
}
/^Internet Protocol,/ {
  print $0 >filename;
  discard = 1;
}
/^Internet Protocol$/ {
  discard = 0;
}
/^User Datagram Protocol,/ {
  print $0 >filename;
  discard = 1;
}
/^User Datagram Protocol$/ {
  discard = 0;
}
/^Transmission Control Protocol,/ {
  print $0 >filename;
  discard = 1;
}
/^Transmission Control Protocol$/ {
  discard = 0;
}
/^Internet Control Message Protocol/ {
  discard = 0;
}
/^Session Initiation Protocol/ {
  discard = 0;
}
/^Diameter Protocol/ {
  discard = 0;
}
/^WebSocket Protocol/ {
  discard = 0;
}
/^Hypertext Transfer Protocol/ {
  discard = 0;
}
/^Call Specification Language/ {
  discard = 0;
}
{
  if (discard==0)
    {

      gsub("&","\\&");
      gsub(">","\\>");
      gsub("<","\\<");
      print $0 > filename;
    }
}
END {
  print "
" >filename
}

BEGIN{
  first=1;
}
#/^Frame [0-9]+/ {
#  filename = destDir "/frames/Frame" $2 ".html";
#  printf "\n" >filename;
#  printf "
\n" >filename;
#  discard = 0;
#}
/^Frame [0-9]+ (.*)/ {
  # New frame, closing
 and html> from previous frame before compute new filename
  if (first==0){
    print "
" >filename;
  }
  else{
    first=0;
  }
  filename = destDir "/frames/Frame" $2 ".html";
  printf "\n" >filename;
  printf "
\n" >filename;
  print $0 >filename;
  # Print time
  getline
  gsub("^ *", "")
  print $0 >filename;
  discard = 1;
}
/^Internet Protocol,/ {
  print $0 >filename;
  discard = 1;
}
/^Internet Protocol$/ {
  discard = 0;
}
/^User Datagram Protocol,/ {
  print $0 >filename;
  discard = 1;
}
/^User Datagram Protocol$/ {
  discard = 0;
}
/^Transmission Control Protocol,/ {
  print $0 >filename;
  discard = 1;
}
/^Transmission Control Protocol$/ {
  discard = 0;
}
/^Internet Control Message Protocol/ {
  discard = 0;
}
/^Session Initiation Protocol/ {
  discard = 0;
}
/^Diameter Protocol/ {
  discard = 0;
}
/^WebSocket Protocol/ {
  discard = 0;
}
/^Hypertext Transfer Protocol/ {
  discard = 0;
}
/^Call Specification Language/ {
  discard = 0;
}
{
  if (discard==0)
    {

      gsub("&","\\&");
      gsub(">","\\>");
      gsub("<","\\<");
      print $0 > filename;
    }
}
END {
  print "
" >filename
}


Substitute "[:space:]" with the character constants it expands to.
This was a silent 'failure' when using Bell-Labs awk.

Submitted by:	David Wolfskill <david@catwhisker.org>

#!/usr/bin/awk -f
#
# Convert forth source files to a giant C string
#
# Joe Abley <jabley@patho.gen.nz>, 12 January 1999
#
# 02-oct-1999:  Cleaned up awk slightly; added some additional logic
#               suggested by dcs to compress the stored forth program.
#
# $FreeBSD$

BEGIN \
{
  printf "/***************************************************************\n";
  printf "** s o f t c o r e . c\n";
  printf "** Forth Inspired Command Language -\n";
  printf "** Words from CORE set written in FICL\n";
  printf "** Author: John Sadler (john_sadler@alum.mit.edu)\n";
  printf "** Created: 27 December 1997\n";
  printf "** Last update: %s\n", datestamp;
  printf "***************************************************************/\n";
  printf "\n/*\n";
  printf "** This file contains definitions that are compiled into the\n";
  printf "** system dictionary by the first virtual machine to be created.\n";
  printf "** Created automagically by ficl/softwords/softcore.awk\n";
  printf "*/\n";
  printf "\n#include \"ficl.h\"\n";
  printf "\nstatic char softWords[] =\n";

  commenting = 0;
}

# some general early substitutions
{
  gsub(/\t/, "    ");			# replace each tab with 4 spaces
  gsub(/\"/, "\\\"");			# escape quotes
  gsub(/\\[ 	]+$/, "");		# toss empty comments
}

# strip out empty lines
/^ *$/ \
{
  next;
}

# emit / ** lines as multi-line C comments
/^\\[ 	]\*\*/ \
{
  sub(/^\\[ 	]/, "");
  if (commenting == 0) printf "/*\n";
  printf "%s\n", $0;
  commenting = 1;
  next;
}

# strip blank lines
/^[ 	]*$/ \
{
  next;
}

# function to close a comment, used later
function end_comments()
{
  commenting = 0;
  printf "*/\n";
}

# pass commented preprocessor directives
/^\\[ 	]#/ \
{
  if (commenting) end_comments();
  sub(/^\\[ 	]/, "");
  printf "%s\n", $0;
  next;
}

# toss all other full-line \ comments
/^\\/ \
{
  if (commenting) end_comments();
  next;
}

# lop off trailing \ comments
/\\[ 	]+/ \
{
  sub(/\\[ 	]+.*$/, "");
}

# expunge ( ) comments
/[ 	]+\([ 	][^)]*\)/ \
{
  sub(/[ 	]+\([ 	][^)]*\)/, "");
}

# remove leading spaces
/^[ 	]+/ \
{
  sub(/^[ 	]+/, "");
}

# removing trailing spaces
/[ 	]+$/ \
{
  sub(/[ 	]+$/, "");
}

# strip out empty lines again (preceding rules may have generated some)
/^[ 	]*$/ \
{
  if (commenting) end_comments();
  next;
}

# emit all other lines as quoted string fragments
{
  if (commenting) end_comments();

  printf "    \"%s \"\n", $0;
  next;
}

END \
{
  if (commenting) end_comments();
  printf "    \"quit \";\n";
  printf "\n\nvoid ficlCompileSoftCore(FICL_SYSTEM *pSys)\n";
  printf "{\n";
  printf "    FICL_VM *pVM = pSys->vmList;\n";
  printf "    int ret = sizeof (softWords);\n";
  printf "	  assert(pVM);\n";
  printf "\n"
  printf "    ret = ficlExec(pVM, softWords);\n";
  printf "    if (ret == VM_ERREXIT)\n";
  printf "        assert(FALSE);\n";
  printf "    return;\n";
  printf "}\n";
}

#!/usr/bin/awk -f
#
# Convert forth source files to a giant C string
#
# Joe Abley <jabley@patho.gen.nz>, 12 January 1999
#
# 02-oct-1999:  Cleaned up awk slightly; added some additional logic
#               suggested by dcs to compress the stored forth program.
#
# Note! This script uses strftime() which is a gawk-ism, and the
# POSIX [[:space:]] character class.
#
# $FreeBSD$

BEGIN \
{
  printf "/***************************************************************\n";
  printf "** s o f t c o r e . c\n";
  printf "** Forth Inspired Command Language -\n";
  printf "** Words from CORE set written in FICL\n";
  printf "** Author: John Sadler (john_sadler@alum.mit.edu)\n";
  printf "** Created: 27 December 1997\n";
  printf "** Last update: %s\n", datestamp;
  printf "***************************************************************/\n";
  printf "\n/*\n";
  printf "** This file contains definitions that are compiled into the\n";
  printf "** system dictionary by the first virtual machine to be created.\n";
  printf "** Created automagically by ficl/softwords/softcore.awk\n";
  printf "*/\n";
  printf "\n#include \"ficl.h\"\n";
  printf "\nstatic char softWords[] =\n";

  commenting = 0;
}

# some general early substitutions
{
  gsub(/\t/, "    ");			# replace each tab with 4 spaces
  gsub(/\"/, "\\\"");			# escape quotes
  gsub(/\\[[:space:]]+$/, "");		# toss empty comments
}

# strip out empty lines
/^ *$/ \
{
  next;
}

# emit / ** lines as multi-line C comments
/^\\[[:space:]]\*\*/ \
{
  sub(/^\\[[:space:]]/, "");
  if (commenting == 0) printf "/*\n";
  printf "%s\n", $0;
  commenting = 1;
  next;
}

# strip blank lines
/^[[:space:]]*$/ \
{
  next;
}

# function to close a comment, used later
function end_comments()
{
  commenting = 0;
  printf "*/\n";
}

# pass commented preprocessor directives
/^\\[[:space:]]#/ \
{
  if (commenting) end_comments();
  sub(/^\\[[:space:]]/, "");
  printf "%s\n", $0;
  next;
}

# toss all other full-line \ comments
/^\\/ \
{
  if (commenting) end_comments();
  next;
}

# lop off trailing \ comments
/\\[[:space:]]+/ \
{
  sub(/\\[[:space:]]+.*$/, "");
}

# expunge ( ) comments
/[[:space:]]+\([[:space:]][^)]*\)/ \
{
  sub(/[[:space:]]+\([[:space:]][^)]*\)/, "");
}

# remove leading spaces
/^[[:space:]]+/ \
{
  sub(/^[[:space:]]+/, "");
}

# removing trailing spaces
/[[:space:]]+$/ \
{
  sub(/[[:space:]]+$/, "");
}

# strip out empty lines again (preceding rules may have generated some)
/^[[:space:]]*$/ \
{
  if (commenting) end_comments();
  next;
}

# emit all other lines as quoted string fragments
{
  if (commenting) end_comments();

  printf "    \"%s \"\n", $0;
  next;
}

END \
{
  if (commenting) end_comments();
  printf "    \"quit \";\n";
  printf "\n\nvoid ficlCompileSoftCore(FICL_SYSTEM *pSys)\n";
  printf "{\n";
  printf "    FICL_VM *pVM = pSys->vmList;\n";
  printf "    int ret = sizeof (softWords);\n";
  printf "	  assert(pVM);\n";
  printf "\n"
  printf "    ret = ficlExec(pVM, softWords);\n";
  printf "    if (ret == VM_ERREXIT)\n";
  printf "        assert(FALSE);\n";
  printf "    return;\n";
  printf "}\n";
}


Fix world-breaking bug, add $FreeBSD$ tag.

This happened to be my first "for real" broken world. I had broken
it once before, but nobody noticed, so it didn't count.

So, how do I get the "I broke world and all I got was the lousy t-shirt"
t-shirt?

#!/usr/bin/awk -f
# Convert forth source files to a giant C string
# Joe Abley <jabley@patho.gen.nz>, 12 January 1999
# $FreeBSD$

BEGIN \
{
  printf "/***************************************************************\n";
  printf "** s o f t c o r e . c\n";
  printf "** Forth Inspired Command Language -\n";
  printf "** Words from CORE set written in FICL\n";
  printf "** Author: John Sadler (john_sadler@alum.mit.edu)\n";
  printf "** Created: 27 December 1997\n";
  printf "** Last update: %s\n", strftime();
  printf "***************************************************************/\n";
  printf "\n/*\n";
  printf "** This file contains definitions that are compiled into the\n";
  printf "** system dictionary by the first virtual machine to be created.\n";
  printf "** Created automagically by ficl/softwords/softcore.awk\n";
  printf "*/\n";
  printf "\n#include \"ficl.h\"\n";
  printf "\nstatic char softWords[] =\n";

  commenting = 0;
}

# some general early substitutions
{
  gsub("\t", "    ");			# replace each tab with 4 spaces
  gsub("\"", "\\\"");			# escape quotes
  gsub("\\\\[[:space:]]+$", "");	# toss empty comments
}

# strip out empty lines
/^ *$/ \
{
  next;
}

# emit / ** lines as multi-line C comments
/^\\[[:space:]]\*\*/ && (commenting == 0) \
{
  sub("^\\\\[[:space:]]", "");
  printf "/*\n%s\n", $0;
  commenting = 1;
  next;
}

/^\\[[:space:]]\*\*/ \
{
  sub("^\\\\[[:space:]]", "");
  printf "%s\n", $0;
  next;
}

# function to close a comment, used later
function end_comments()
{
  commenting = 0;
  printf "*/\n";
}

# pass commented preprocessor directives
/^\\[[:space:]]#/ \
{
  if (commenting) end_comments();
  sub("^\\\\[[:space:]]", "");
  printf "%s\n", $0;
  next;
}

# toss all other full-line comments
/^\\/ \
{
  if (commenting) end_comments();
  next;
}

# emit all other lines as quoted string fragments
{
  if (commenting) end_comments();

  sub("\\\\[[:space:]]+.*$", "");	# lop off trailing \ comments
  sub("[[:space:]]+$", "");		# remove trailing spaces
  printf "    \"%s \\n\"\n", $0;
  next;
}

END \
{
  if (commenting) end_comments();
  printf "    \"quit \";\n";
  printf "\n\nvoid ficlCompileSoftCore(FICL_VM *pVM)\n";
  printf "{\n";
  printf "    assert(ficlExec(pVM, softWords) != VM_ERREXIT);\n";
  printf "}\n";
}

#!/usr/bin/awk -f
# Convert forth source files to a giant C string
# Joe Abley <jabley@patho.gen.nz>, 12 January 1999

BEGIN \
{
  printf "/***************************************************************\n";
  printf "** s o f t c o r e . c\n";
  printf "** Forth Inspired Command Language -\n";
  printf "** Words from CORE set written in FICL\n";
  printf "** Author: John Sadler (john_sadler@alum.mit.edu)\n";
  printf "** Created: 27 December 1997\n";
  printf "** Last update: %s\n", strftime();
  printf "***************************************************************/\n";
  printf "\n/*\n";
  printf "** This file contains definitions that are compiled into the\n";
  printf "** system dictionary by the first virtual machine to be created.\n";
  printf "** Created automagically by ficl/softwords/softcore.awk\n";
  printf "*/\n";
  printf "\n#include \"ficl.h\"\n";
  printf "\nstatic char softWords[] =\n";

  commenting = 0;
}

# some general early substitutions
{
  gsub("\t", "    ");			# replace each tab with 4 spaces
  gsub("\"", "\\\"");			# escape quotes
  gsub("\\\\[[:space:]]+$", "");	# toss empty comments
}

# strip out empty lines
/^ *$/ \
{
  next;
}

# emit / ** lines as multi-line C comments
/^\\[[:space:]]\*\*/ && (commenting == 0) \
{
  sub("^\\\\[[:space:]]", "");
  printf "/*\n%s\n", $0;
  commenting = 1;
  next;
}

/^\\[[:space:]]\*\*/ \
{
  sub("^\\\\[[:space:]]", "");
  printf "%s\n", $0;
  next;
}

# function to close a comment, used later
function end_comments()
{
  commenting = 0;
  printf "*/\n";
}

# pass commented preprocessor directives
/^\\[[:space:]]#/ \
{
  if (commenting) end_comments();
  sub("^\\\\[[:space:]]", "");
  printf "%s\n", $0;
  next;
}

# toss all other full-line comments
/^\\/ \
{
  if (commenting) end_comments();
  next;
}

# emit all other lines as quoted string fragments
{
  if (commenting) end_comments();

  sub("\\\\[[:space:]]+.*$", "");	# lop off trailing \ comments
  sub("[[:space:]]+$", "");		# remove trailing spaces
  printf "    \"%s \\n\"\n", $0;
  next;
}

END \
{
  if (commenting) end_comments();
  printf "    \"quit \";\n";
  printf "\n\nvoid ficlCompileSoftCore(FICL_VM *pVM)\n";
  printf "{\n";
  printf "    assert(ficlExec(pVM, softWords, -1) != VM_ERREXIT);\n";
  printf "}\n";
}


Check named_enable rather than just named_flags. PR:		3893 (sort of)

# $Id: ndcedit.awk,v 1.5 1997/05/27 07:19:57 jkh Exp $
NR == 3 {
	print "#"
	print "# This file is generated automatically, do not edit it here!"
	print "# Please change src/usr.sbin/ndc/ndcedit.awk instead"
	print "#"
	print ""

	print "# If there is a global system configuration file, suck it in."
	print "if [ -f /etc/rc.conf ]; then"
	print "\t. /etc/rc.conf"
	print "fi\n"
}
{
	if ($1 == "named") {
		printf "\t\t# $named_flags is imported from /etc/rc.conf\n"
		printf "\t\tif [ \"X${named_enable}\" = X\"YES\" ]; then\n"
		printf "\t\t\tnamed ${named_flags} && {\n"
		getline
		printf "\t%s\n", $0
		getline
		printf "\t%s\n", $0
		getline
		printf "\t%s\n", $0
		printf "\t\tfi\n"
	} else {
	        if (/PATH=/) {
			gsub(":/usr/ucb:", ":", $0);
		      	if (!/export/) {
				$0=$0"\nexport PATH";
			}
		}
		print;
	}
}

# $Id: ndcedit.awk,v 1.4 1997/02/22 16:08:19 peter Exp $
NR == 3 {
	print "#"
	print "# This file is generated automatically, do not edit it here!"
	print "# Please change src/usr.sbin/ndc/ndcedit.awk instead"
	print "#"
	print ""

	print "# If there is a global system configuration file, suck it in."
	print "if [ -f /etc/rc.conf ]; then"
	print "\t. /etc/rc.conf"
	print "fi\n"
}
{
	if ($1 == "named") {
		printf "\t\t# $namedflags is imported from /etc/rc.conf\n"
		printf "\t\tif [ \"X${named_flags}\" != X\"NO\" ]; then\n"
		printf "\t\t\tnamed ${named_flags} && {\n"
		getline
		printf "\t%s\n", $0
		getline
		printf "\t%s\n", $0
		getline
		printf "\t%s\n", $0
		printf "\t\tfi\n"
	} else {
	        if (/PATH=/) {
			gsub(":/usr/ucb:", ":", $0);
		      	if (!/export/) {
				$0=$0"\nexport PATH";
			}
		}
		print;
	}
}


get @BASE prefix working

get @BASE prefix working

#! /usr/bin/awk -f

#  Reduce the subject and object of RDF triples (ntriples format)
# down to their @prefix (or literal object class)
#  Reduce predicates to the specific identifier and
# the ontology they are from.(curi form)
#  Express the subject and object as nodes with a directed edge
# labeled with the predicate in the graphviz dot format
#  Include a tally of each combination of nodes and edge

#  This may over generalize in some cases because I do not have
# a handy way to differentiate uri for subjects and objects
# which may belong to a "structural" ontology as opposed to
# a data uri.

#  Perhaps an improvement would be to also
# express subject and objects as individual curies (ala predicates)
# iff their namespace is also used by a predicate.

##########################################################
# remove first and last chars from input string <>
function trim(str){
	return substr(str,2,length(str)-2)
}

########################################################
# remove final(ish) element in paths with various delimiters
# this leaves the namespace of a removed identifier

# this may need to be called more than once since
# some identifiers may have embedded delimiters
function stripid(uri){
	# <_:blanknode> are not allowed in ntriples (but may happen anyway)
	if(1 == match(uri, /^_:/))
		return "BNODE"
	# perspective endpoints, choose the longest
	delim["_"]=0; delim["/"]=0;
	delim["="]=0; delim[":"]=0; delim["#"]=0;
	char=""; max=-1;
	for(c in delim){
		l = match(uri, char)  # side effect is RLENGTH
		if(l > max){
			char = c;
			delim[char] = RLENGTH
		}
	}
	if(max<=0 || char=="")
		# we don't know what it is, a literal perhaps or uri fragment
		return uri
	else
		return substr(uri,1,delim[char])  # the probably truncated uri
}

# keep underscore, letters & numbers
# change the rest to (a single) underscore sans leading & trailing
# this passes valid node labels from dot's perspective
function simplify(str){
	gsub(/[^[:alpha:][:digit:]_]+/,"_",str)
	gsub(/^_+|_+$/, "",str)
	gsub(/__*/,"_",str)
	return str
}

# if possible, find a shorter form for the input
function contract(uri){
	u = uri
	# shorten till longest uri in curi map is found (or not)
	while(!(u in prefix) && (0 < length(u)))
		u = stripid(substr(u,1,length(u)-1))
	if(u in prefix)
		return prefix[u]
	else
		for(ex in exception){
			if((0 < match(uri, ex)) && exception[substr(uri,1,RLENGTH)])
				return exception[substr(uri,1,RLENGTH)]
		}
		return "___" simplify(uri)
}

# get the final (incl fragment identifier) portion of a slashed path
function final(uri){
	split(uri, b, "/")
	p = b[length(b)]
	anchor = match(p, "#")
	if(anchor > 0)
		p = substr(p, anchor+1)
	return p
}

BEGIN{
	prefix["BNODE"]="BNODE"  # is a fixed point
	prefix["https://monarchinitiative.org/_"]="BNODE"
	# just until skolemized bnodes get in the curie map?
	exception["https://monarchinitiative.org/.well-known/genid"]="BNODE"
	# revisit if exceptions are still necessary
	exception["http://www.w3.org/1999/02/22-rdf-syntax-ns#"]="rdf"
	exception["http://www.w3.org/2000/01/rdf-schema#"]="rdfs"
	exception["http://www.w3.org/2002/07/owl#"]="owl"
	# in mgi
	exception["https://www.mousephenotype.org"]="IMPC"
	# in panther
	exception["http://identifiers.org/wormbase"]="WormBase"
	# till all non httpS: are purged
	exception["http://monarchinitiative.org/"]="BASE"
	exception["https://monarchinitiative.org/MONARCH_"]="MONARCH"
}

# main loop
# parse and stash the curie yaml file (first file)
# YAML format is tic delimited word (the curi prefix)
# optional whitespace, a colon, then a tic delimited url
# (FNR == NR) && /^'[^']*' *: 'http[^']*'.*/ { # loosing some?
(FNR == NR) && /^'.*/ {
	split($0, arr, "'")
	if(arr[2]=="")
		arr[2]="BASE"
	prefix[arr[4]]=arr[2]
}
# process the ntriple file(s)  which are not the first file
### case when subject predicate and object are all uri
(FNR != NR) && /^<[^>]*> <[^>]*> <[^>]*> \.$/ {
	### Subject (uri)
	s = contract(stripid(trim($1)))
	### Predicate (uri)
	p =  final(trim($2))
	ns = contract(stripid(trim($2)))
	### Object (like subject)
	o = contract(stripid(trim($3)))
	edgelist[s,ns ":" p,o]++
}
### case when the object is a literal
(FNR != NR) && /^<[^>]*> <[^>]*> "[^"]*" \.$/ {
	### Subject (uri)
	s = contract(stripid(trim($1)))
	### Predicate (uri)
	p = final(trim($2))
	ns = contract(stripid(trim($2)))
	### not a uri
	o = "LITERAL"
	edgelist[s, ns ":" p, o]++
	nodelist[o " [shape=record];"]++
}

# output dot file, include edge counts
END{
	print "digraph {"
	print "rankdir=LR;"
	print "charset=\"utf-8\";"
	for(edge in edgelist){
		split(edge ,spo, SUBSEP);
		print simplify(spo[1]) " -> " simplify(spo[3]) \
		" [label=\"" spo[2] " (" edgelist[edge] ")\"];"
	}
	for(node in nodelist) print node
	print "labelloc=\"t\";"
	title = final(FILENAME)
	datestamp = strftime("%Y%m%d", systime())
	print "label=\"" substr(title,1,length(title)-3) " (" datestamp ")\";"
	print "}"
}

#! /usr/bin/awk -f

#  Reduce the subject and object of RDF triples (ntriples format)
# down to their @prefix (or literal object class)
#  Reduce predicates to the specific identifier and
# the ontology they are from.(curi form)
#  Express the subject and object as nodes with a directed edge
# labeled with the predicate in the graphviz dot format
#  Include a tally of each combination of nodes and edge

#  This may over generalize in some cases because I do not have
# a handy way to differentiate uri for subjects and objects
# which may belong to a "structural" ontology as opposed to
# a data uri.

#  Perhaps an improvement would be to also
# express subject and objects as individual curies (ala predicates)
# iff their namespace is also used by a predicate.

##########################################################
# remove first and last chars from input string <>
function trim(str){
	return substr(str,2,length(str)-2)
}

########################################################
# remove final(ish) element in paths with various delimiters
# this leaves the namespace of a removed identifier

# this may need to be called more than once since
# some identifiers may have embedded delimiters
function stripid(uri){
	# <_:blanknode> are not allowed in ntriples (but may happen anyway)
	if(1 == match(uri, /^_:/))
		return "BNODE"
	# perspective endpoints, choose the longest
	delim["_"]=0; delim["/"]=0;
	delim["="]=0; delim[":"]=0; delim["#"]=0;
	char=""; max=-1;
	for(c in delim){
		l = match(uri, char)  # side effect is RLENGTH
		if(l > max){
			char = c;
			delim[char] = RLENGTH
		}
	}
	if(max<=0) # we don't know what it is, a literal perhaps or uri fragment
		return uri
	else
		return substr(uri,1,delim[char])  # the probably truncated uri
}

# keep underscore, letters & numbers
# change the rest to (a single) underscore sans leading & trailing
# this passes valid node labels from dot's perspective
function simplify(str){
	gsub(/[^[:alpha:][:digit:]_]+/,"_",str)
	gsub(/^_+|_+$/, "",str)
	gsub(/__*/,"_",str)
	return str
}

# if possible, find a shorter form for the input
function contract(uri){
	u = uri
	# shorten till longest uri in curi map is found (or not)
	while(!(u in prefix) && (0 < length(u)))
		u = stripid(substr(u,1,length(u)-1))

	if(u in prefix)
		return prefix[u]
	else
		for(ex in exception){
			if(0 < match(uri, ex))
				return exception[substr(uri, 1, RLENGTH)]
		}
		return "___" simplify(uri)
}

# get the final (incl fragment identifier) portion of a slashed path
function final(uri){
	split(uri, b, "/")
	p = b[length(b)]
	anchor = match(p, "#")
	if(anchor > 0)
		p = substr(p, anchor+1)
	return p
}

BEGIN{
	prefix["BNODE"] = "BNODE"  # is a fixed point
	# revisit if exceptions are still necessary
	exception["http://www.w3.org/1999/02/22-rdf-syntax-ns#"]="rdf"
	exception["http://www.w3.org/2000/01/rdf-schema#"]="rdfs"
	exception["http://www.w3.org/2002/07/owl#"]="owl"
	# in mgi
	exception["https://www.mousephenotype.org"]="IMPC"
	# in panther
	exception["http://identifiers.org/wormbase"]="WormBase"
	# just until skolemized bnodes get in the curie map?
	exception["https://monarchinitiave.org/.well-known/genid"]="BNODE"
	# till all non httpS: are purged
	exception["http://monarchinitiave.org"]="MONARCH"
}

# main loop
# parse and stash the curie yaml file (first file)
# YAML format is tic delimited word (the curi prefix)
# optional whitespace, a colon, then a tic delimited url
# (FNR == NR) && /^'[^']*' *: 'http[^']*'.*/ { # loosing some?
(FNR == NR) && /^'.*/ {
	split($0, arr, "'")
	prefix[arr[4]]=arr[2]
}
# process the ntriple file(s)  which are not the first file
### case when subject predicate and object are all uri
(FNR != NR) && /^<[^>]*> <[^>]*> <[^>]*> \.$/ {
	### Subject (uri)
	s = contract(stripid(trim($1)))
	### Predicate (uri)
	p =  final(trim($2))
	ns = contract(stripid(trim($2)))
	### Object (like subject)
	o = contract(stripid(trim($3)))
	edgelist[s,ns ":" p,o]++
}
### case when the object is a literal
(FNR != NR) && /^<[^>]*> <[^>]*> "[^"]*" \.$/ {
	### Subject (uri)
	s = contract(stripid(trim($1)))
	### Predicate (uri)
	p = final(trim($2))
	ns = contract(stripid(trim($2)))
	### not a uri
	o = "LITERAL"
	edgelist[s, ns ":" p, o]++
	nodelist[o " [shape=record];"]++
}

# output dot file, include edge counts
END{
	print "digraph {"
	print "rankdir=LR;"
	print "charset=\"utf-8\";"
	for(edge in edgelist){
		split(edge ,spo, SUBSEP);
		print simplify(spo[1]) " -> " simplify(spo[3]) \
		" [label=\"" spo[2] " (" edgelist[edge] ")\"];"
	}
	for(node in nodelist) print node
	print "labelloc=\"t\";"
	title = final(FILENAME)
	datestamp = strftime("%Y%m%d", systime())
	print "label=\"" substr(title,1,length(title)-3) " (" datestamp ")\";"
	print "}"

}


ahrf.awk: Rework paragraph. Each word is now handled separately (was only managing lines before). It is much more efficient and allow us more flexibility.

#!/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 ]*:/ {
	match($0,":+")
	cnt = RLENGTH
	gsub(/^[\t ]*:+[\t ]*|[\t ]*:+[\t ]*$/,"")
	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++) {
			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 ]*====+[\t ]*\n|\n[\t ]*====+[\t ]*$/,"")
		printf("
")
		for (c=1; c<NF; c++) {
			gsub(/^ +$/,"",$c)
			printf("%s\n", $c)
		}
		printf("%s
\n", $NF)
	}
	next
}

# List
/^[\t ]*\* +/ {
	printf("
\n")
	for (l=1; l<=NF; l++) {
		gsub(/^[\t ]*/,"",$l)
		if ($l ~ /\* +/) {
			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 removed useless tabs/spaces
			num = substr($u,RSTART,RLENGTH)
			url = substr($u,RSTART+RLENGTH+1)
			if (length(url) >= 60) {
				printf("\t
%s %.60s…
\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 ]*:/ {
	match($0,":+")
	cnt = RLENGTH
	gsub(/^[\t ]*:+[\t ]*|[\t ]*:+[\t ]*$/,"")
	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++) {
		if ($p ~ / +$/) {
			gsub(/ +$/,"",$p)
			printf("%s
\n", $p)
		} else {
			printf("%s\n", $p)
		}
	}
	printf("%s
\n", $p)
	next
}

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

# List
/^[\t ]*\* +/ {
	printf("
\n")
	for (l=1; l<=NF; l++) {
		gsub(/^[\t ]*/,"",$l)
		if ($l ~ /\* +/) {
			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 removed useless tabs/spaces
			num = substr($u,RSTART,RLENGTH)
			url = substr($u,RSTART+RLENGTH+1)
			if (length(url) >= 60) {
				printf("\t
%s %.60s…
\n", num, url, url)
			} else {
				printf("\t
%s %s
\n", num, url, url)
			}
		}
	}
	printf("
\n")
	next
}


prefer LC_CTYPE to LANG * fix Debian#762138 (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=762138)

####################################################################
# Languages.awk                                                    #
####################################################################

# Initialize all supported locales.
# Mostly ISO 639-1 codes, with a few ISO 639-2 codes (alpha-3).
# See: <https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes>
#      <http://www.loc.gov/standards/iso639-2/php/code_list.php>
function initLocale() {

    #1 Afrikaans
    Locale["af"]["name"]       = "Afrikaans"
    Locale["af"]["endonym"]    = "Afrikaans"
    Locale["af"]["message"]    = "Vertalings van %s"

    #2 Albanian
    Locale["sq"]["name"]       = "Albanian"
    Locale["sq"]["endonym"]    = "Shqip"
    Locale["sq"]["message"]    = "Përkthimet e %s"

    #3 Arabic
    Locale["ar"]["name"]       = "Arabic"
    Locale["ar"]["endonym"]    = "العربية"
    Locale["ar"]["message"]    = "ترجمات %s"
    Locale["ar"]["rtl"]        = "true" # RTL language

    #4 Armenian
    Locale["hy"]["name"]       = "Armenian"
    Locale["hy"]["endonym"]    = "Հայերեն"
    Locale["hy"]["message"]    = "%s-ի թարգմանությունները"

    #5 Azerbaijani
    Locale["az"]["name"]       = "Azerbaijani"
    Locale["az"]["endonym"]    = "Azərbaycanca"
    Locale["az"]["message"]    = "%s sözünün tərcüməsi"

    #6 Basque
    Locale["eu"]["name"]       = "Basque"
    Locale["eu"]["endonym"]    = "Euskara"
    Locale["eu"]["message"]    = "%s esapidearen itzulpena"

    #7 Belarusian (Cyrillic alphabet)
    Locale["be"]["name"]       = "Belarusian"
    Locale["be"]["endonym"]    = "беларуская"
    Locale["be"]["message"]    = "Пераклады %s"

    #8 Bengali
    Locale["bn"]["name"]       = "Bengali"
    Locale["bn"]["endonym"]    = "বাংলা"
    Locale["bn"]["message"]    = "%s এর অনুবাদ"

    #9 Bosnian (Latin alphabet)
    Locale["bs"]["name"]       = "Bosnian"
    Locale["bs"]["endonym"]    = "Bosanski"
    Locale["bs"]["message"]    = "Prijevod za: %s"

    #10 Bulgarian
    Locale["bg"]["name"]       = "Bulgarian"
    Locale["bg"]["endonym"]    = "български"
    Locale["bg"]["message"]    = "Преводи на %s"

    #11 Catalan
    Locale["ca"]["name"]       = "Catalan"
    Locale["ca"]["endonym"]    = "Català"
    Locale["ca"]["message"]    = "Traduccions per a %s"

    #12 Cebuano
    Locale["ceb"]["name"]      = "Cebuano"
    Locale["ceb"]["endonym"]   = "Cebuano"
    Locale["ceb"]["message"]   = "%s Mga Paghubad sa PULONG_O_HUGPONG SA PAMULONG"

    #13a Chinese (Simplified)
    Locale["zh-CN"]["name"]    = "Chinese Simplified"
    Locale["zh-CN"]["endonym"] = "简体中文"
    Locale["zh-CN"]["message"] = "%s 的翻译"

    #13b Chinese (Traditional)
    Locale["zh-TW"]["name"]    = "Chinese Traditional"
    Locale["zh-TW"]["endonym"] = "正體中文"
    Locale["zh-TW"]["message"] = "「%s」的翻譯"

    #14 Croatian
    Locale["hr"]["name"]       = "Croatian"
    Locale["hr"]["endonym"]    = "Hrvatski"
    Locale["hr"]["message"]    = "Prijevodi riječi ili izraza %s"

    #15 Czech
    Locale["cs"]["name"]       = "Czech"
    Locale["cs"]["endonym"]    = "Čeština"
    Locale["cs"]["message"]    = "Překlad výrazu %s"

    #16 Danish
    Locale["da"]["name"]       = "Danish"
    Locale["da"]["endonym"]    = "Dansk"
    Locale["da"]["message"]    = "Oversættelser af %s"

    #17 Dutch
    Locale["nl"]["name"]       = "Dutch"
    Locale["nl"]["endonym"]    = "Nederlands"
    Locale["nl"]["message"]    = "Vertalingen van %s"

    #18 English
    Locale["en"]["name"]       = "English"
    Locale["en"]["endonym"]    = "English"
    Locale["en"]["message"]    = "Translations of %s"

    #19 Esperanto
    Locale["eo"]["name"]       = "Esperanto"
    Locale["eo"]["endonym"]    = "Esperanto"
    Locale["eo"]["message"]    = "Tradukoj de %s"

    #20 Estonian
    Locale["et"]["name"]       = "Estonian"
    Locale["et"]["endonym"]    = "Eesti"
    Locale["et"]["message"]    = "Sõna(de) %s tõlked"

    #21 Filipino
    Locale["tl"]["name"]       = "Filipino"
    Locale["tl"]["endonym"]    = "Tagalog"
    Locale["tl"]["message"]    = "Mga pagsasalin ng %s"

    #22 Finnish
    Locale["fi"]["name"]       = "Finnish"
    Locale["fi"]["endonym"]    = "Suomi"
    Locale["fi"]["message"]    = "Käännökset tekstille %s"

    #23 French
    Locale["fr"]["name"]       = "French"
    Locale["fr"]["endonym"]    = "Français"
    Locale["fr"]["message"]    = "Traductions de %s"

    #24 Galician
    Locale["gl"]["name"]       = "Galician"
    Locale["gl"]["endonym"]    = "Galego"
    Locale["gl"]["message"]    = "Traducións de %s"

    #25 Georgian
    Locale["ka"]["name"]       = "Georgian"
    Locale["ka"]["endonym"]    = "ქართული"
    Locale["ka"]["message"]    = "%s-ის თარგმანები"

    #26 German
    Locale["de"]["name"]       = "German"
    Locale["de"]["endonym"]    = "Deutsch"
    Locale["de"]["message"]    = "Übersetzungen für %s"

    #27 Greek
    Locale["el"]["name"]       = "Greek"
    Locale["el"]["endonym"]    = "Ελληνικά"
    Locale["el"]["message"]    = "Μεταφράσεις του %s"

    #28 Gujarati
    Locale["gu"]["name"]       = "Gujarati"
    Locale["gu"]["endonym"]    = "ગુજરાતી"
    Locale["gu"]["message"]    = "%s ના અનુવાદ"

    #29 Haitian Creole
    Locale["ht"]["name"]       = "Haitian Creole"
    Locale["ht"]["endonym"]    = "Kreyòl Ayisyen"
    Locale["ht"]["message"]    = "Tradiksyon %s"

    #30 Hausa (Latin / Boko alphabet)
    Locale["ha"]["name"]       = "Hausa"
    Locale["ha"]["endonym"]    = "Hausa"
    Locale["ha"]["message"]    = "Fassarar %s"

    #31 Hebrew
    Locale["he"]["name"]       = "Hebrew"
    Locale["he"]["endonym"]    = "עִבְרִית"
    Locale["he"]["message"]    = "תרגומים של %s"
    Locale["he"]["rtl"]        = "true" # RTL language

    #32 Hindi
    Locale["hi"]["name"]       = "Hindi"
    Locale["hi"]["endonym"]    = "हिन्दी"
    Locale["hi"]["message"]    = "%s के अनुवाद"

    #33 Hmong
    Locale["hmn"]["name"]      = "Hmong"
    Locale["hmn"]["endonym"]   = "Hmoob"
    Locale["hmn"]["message"]   = "Lus txhais: %s"

    #34 Hungarian
    Locale["hu"]["name"]       = "Hungarian"
    Locale["hu"]["endonym"]    = "Magyar"
    Locale["hu"]["message"]    = "%s fordításai"

    #35 Icelandic
    Locale["is"]["name"]       = "Icelandic"
    Locale["is"]["endonym"]    = "Íslenska"
    Locale["is"]["message"]    = "Þýðingar á %s"

    #36 Igbo
    Locale["ig"]["name"]       = "Igbo"
    Locale["ig"]["endonym"]    = "Igbo"
    Locale["ig"]["message"]    = "Ntụgharị asụsụ nke %s"

    #37 Indonesian
    Locale["id"]["name"]       = "Indonesian"
    Locale["id"]["endonym"]    = "Bahasa Indonesia"
    Locale["id"]["message"]    = "Terjemahan dari %s"

    #38 Irish
    Locale["ga"]["name"]       = "Irish"
    Locale["ga"]["endonym"]    = "Gaeilge"
    Locale["ga"]["message"]    = "Aistriúcháin ar %s"

    #39 Italian
    Locale["it"]["name"]       = "Italian"
    Locale["it"]["endonym"]    = "Italiano"
    Locale["it"]["message"]    = "Traduzioni di %s"

    #40 Japanese
    Locale["ja"]["name"]       = "Japanese"
    Locale["ja"]["endonym"]    = "日本語"
    Locale["ja"]["message"]    = "「%s」の翻訳"

    #41 Javanese (Latin alphabet)
    Locale["jv"]["name"]       = "Javanese"
    Locale["jv"]["endonym"]    = "Basa Jawa"
    Locale["jv"]["message"]    = "Terjemahan"

    #42 Kannada
    Locale["kn"]["name"]       = "Kannada"
    Locale["kn"]["endonym"]    = "ಕನ್ನಡ"
    Locale["kn"]["message"]    = "%s ನ ಅನುವಾದಗಳು"

    #43 Khmer (Central Khmer)
    Locale["km"]["name"]       = "Khmer"
    Locale["km"]["endonym"]    = "ភាសាខ្មែរ"
    Locale["km"]["message"]    = "ការបកប្រែនៃ %s"

    #44 Korean
    Locale["ko"]["name"]       = "Korean"
    Locale["ko"]["endonym"]    = "한국어"
    Locale["ko"]["message"]    = "%s의 번역"

    #45 Lao
    Locale["lo"]["name"]       = "Lao"
    Locale["lo"]["endonym"]    = "ລາວ"
    Locale["lo"]["message"]    = "ການແປພາສາຂອງ %s"

    #46 Latin
    Locale["la"]["name"]       = "Latin"
    Locale["la"]["endonym"]    = "Latina"
    Locale["la"]["message"]    = "Versio de %s"

    #47 Latvian
    Locale["lv"]["name"]       = "Latvian"
    Locale["lv"]["endonym"]    = "Latviešu"
    Locale["lv"]["message"]    = "%s tulkojumi"

    #48 Lithuanian
    Locale["lt"]["name"]       = "Lithuanian"
    Locale["lt"]["endonym"]    = "Lietuvių"
    Locale["lt"]["message"]    = "„%s“ vertimai"

    #49 Macedonian
    Locale["mk"]["name"]       = "Macedonian"
    Locale["mk"]["endonym"]    = "Македонски"
    Locale["mk"]["message"]    = "Преводи на %s"

    #50 Malay
    Locale["ms"]["name"]       = "Malay"
    Locale["ms"]["endonym"]    = "Bahasa Melayu"
    Locale["ms"]["message"]    = "Terjemahan %s"

    #51 Maltese
    Locale["mt"]["name"]       = "Maltese"
    Locale["mt"]["endonym"]    = "Malti"
    Locale["mt"]["message"]    = "Traduzzjonijiet ta' %s"

    #52 Maori
    Locale["mi"]["name"]       = "Maori"
    Locale["mi"]["endonym"]    = "Māori"
    Locale["mi"]["message"]    = "Ngā whakamāoritanga o %s"

    #53 Marathi
    Locale["mr"]["name"]       = "Marathi"
    Locale["mr"]["endonym"]    = "मराठी"
    Locale["mr"]["message"]    = "%s ची भाषांतरे"

    #54 Mongolian (Cyrillic alphabet)
    Locale["mn"]["name"]       = "Mongolian"
    Locale["mn"]["endonym"]    = "Монгол"
    Locale["mn"]["message"]    = "%s-н орчуулга"

    #55 Nepali
    Locale["ne"]["name"]       = "Nepali"
    Locale["ne"]["endonym"]    = "नेपाली"
    Locale["ne"]["message"]    = "%sका अनुवाद"

    #56 Norwegian
    Locale["no"]["name"]       = "Norwegian"
    Locale["no"]["endonym"]    = "Norsk"
    Locale["no"]["message"]    = "Oversettelser av %s"

    #57 Persian
    Locale["fa"]["name"]       = "Persian"
    Locale["fa"]["endonym"]    = "فارسی"
    Locale["fa"]["message"]    = "ترجمه‌های %s"
    Locale["fa"]["rtl"]        = "true" # RTL language

    #58 Punjabi (Brahmic / Gurmukhī alphabet)
    Locale["pa"]["name"]       = "Punjabi"
    Locale["pa"]["endonym"]    = "ਪੰਜਾਬੀ"
    Locale["pa"]["message"]    = "ਦੇ ਅਨੁਵਾਦ%s"

    #59 Polish
    Locale["pl"]["name"]       = "Polish"
    Locale["pl"]["endonym"]    = "Polski"
    Locale["pl"]["message"]    = "Tłumaczenia %s"

    #60 Portuguese
    Locale["pt"]["name"]       = "Portuguese"
    Locale["pt"]["endonym"]    = "Português"
    Locale["pt"]["message"]    = "Traduções de %s"

    #61 Romanian
    Locale["ro"]["name"]       = "Romanian"
    Locale["ro"]["endonym"]    = "Română"
    Locale["ro"]["message"]    = "Traduceri pentru %s"

    #62 Russian
    Locale["ru"]["name"]       = "Russian"
    Locale["ru"]["endonym"]    = "Русский"
    Locale["ru"]["message"]    = "%s: варианты перевода"

    #63 Serbian (Cyrillic alphabet)
    Locale["sr"]["name"]       = "Serbian"
    Locale["sr"]["endonym"]    = "српски"
    Locale["sr"]["message"]    = "Преводи за „%s“"

    #64 Slovak
    Locale["sk"]["name"]       = "Slovak"
    Locale["sk"]["endonym"]    = "Slovenčina"
    Locale["sk"]["message"]    = "Preklady výrazu: %s"

    #65 Slovenian
    Locale["sl"]["name"]       = "Slovenian"
    Locale["sl"]["endonym"]    = "Slovenščina"
    Locale["sl"]["message"]    = "Prevodi za %s"

    #66 Somali
    Locale["so"]["name"]       = "Somali"
    Locale["so"]["endonym"]    = "Soomaali"
    Locale["so"]["message"]    = "Turjumaada %s"

    #67 Spanish
    Locale["es"]["name"]       = "Spanish"
    Locale["es"]["endonym"]    = "Español"
    Locale["es"]["message"]    = "Traducciones de %s"

    #68 Swahili
    Locale["sw"]["name"]       = "Swahili"
    Locale["sw"]["endonym"]    = "Kiswahili"
    Locale["sw"]["message"]    = "Tafsiri ya %s"

    #69 Swedish
    Locale["sv"]["name"]       = "Swedish"
    Locale["sv"]["endonym"]    = "Svenska"
    Locale["sv"]["message"]    = "Översättningar av %s"

    #70 Tamil
    Locale["ta"]["name"]       = "Tamil"
    Locale["ta"]["endonym"]    = "தமிழ்"
    Locale["ta"]["message"]    = "%s இன் மொழிபெயர்ப்புகள்"

    #71 Telugu
    Locale["te"]["name"]       = "Telugu"
    Locale["te"]["endonym"]    = "తెలుగు"
    Locale["te"]["message"]    = "%s యొక్క అనువాదాలు"

    #72 Thai
    Locale["th"]["name"]       = "Thai"
    Locale["th"]["endonym"]    = "ไทย"
    Locale["th"]["message"]    = "คำแปลของ %s"

    #73 Turkish
    Locale["tr"]["name"]       = "Turkish"
    Locale["tr"]["endonym"]    = "Türkçe"
    Locale["tr"]["message"]    = "%s çevirileri"

    #74 Ukrainian
    Locale["uk"]["name"]       = "Ukrainian"
    Locale["uk"]["endonym"]    = "Українська"
    Locale["uk"]["message"]    = "Переклади слова або виразу \"%s\""

    #75 Urdu
    Locale["ur"]["name"]       = "Urdu"
    Locale["ur"]["endonym"]    = "اُردُو"
    Locale["ur"]["message"]    = "کے ترجمے %s"
    Locale["ur"]["rtl"]        = "true" # RTL language

    #76 Vietnamese
    Locale["vi"]["name"]       = "Vietnamese"
    Locale["vi"]["endonym"]    = "Tiếng Việt"
    Locale["vi"]["message"]    = "Bản dịch của %s"

    #77 Welsh
    Locale["cy"]["name"]       = "Welsh"
    Locale["cy"]["endonym"]    = "Cymraeg"
    Locale["cy"]["message"]    = "Cyfieithiadau %s"

    #78 Yiddish
    Locale["yi"]["name"]       = "Yiddish"
    Locale["yi"]["endonym"]    = "ייִדיש"
    Locale["yi"]["message"]    = "איבערזעצונגען פון %s"
    Locale["yi"]["rtl"]        = "true" # RTL language

    #79 Yoruba
    Locale["yo"]["name"]       = "Yoruba"
    Locale["yo"]["endonym"]    = "Yorùbá"
    Locale["yo"]["message"]    = "Awọn itumọ ti %s"

    #80 Zulu
    Locale["zu"]["name"]       = "Zulu"
    Locale["zu"]["endonym"]    = "isiZulu"
    Locale["zu"]["message"]    = "Ukuhumusha i-%s"

    # Aliases for some locales
    # See: <http://www.loc.gov/standards/iso639-2/php/code_changes.php>
    LocaleAlias["in"] = "id" # withdrawn language code for Indonesian
    LocaleAlias["iw"] = "he" # withdrawn language code for Hebrew
    LocaleAlias["ji"] = "yi" # withdrawn language code for Yiddish

    LocaleAlias["jw"] = "jv" # withdrawn language code for Javanese
    LocaleAlias["mo"] = "ro" # Moldavian or Moldovan considered a variant of the Romanian language
    LocaleAlias["sh"] = "sr" # Serbo-Croatian: prefer Serbian
    LocaleAlias["zh"] = "zh-CN" # Chinese: prefer Chinese Simplified
    LocaleAlias["zh-cn"] = "zh-CN" # lowercase
    LocaleAlias["zh-tw"] = "zh-TW" # lowercase
    # TODO: any more aliases supported by Google Translate?
}

# Get locale key by language code or alias.
function getCode(code) {
    code = tolower(code) # case-insensitive

    if (code in Locale || code == "auto")
        return code
    else if (code in LocaleAlias)
        return LocaleAlias[code]
    else
        return # return nothing if not found
}

# Detect external bidirectional algorithm utility (fribidi);
# Fallback to Unix `rev` if not found.
function initBiDi() {
    "fribidi --version 2>/dev/null" |& getline FriBidi
    BiDiNoPad = FriBidi ? "fribidi --nopad" : "rev"
    BiDi = FriBidi ? "fribidi --width %s" : "rev | sed \"s/'/\\\\\\'/\" | xargs printf '%%s '"
}

# Convert a logical string to visual; don't right justify RTL lines.
# Parameters:
#     code: ignore to apply bidirectional algorithm on every string
function show(text, code,    temp) {
    if (!code || Locale[getCode(code)]["rtl"]) {
        if (Cache[text][0])
            return Cache[text][0]
        else {
            if (FriBidi || (code && Locale[getCode(code)]["rtl"]))
                ("echo " parameterize(text) " | " BiDiNoPad) | getline temp
            else # non-RTL language, or FriBidi not installed
                temp = text
            return Cache[text][0] = temp
        }
    } else
        return text
}

# Convert a logical string to visual and right justify RTL lines.
# Parameters:
#     code: ignore to apply bidirectional algorithm on every string
#     width: ignore to use default width for padding
function s(text, code, width,    temp) {
    if (!code || Locale[getCode(code)]["rtl"]) {
        if (!width) width = Option["width"]
        if (Cache[text][width])
            return Cache[text][width]
        else {
            if (FriBidi || (code && Locale[getCode(code)]["rtl"]))
                ("echo " parameterize(text) " | " sprintf(BiDi, width)) | getline temp
            else # non-RTL language, or FriBidi not installed
                temp = text
            return Cache[text][width] = temp
        }
    } else
        return text
}

# Initialize strings for displaying endonyms of locales.
function initLocaleDisplay(    i) {
    for (i in Locale)
        Locale[i]["display"] = show(Locale[i]["endonym"], i)
}

# Parse a POSIX locale identifier and return the language code;
# Identified by both language identifier and region identifier.
# Parameters:
#     lang = [language[_territory][.codeset][@modifier]]
# See: <https://en.wikipedia.org/wiki/Locale>
function parseLang(lang,    code, group) {
    match(lang, /^([a-z][a-z][a-z]?)(_|$)/, group)
    code = getCode(group[1])

    # Detect region identifier
    ## Regions using Chinese Simplified: China, Singapore
    if (lang ~ /^zh_(CN|SG)/) code = "zh-CN"
    ## Regions using Chinese Traditional: Taiwan, Hong Kong
    else if (lang ~ /^zh_(TW|HK)/) code = "zh-TW"

    # FIXME: handle unrecognized language code
    if (!code) code = "en"

    return code
}

# Initialize `UserLang`.
function initUserLang() {
    UserLang = ENVIRON["LC_CTYPE"] ?
        parseLang(ENVIRON["LC_CTYPE"]) :
        (ENVIRON["LANG"] ?
         parseLang(ENVIRON["LANG"]) :
         "en")

    if (ENVIRON["LANG"] !~ /UTF-8$/ && ENVIRON["LC_CTYPE"] !~ /UTF-8$/)
        w("[WARNING] Your locale codeset (" ENVIRON["LANG"] ") is not UTF-8. You have been warned.")
}

####################################################################
# Languages.awk                                                    #
####################################################################

# Initialize all supported locales.
# Mostly ISO 639-1 codes, with a few ISO 639-2 codes (alpha-3).
# See: <https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes>
#      <http://www.loc.gov/standards/iso639-2/php/code_list.php>
function initLocale() {

    #1 Afrikaans
    Locale["af"]["name"]       = "Afrikaans"
    Locale["af"]["endonym"]    = "Afrikaans"
    Locale["af"]["message"]    = "Vertalings van %s"

    #2 Albanian
    Locale["sq"]["name"]       = "Albanian"
    Locale["sq"]["endonym"]    = "Shqip"
    Locale["sq"]["message"]    = "Përkthimet e %s"

    #3 Arabic
    Locale["ar"]["name"]       = "Arabic"
    Locale["ar"]["endonym"]    = "العربية"
    Locale["ar"]["message"]    = "ترجمات %s"
    Locale["ar"]["rtl"]        = "true" # RTL language

    #4 Armenian
    Locale["hy"]["name"]       = "Armenian"
    Locale["hy"]["endonym"]    = "Հայերեն"
    Locale["hy"]["message"]    = "%s-ի թարգմանությունները"

    #5 Azerbaijani
    Locale["az"]["name"]       = "Azerbaijani"
    Locale["az"]["endonym"]    = "Azərbaycanca"
    Locale["az"]["message"]    = "%s sözünün tərcüməsi"

    #6 Basque
    Locale["eu"]["name"]       = "Basque"
    Locale["eu"]["endonym"]    = "Euskara"
    Locale["eu"]["message"]    = "%s esapidearen itzulpena"

    #7 Belarusian (Cyrillic alphabet)
    Locale["be"]["name"]       = "Belarusian"
    Locale["be"]["endonym"]    = "беларуская"
    Locale["be"]["message"]    = "Пераклады %s"

    #8 Bengali
    Locale["bn"]["name"]       = "Bengali"
    Locale["bn"]["endonym"]    = "বাংলা"
    Locale["bn"]["message"]    = "%s এর অনুবাদ"

    #9 Bosnian (Latin alphabet)
    Locale["bs"]["name"]       = "Bosnian"
    Locale["bs"]["endonym"]    = "Bosanski"
    Locale["bs"]["message"]    = "Prijevod za: %s"

    #10 Bulgarian
    Locale["bg"]["name"]       = "Bulgarian"
    Locale["bg"]["endonym"]    = "български"
    Locale["bg"]["message"]    = "Преводи на %s"

    #11 Catalan
    Locale["ca"]["name"]       = "Catalan"
    Locale["ca"]["endonym"]    = "Català"
    Locale["ca"]["message"]    = "Traduccions per a %s"

    #12 Cebuano
    Locale["ceb"]["name"]      = "Cebuano"
    Locale["ceb"]["endonym"]   = "Cebuano"
    Locale["ceb"]["message"]   = "%s Mga Paghubad sa PULONG_O_HUGPONG SA PAMULONG"

    #13a Chinese (Simplified)
    Locale["zh-CN"]["name"]    = "Chinese Simplified"
    Locale["zh-CN"]["endonym"] = "简体中文"
    Locale["zh-CN"]["message"] = "%s 的翻译"

    #13b Chinese (Traditional)
    Locale["zh-TW"]["name"]    = "Chinese Traditional"
    Locale["zh-TW"]["endonym"] = "正體中文"
    Locale["zh-TW"]["message"] = "「%s」的翻譯"

    #14 Croatian
    Locale["hr"]["name"]       = "Croatian"
    Locale["hr"]["endonym"]    = "Hrvatski"
    Locale["hr"]["message"]    = "Prijevodi riječi ili izraza %s"

    #15 Czech
    Locale["cs"]["name"]       = "Czech"
    Locale["cs"]["endonym"]    = "Čeština"
    Locale["cs"]["message"]    = "Překlad výrazu %s"

    #16 Danish
    Locale["da"]["name"]       = "Danish"
    Locale["da"]["endonym"]    = "Dansk"
    Locale["da"]["message"]    = "Oversættelser af %s"

    #17 Dutch
    Locale["nl"]["name"]       = "Dutch"
    Locale["nl"]["endonym"]    = "Nederlands"
    Locale["nl"]["message"]    = "Vertalingen van %s"

    #18 English
    Locale["en"]["name"]       = "English"
    Locale["en"]["endonym"]    = "English"
    Locale["en"]["message"]    = "Translations of %s"

    #19 Esperanto
    Locale["eo"]["name"]       = "Esperanto"
    Locale["eo"]["endonym"]    = "Esperanto"
    Locale["eo"]["message"]    = "Tradukoj de %s"

    #20 Estonian
    Locale["et"]["name"]       = "Estonian"
    Locale["et"]["endonym"]    = "Eesti"
    Locale["et"]["message"]    = "Sõna(de) %s tõlked"

    #21 Filipino
    Locale["tl"]["name"]       = "Filipino"
    Locale["tl"]["endonym"]    = "Tagalog"
    Locale["tl"]["message"]    = "Mga pagsasalin ng %s"

    #22 Finnish
    Locale["fi"]["name"]       = "Finnish"
    Locale["fi"]["endonym"]    = "Suomi"
    Locale["fi"]["message"]    = "Käännökset tekstille %s"

    #23 French
    Locale["fr"]["name"]       = "French"
    Locale["fr"]["endonym"]    = "Français"
    Locale["fr"]["message"]    = "Traductions de %s"

    #24 Galician
    Locale["gl"]["name"]       = "Galician"
    Locale["gl"]["endonym"]    = "Galego"
    Locale["gl"]["message"]    = "Traducións de %s"

    #25 Georgian
    Locale["ka"]["name"]       = "Georgian"
    Locale["ka"]["endonym"]    = "ქართული"
    Locale["ka"]["message"]    = "%s-ის თარგმანები"

    #26 German
    Locale["de"]["name"]       = "German"
    Locale["de"]["endonym"]    = "Deutsch"
    Locale["de"]["message"]    = "Übersetzungen für %s"

    #27 Greek
    Locale["el"]["name"]       = "Greek"
    Locale["el"]["endonym"]    = "Ελληνικά"
    Locale["el"]["message"]    = "Μεταφράσεις του %s"

    #28 Gujarati
    Locale["gu"]["name"]       = "Gujarati"
    Locale["gu"]["endonym"]    = "ગુજરાતી"
    Locale["gu"]["message"]    = "%s ના અનુવાદ"

    #29 Haitian Creole
    Locale["ht"]["name"]       = "Haitian Creole"
    Locale["ht"]["endonym"]    = "Kreyòl Ayisyen"
    Locale["ht"]["message"]    = "Tradiksyon %s"

    #30 Hausa (Latin / Boko alphabet)
    Locale["ha"]["name"]       = "Hausa"
    Locale["ha"]["endonym"]    = "Hausa"
    Locale["ha"]["message"]    = "Fassarar %s"

    #31 Hebrew
    Locale["he"]["name"]       = "Hebrew"
    Locale["he"]["endonym"]    = "עִבְרִית"
    Locale["he"]["message"]    = "תרגומים של %s"
    Locale["he"]["rtl"]        = "true" # RTL language

    #32 Hindi
    Locale["hi"]["name"]       = "Hindi"
    Locale["hi"]["endonym"]    = "हिन्दी"
    Locale["hi"]["message"]    = "%s के अनुवाद"

    #33 Hmong
    Locale["hmn"]["name"]      = "Hmong"
    Locale["hmn"]["endonym"]   = "Hmoob"
    Locale["hmn"]["message"]   = "Lus txhais: %s"

    #34 Hungarian
    Locale["hu"]["name"]       = "Hungarian"
    Locale["hu"]["endonym"]    = "Magyar"
    Locale["hu"]["message"]    = "%s fordításai"

    #35 Icelandic
    Locale["is"]["name"]       = "Icelandic"
    Locale["is"]["endonym"]    = "Íslenska"
    Locale["is"]["message"]    = "Þýðingar á %s"

    #36 Igbo
    Locale["ig"]["name"]       = "Igbo"
    Locale["ig"]["endonym"]    = "Igbo"
    Locale["ig"]["message"]    = "Ntụgharị asụsụ nke %s"

    #37 Indonesian
    Locale["id"]["name"]       = "Indonesian"
    Locale["id"]["endonym"]    = "Bahasa Indonesia"
    Locale["id"]["message"]    = "Terjemahan dari %s"

    #38 Irish
    Locale["ga"]["name"]       = "Irish"
    Locale["ga"]["endonym"]    = "Gaeilge"
    Locale["ga"]["message"]    = "Aistriúcháin ar %s"

    #39 Italian
    Locale["it"]["name"]       = "Italian"
    Locale["it"]["endonym"]    = "Italiano"
    Locale["it"]["message"]    = "Traduzioni di %s"

    #40 Japanese
    Locale["ja"]["name"]       = "Japanese"
    Locale["ja"]["endonym"]    = "日本語"
    Locale["ja"]["message"]    = "「%s」の翻訳"

    #41 Javanese (Latin alphabet)
    Locale["jv"]["name"]       = "Javanese"
    Locale["jv"]["endonym"]    = "Basa Jawa"
    Locale["jv"]["message"]    = "Terjemahan"

    #42 Kannada
    Locale["kn"]["name"]       = "Kannada"
    Locale["kn"]["endonym"]    = "ಕನ್ನಡ"
    Locale["kn"]["message"]    = "%s ನ ಅನುವಾದಗಳು"

    #43 Khmer (Central Khmer)
    Locale["km"]["name"]       = "Khmer"
    Locale["km"]["endonym"]    = "ភាសាខ្មែរ"
    Locale["km"]["message"]    = "ការបកប្រែនៃ %s"

    #44 Korean
    Locale["ko"]["name"]       = "Korean"
    Locale["ko"]["endonym"]    = "한국어"
    Locale["ko"]["message"]    = "%s의 번역"

    #45 Lao
    Locale["lo"]["name"]       = "Lao"
    Locale["lo"]["endonym"]    = "ລາວ"
    Locale["lo"]["message"]    = "ການແປພາສາຂອງ %s"

    #46 Latin
    Locale["la"]["name"]       = "Latin"
    Locale["la"]["endonym"]    = "Latina"
    Locale["la"]["message"]    = "Versio de %s"

    #47 Latvian
    Locale["lv"]["name"]       = "Latvian"
    Locale["lv"]["endonym"]    = "Latviešu"
    Locale["lv"]["message"]    = "%s tulkojumi"

    #48 Lithuanian
    Locale["lt"]["name"]       = "Lithuanian"
    Locale["lt"]["endonym"]    = "Lietuvių"
    Locale["lt"]["message"]    = "„%s“ vertimai"

    #49 Macedonian
    Locale["mk"]["name"]       = "Macedonian"
    Locale["mk"]["endonym"]    = "Македонски"
    Locale["mk"]["message"]    = "Преводи на %s"

    #50 Malay
    Locale["ms"]["name"]       = "Malay"
    Locale["ms"]["endonym"]    = "Bahasa Melayu"
    Locale["ms"]["message"]    = "Terjemahan %s"

    #51 Maltese
    Locale["mt"]["name"]       = "Maltese"
    Locale["mt"]["endonym"]    = "Malti"
    Locale["mt"]["message"]    = "Traduzzjonijiet ta' %s"

    #52 Maori
    Locale["mi"]["name"]       = "Maori"
    Locale["mi"]["endonym"]    = "Māori"
    Locale["mi"]["message"]    = "Ngā whakamāoritanga o %s"

    #53 Marathi
    Locale["mr"]["name"]       = "Marathi"
    Locale["mr"]["endonym"]    = "मराठी"
    Locale["mr"]["message"]    = "%s ची भाषांतरे"

    #54 Mongolian (Cyrillic alphabet)
    Locale["mn"]["name"]       = "Mongolian"
    Locale["mn"]["endonym"]    = "Монгол"
    Locale["mn"]["message"]    = "%s-н орчуулга"

    #55 Nepali
    Locale["ne"]["name"]       = "Nepali"
    Locale["ne"]["endonym"]    = "नेपाली"
    Locale["ne"]["message"]    = "%sका अनुवाद"

    #56 Norwegian
    Locale["no"]["name"]       = "Norwegian"
    Locale["no"]["endonym"]    = "Norsk"
    Locale["no"]["message"]    = "Oversettelser av %s"

    #57 Persian
    Locale["fa"]["name"]       = "Persian"
    Locale["fa"]["endonym"]    = "فارسی"
    Locale["fa"]["message"]    = "ترجمه‌های %s"
    Locale["fa"]["rtl"]        = "true" # RTL language

    #58 Punjabi (Brahmic / Gurmukhī alphabet)
    Locale["pa"]["name"]       = "Punjabi"
    Locale["pa"]["endonym"]    = "ਪੰਜਾਬੀ"
    Locale["pa"]["message"]    = "ਦੇ ਅਨੁਵਾਦ%s"

    #59 Polish
    Locale["pl"]["name"]       = "Polish"
    Locale["pl"]["endonym"]    = "Polski"
    Locale["pl"]["message"]    = "Tłumaczenia %s"

    #60 Portuguese
    Locale["pt"]["name"]       = "Portuguese"
    Locale["pt"]["endonym"]    = "Português"
    Locale["pt"]["message"]    = "Traduções de %s"

    #61 Romanian
    Locale["ro"]["name"]       = "Romanian"
    Locale["ro"]["endonym"]    = "Română"
    Locale["ro"]["message"]    = "Traduceri pentru %s"

    #62 Russian
    Locale["ru"]["name"]       = "Russian"
    Locale["ru"]["endonym"]    = "Русский"
    Locale["ru"]["message"]    = "%s: варианты перевода"

    #63 Serbian (Cyrillic alphabet)
    Locale["sr"]["name"]       = "Serbian"
    Locale["sr"]["endonym"]    = "српски"
    Locale["sr"]["message"]    = "Преводи за „%s“"

    #64 Slovak
    Locale["sk"]["name"]       = "Slovak"
    Locale["sk"]["endonym"]    = "Slovenčina"
    Locale["sk"]["message"]    = "Preklady výrazu: %s"

    #65 Slovenian
    Locale["sl"]["name"]       = "Slovenian"
    Locale["sl"]["endonym"]    = "Slovenščina"
    Locale["sl"]["message"]    = "Prevodi za %s"

    #66 Somali
    Locale["so"]["name"]       = "Somali"
    Locale["so"]["endonym"]    = "Soomaali"
    Locale["so"]["message"]    = "Turjumaada %s"

    #67 Spanish
    Locale["es"]["name"]       = "Spanish"
    Locale["es"]["endonym"]    = "Español"
    Locale["es"]["message"]    = "Traducciones de %s"

    #68 Swahili
    Locale["sw"]["name"]       = "Swahili"
    Locale["sw"]["endonym"]    = "Kiswahili"
    Locale["sw"]["message"]    = "Tafsiri ya %s"

    #69 Swedish
    Locale["sv"]["name"]       = "Swedish"
    Locale["sv"]["endonym"]    = "Svenska"
    Locale["sv"]["message"]    = "Översättningar av %s"

    #70 Tamil
    Locale["ta"]["name"]       = "Tamil"
    Locale["ta"]["endonym"]    = "தமிழ்"
    Locale["ta"]["message"]    = "%s இன் மொழிபெயர்ப்புகள்"

    #71 Telugu
    Locale["te"]["name"]       = "Telugu"
    Locale["te"]["endonym"]    = "తెలుగు"
    Locale["te"]["message"]    = "%s యొక్క అనువాదాలు"

    #72 Thai
    Locale["th"]["name"]       = "Thai"
    Locale["th"]["endonym"]    = "ไทย"
    Locale["th"]["message"]    = "คำแปลของ %s"

    #73 Turkish
    Locale["tr"]["name"]       = "Turkish"
    Locale["tr"]["endonym"]    = "Türkçe"
    Locale["tr"]["message"]    = "%s çevirileri"

    #74 Ukrainian
    Locale["uk"]["name"]       = "Ukrainian"
    Locale["uk"]["endonym"]    = "Українська"
    Locale["uk"]["message"]    = "Переклади слова або виразу \"%s\""

    #75 Urdu
    Locale["ur"]["name"]       = "Urdu"
    Locale["ur"]["endonym"]    = "اُردُو"
    Locale["ur"]["message"]    = "کے ترجمے %s"
    Locale["ur"]["rtl"]        = "true" # RTL language

    #76 Vietnamese
    Locale["vi"]["name"]       = "Vietnamese"
    Locale["vi"]["endonym"]    = "Tiếng Việt"
    Locale["vi"]["message"]    = "Bản dịch của %s"

    #77 Welsh
    Locale["cy"]["name"]       = "Welsh"
    Locale["cy"]["endonym"]    = "Cymraeg"
    Locale["cy"]["message"]    = "Cyfieithiadau %s"

    #78 Yiddish
    Locale["yi"]["name"]       = "Yiddish"
    Locale["yi"]["endonym"]    = "ייִדיש"
    Locale["yi"]["message"]    = "איבערזעצונגען פון %s"
    Locale["yi"]["rtl"]        = "true" # RTL language

    #79 Yoruba
    Locale["yo"]["name"]       = "Yoruba"
    Locale["yo"]["endonym"]    = "Yorùbá"
    Locale["yo"]["message"]    = "Awọn itumọ ti %s"

    #80 Zulu
    Locale["zu"]["name"]       = "Zulu"
    Locale["zu"]["endonym"]    = "isiZulu"
    Locale["zu"]["message"]    = "Ukuhumusha i-%s"

    # Aliases for some locales
    # See: <http://www.loc.gov/standards/iso639-2/php/code_changes.php>
    LocaleAlias["in"] = "id" # withdrawn language code for Indonesian
    LocaleAlias["iw"] = "he" # withdrawn language code for Hebrew
    LocaleAlias["ji"] = "yi" # withdrawn language code for Yiddish

    LocaleAlias["jw"] = "jv" # withdrawn language code for Javanese
    LocaleAlias["mo"] = "ro" # Moldavian or Moldovan considered a variant of the Romanian language
    LocaleAlias["sh"] = "sr" # Serbo-Croatian: prefer Serbian
    LocaleAlias["zh"] = "zh-CN" # Chinese: prefer Chinese Simplified
    LocaleAlias["zh-cn"] = "zh-CN" # lowercase
    LocaleAlias["zh-tw"] = "zh-TW" # lowercase
    # TODO: any more aliases supported by Google Translate?
}

# Get locale key by language code or alias.
function getCode(code) {
    code = tolower(code) # case-insensitive

    if (code in Locale || code == "auto")
        return code
    else if (code in LocaleAlias)
        return LocaleAlias[code]
    else
        return # return nothing if not found
}

# Detect external bidirectional algorithm utility (fribidi);
# Fallback to Unix `rev` if not found.
function initBiDi() {
    "fribidi --version 2>/dev/null" |& getline FriBidi
    BiDiNoPad = FriBidi ? "fribidi --nopad" : "rev"
    BiDi = FriBidi ? "fribidi --width %s" : "rev | sed \"s/'/\\\\\\'/\" | xargs printf '%%s '"
}

# Convert a logical string to visual; don't right justify RTL lines.
# Parameters:
#     code: ignore to apply bidirectional algorithm on every string
function show(text, code,    temp) {
    if (!code || Locale[getCode(code)]["rtl"]) {
        if (Cache[text][0])
            return Cache[text][0]
        else {
            if (FriBidi || (code && Locale[getCode(code)]["rtl"]))
                ("echo " parameterize(text) " | " BiDiNoPad) | getline temp
            else # non-RTL language, or FriBidi not installed
                temp = text
            return Cache[text][0] = temp
        }
    } else
        return text
}

# Convert a logical string to visual and right justify RTL lines.
# Parameters:
#     code: ignore to apply bidirectional algorithm on every string
#     width: ignore to use default width for padding
function s(text, code, width,    temp) {
    if (!code || Locale[getCode(code)]["rtl"]) {
        if (!width) width = Option["width"]
        if (Cache[text][width])
            return Cache[text][width]
        else {
            if (FriBidi || (code && Locale[getCode(code)]["rtl"]))
                ("echo " parameterize(text) " | " sprintf(BiDi, width)) | getline temp
            else # non-RTL language, or FriBidi not installed
                temp = text
            return Cache[text][width] = temp
        }
    } else
        return text
}

# Initialize strings for displaying endonyms of locales.
function initLocaleDisplay(    i) {
    for (i in Locale)
        Locale[i]["display"] = show(Locale[i]["endonym"], i)
}

# Parse a POSIX locale identifier and return the language code;
# Identified by both language identifier and region identifier.
# Parameters:
#     lang = [language[_territory][.codeset][@modifier]]
# See: <https://en.wikipedia.org/wiki/Locale>
function parseLang(lang,    code, group) {
    match(lang, /^([a-z][a-z][a-z]?)(_|$)/, group)
    code = getCode(group[1])

    # Detect region identifier
    ## Regions using Chinese Simplified: China, Singapore
    if (lang ~ /^zh_(CN|SG)/) code = "zh-CN"
    ## Regions using Chinese Traditional: Taiwan, Hong Kong
    else if (lang ~ /^zh_(TW|HK)/) code = "zh-TW"

    # FIXME: handle unrecognized language code
    if (!code) code = "en"

    return code
}

# Initialize `UserLang`.
function initUserLang() {
    UserLang = ENVIRON["LANG"] ? parseLang(ENVIRON["LANG"]) : "en"

    if (!(ENVIRON["LANG"] ~ /UTF-8$/))
        w("[WARNING] Your codeset of locale (" ENVIRON["LANG"] ") is not UTF-8. You have been warned.")
}