Seriosly, drop very large synsets

Seriosly, drop very large synsets

#!/usr/bin/awk -f
BEGIN {
    FS = OFS = "\t";
}
{
    gsub("(#[[:digit:]]+|, $)", "");

    len = split($3, words, ", ");

    if (len >= 10000) next;

    for (i = 1; i <= len; i++) uniq[words[i]];

    for (word in uniq) {
        synset = synset sep word;
        sep = ", ";
        len++;
    }

    print $1, len, synset | "sort --parallel=$(nproc) -t \"\t\" -S1G -k2nr -k1n -s";

    synset = sep = len = ""; delete uniq;
}

#!/usr/bin/awk -f
BEGIN {
    FS = OFS = "\t";
}
{
    gsub("(#[[:digit:]]+|, $)", "");

    for (i = 1; i <= split($3, words, ", "); i++) uniq[words[i]];

    for (word in uniq) {
        synset = synset sep word;
        sep = ", ";
        len++;
    }

    print $1, len, synset | "sort --parallel=$(nproc) -t \"\t\" -S1G -k2nr -k1n -s";

    synset = sep = len = ""; delete uniq;
}


md.awk: fix code handling

md.awk: fix code handling

#!/bin/sh
# usage: markdown FILE.md | ../md.awk | pbcopy
awk '
NR < 3 {
	next
}
/
CODE<\/p>/ {
	print "

CODE

\n"
	next
}
/<\/code><\/pre>/ {
	print "

\n"
	next
}
/
.*<\/p>/ {
	printf("%s

\n\n", substr($0,4,length($0)-7))
	next
}
/^\s+$/ {
	print "

\n\n"
	next
}
/.+/ {
	print $0
	next
}
'

#!/bin/sh
# usage: markdown FILE.md | ../md.awk | pbcopy
awk '
NR < 3 {
	next
}
/
CODE<\/p>/ {
	print "

CODE

\n"
	next
}
/
.*<\/p>/ {
	printf("%s

\n\n", substr($0,4,length($0)-7))
	next
}
/^\s+$/ {
	print "

\n\n"
	next
}
/.+/ {
	print $0
	next
}
'


No need to initialize the domain_count as the variables of numbers in awk are 0 as default.

#!/usr/bin/awk -f

# Add domain name to global variable domains.
function add(domain) {
	domain_count = domain_count + 1
	domains[domain_count] = domain
}

# Extract domain name from non-regex line
function extract(line, original_line) {
	sub(/.*:\/\//, "", line) # remove everything till ://, such as http:// https://
	sub(/\/.*/, "", line)    # remove everything from /
	sub(/:.*/, "", line)     # remove everything from :
	sub(/\*/, "", line)      # remove *
	sub(/^\./, "", line)     # remove leading dot

	if (match(line, /([a-zA-Z0-9\-]+\.)+[a-zA-Z0-9\-]+/)) {
		add(line)
	} else {
		print "[WARN] <NR>" NR "</NR><original>" original_line "</original><extracted>" line "</extracted>" | "cat >&2"
	}
}

# Extract domain name from regex line
function extract_regex(line, original_line) {

	# Expand the lines like (aa|bb|cc) into multiple records
	pos = match(line, /\([a-zA-Z0-9\.\|]+\)/)
	if (pos != 0) {
		in_bracket = substr(line, RSTART + 1, RLENGTH - 2)
		n = split(in_bracket, arr, "|")
		for (i = 1; i <= n; i++) {
			expanded_line = line
			sub(/\([a-zA-Z0-9\.\|]+\)/, arr[i], expanded_line)
			extract_regex(expanded_line, original_line)
		}
	} else {
		sub(/.*:\\\/\\\//, "", line)    # remove everything till :\/\/ in regex, :// in plain text, such as http:// https://
		gsub(/\([^\)]+\)\*?/, "", line) # remove (...)*? such as ([^\/]+\.)
		gsub(/\[.*\]\+/, "", line)      # remove [...]
		sub(/\\\/.*/, "", line)         # remove everything from \/ in regex, / in plaint text
		gsub(/\\\./, ".", line)         # replace \. to .
		extract(line, original_line)
	}
}

BEGIN {
	"date \"+%Y-%m-%d %H:%M:%S\"" | getline now
	print "# gfw list ipset rules for dnsmasq"
	print "# updated on " now
	print "#"

	if (host == "") {
		host = "127.0.0.1"
	}
	if (port == "") {
		port = 5353
	}
}
{
	original_line = $0

	if (/^#/) {
		# #
		# comments in user_rule.txt
	} else if (/^\!/) {
		# !
		# https://adblockplus.org/en/filters#comments
		# comments
	} else if (/^\[/) {
		# [
		# comments
	} else if (/^@@/) {
		# @@
		# https://adblockplus.org/en/filters#whitelist
	} else if (/^$/) {
		# Empty line
	} else if (/^\|\|/) {
		# ||
		# https://adblockplus.org/en/filters#anchors
		sub(/^\|\|/, "") # remove leading ||
		extract($0, original_line)
	} else if (/^\|/) {
		# |
		# https://adblockplus.org/en/filters#anchors
		sub(/^\|/, "") # removing leading |
		extract($0, original_line)
	} else if (/^\/.*\/$/) {
		# /.../
		# https://adblockplus.org/en/filters#regexps
		sub(/^\//, "") # remove leading /
		sub(/\/$/, "") # remove tailing /
		extract_regex($0, original_line)
	} else if (/^\./) {
		# start with dot
		extract($0, original_line)
	} else {
		extract($0, original_line)
	}
}
END {
	for (i = 1; i <= domain_count; i++) {
		printf "server=/.%s/%s#%d\n", domains[i], host, port | "sort | uniq"
	}
}

#!/usr/bin/awk -f

# Add domain name to global variable domains.
function add(domain) {
	domain_count = domain_count + 1
	domains[domain_count] = domain
}

# Extract domain name from non-regex line
function extract(line, original_line) {
	sub(/.*:\/\//, "", line) # remove everything till ://, such as http:// https://
	sub(/\/.*/, "", line)    # remove everything from /
	sub(/:.*/, "", line)     # remove everything from :
	sub(/\*/, "", line)      # remove *
	sub(/^\./, "", line)     # remove leading dot

	if (match(line, /([a-zA-Z0-9\-]+\.)+[a-zA-Z0-9\-]+/)) {
		add(line)
	} else {
		print "[WARN] <NR>" NR "</NR><original>" original_line "</original><extracted>" line "</extracted>" | "cat >&2"
	}
}

# Extract domain name from regex line
function extract_regex(line, original_line) {

	# Expand the lines like (aa|bb|cc) into multiple records
	pos = match(line, /\([a-zA-Z0-9\.\|]+\)/)
	if (pos != 0) {
		in_bracket = substr(line, RSTART + 1, RLENGTH - 2)
		n = split(in_bracket, arr, "|")
		for (i = 1; i <= n; i++) {
			expanded_line = line
			sub(/\([a-zA-Z0-9\.\|]+\)/, arr[i], expanded_line)
			extract_regex(expanded_line, original_line)
		}
	} else {
		sub(/.*:\\\/\\\//, "", line)    # remove everything till :\/\/ in regex, :// in plain text, such as http:// https://
		gsub(/\([^\)]+\)\*?/, "", line) # remove (...)*? such as ([^\/]+\.)
		gsub(/\[.*\]\+/, "", line)      # remove [...]
		sub(/\\\/.*/, "", line)         # remove everything from \/ in regex, / in plaint text
		gsub(/\\\./, ".", line)         # replace \. to .
		extract(line, original_line)
	}
}

BEGIN {
	"date \"+%Y-%m-%d %H:%M:%S\"" | getline now
	print "# gfw list ipset rules for dnsmasq"
	print "# updated on " now
	print "#"

	if (host == "") {
		host = "127.0.0.1"
	}
	if (port == "") {
		port = 5353
	}

	domain_count = 0
}
{
	original_line = $0

	if (/^#/) {
		# #
		# comments in user_rule.txt
	} else if (/^\!/) {
		# !
		# https://adblockplus.org/en/filters#comments
		# comments
	} else if (/^\[/) {
		# [
		# comments
	} else if (/^@@/) {
		# @@
		# https://adblockplus.org/en/filters#whitelist
	} else if (/^$/) {
		# Empty line
	} else if (/^\|\|/) {
		# ||
		# https://adblockplus.org/en/filters#anchors
		sub(/^\|\|/, "") # remove leading ||
		extract($0, original_line)
	} else if (/^\|/) {
		# |
		# https://adblockplus.org/en/filters#anchors
		sub(/^\|/, "") # removing leading |
		extract($0, original_line)
	} else if (/^\/.*\/$/) {
		# /.../
		# https://adblockplus.org/en/filters#regexps
		sub(/^\//, "") # remove leading /
		sub(/\/$/, "") # remove tailing /
		extract_regex($0, original_line)
	} else if (/^\./) {
		# start with dot
		extract($0, original_line)
	} else {
		extract($0, original_line)
	}
}
END {
	for (i = 1; i <= domain_count; i++) {
		printf "server=/.%s/%s#%d\n", domains[i], host, port | "sort | uniq"
	}
}


support for code

support for code

BEGIN {
  print "%TCIDATA{Version=5.00.0.2606}";
  print "%TCIDATA{LaTeXparent=0,0,classes.tex}";
  print "                      ";
  print "";
  print "%%%%% BEGINNING OF DOCUMENT BODY %%%%%";
  print "% html: Beginning of file: `clean.html'";
  print "% DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"";
  print "%  This is a (PRE) block.  Make sure it's left aligned or your toc title will be off. ";
  print "";
  quoting = 0;
  itemizing = 0;
  coding = 0;
}

END {
  print "% html: End of file: `clean.html'";
  print "";
  print "%%%%% END OF DOCUMENT BODY %%%%%";
  print "% In the future, we might want to put some additional data here, such";
  print "% as when the documentation was converted from wiki to TeX.";
  print "%";
}

## pragmas do not count
!coding && /\#labels/ {
  next;
}

## make sure that control sequences are always at the front
/ *{{{/ { sub(/ */, "") }
/ *}}}/ { sub(/ */, "") }
/ *=/ { sub(/ */, "") }

itemizing && !/^   *\*/ {
  print "\\end{itemize}";
  itemizing = 0;
}

quoting && /^  / {
  sub(/^  /, "");
  print;
  next;
}

quoting && !/^  / {
  print "\\end{quotation}";
  quoting = 0;
}

## empty lines do not count
!coding && /^ *$/ {
  next;
}

/`/ {
  line = $0;
  sub(/`/, "\\texttt{", line);
  sub(/`/, "}", line);
  $0 = line
}

/^==/ {
  sub(/^==/, "\\subsection*{");
  sub(/==/, "}");
  print;
  next;
}

/^=/ {
  sub(/^=/, "\\section*{");
  sub(/=/, "}");
  print;
  print "";
  print "\\label{f0}";
  next;
}

!itemizing && /^   *\*/ {
  print "\\begin{itemize}";
  itemizing = 1;
}

itemizing && /^   *\*/ {
  sub(/^   *\*/, "\\item");
  print;
  print "";
  next;
}

## tracking code

!coding && /^{{{/ {
  print "\\begin{verbatim}";
  coding = 1;
  next;
}

coding && /^}}}/ {
  print "\\end{verbatim}";
  coding = 0;
  next;
}

coding {
  sub(/^/, "{\\small ");
  print;
  print "}";
  next;
}

!coding && /^  / {
  print "\\begin{quotation}";
  quoting = 1;
  sub(/^  /, "");
  print;
  next;
}

{ print }

BEGIN {
  print "%TCIDATA{Version=5.00.0.2606}";
  print "%TCIDATA{LaTeXparent=0,0,classes.tex}";
  print "                      ";
  print "";
  print "%%%%% BEGINNING OF DOCUMENT BODY %%%%%";
  print "% html: Beginning of file: `clean.html'";
  print "% DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"";
  print "%  This is a (PRE) block.  Make sure it's left aligned or your toc title will be off. ";
  print "";
  quoting = 0;
  itemizing = 0;
}

END {
  print "% html: End of file: `clean.html'";
  print "";
  print "%%%%% END OF DOCUMENT BODY %%%%%";
  print "% In the future, we might want to put some additional data here, such";
  print "% as when the documentation was converted from wiki to TeX.";
  print "%";
}

## pragmas do not count
/\#labels/ {
  next;
}

itemizing && !/^   *\*/ {
  print "\\end{itemize}";
  itemizing = 0;
}

quoting && /^  / {
  sub(/^  /, "");
  print;
  next;
}

quoting && !/^  / {
  print "\\end{quotation}";
  quoting = 0;
}

## empty lines do not count
/^ *$/ {
  next;
}

/`/ {
  line = $0;
  sub(/`/, "\\texttt{", line);
  sub(/`/, "}", line);
  $0 = line
}

/==/ {
  sub(/==/, "\\subsection*{");
  sub(/==/, "}");
  print;
  next;
}

/=/ {
  sub(/=/, "\\section*{");
  sub(/=/, "}");
  print;
  print "";
  print "\\label{f0}";
  next;
}

!itemizing && /^   *\*/ {
  print "\\begin{itemize}";
  itemizing = 1;
}

itemizing && /^   *\*/ {
  sub(/^   *\*/, "\\item");
  print;
  print "";
  next;
}

/^  / {
  print "\\begin{quotation}";
  quoting = 1;
  sub(/^  /, "");
  print;
  next;
}

{ print }


checkpoint, mucking out old curie exceptions & adding new ones

#! /usr/bin/gawk -f

#  Reduce the subject and object of RDF triples (ntriples format)
#  down to their curie prefix (or literal object)
#  Reduce predicates to the specific term 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 (t-box) as opposed to
#  a data uri (a-box).

#  Post processing to augment predicate identifiers
#  with their labels seems to improve usefulness.

function usage(){
	print "usage: ntriple2dot.awk prefix_baseurl.yaml rdf.nt > dot.gv"
}

##########################################################
# 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 local identifier

# this may need to be called more than once since
# some identifiers may have embedded delimiters other uri use differently
function stripid(uri,  delim, char, max, c, l){
	# <_:blanknode> are not allowed in ntriples (but may happen anyway)
	if(0 < match(uri, /^_:|^https:\/\/monarchinitiative.org\/.well-known\/genid\//))
		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 (C-lang identifier rules)
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){
	u = uri
	# shorten till longest uri in curi map is found (or not)

	while(!(u in prefix) &&  length(u))
		u = stripid(substr(u,1,length(u)-1))
	if(u in prefix)
		return prefix[u]
	else{
		# printf("WARN  %s\n", uri) > "/dev/stderr"
		return simplify(uri)
	}
}

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

# fix curie namespace when redundant due to OBO  i.e RO:RO_123

function deoboify(curie,  a){
	split(curie, a , ":")
	if(match(a[2], a[1]"_") > 0){
		sub("_", ":", a[2]);
		curie=a[2]
	}
	return curie
}

BEGIN{
	# exceptions
	prefix["BNODE"]="BNODE"  # is a fixed point
	prefix["https://monarchinitiative.org/.well-known/genid"]="BNODE"
	prefix["https://archive.monarchinitiative.org/"]="MonarchArchive"
	############################################################
	# not expected to be added to curie map
	# in HPOA
	prefix["http://www.ncbi.nlm.nih.gov/bookshelf/br.fcgi?book=gene&part="]="NCBIBook"
	prefix["http://www.ncbi.nlm.nih.gov/books/NBK"]="NCBINBK"

	############################################################
	# Often re-visit whether these exceptions are still necessary
	# they may have been moved into the curie prefix mapping file
	# or addressed in a local translation table
    # https://raw.githubusercontent.com/monarch-initiative/dipper/master/dipper/curie_map.yaml

	# in mgi
	prefix["https://www.mousephenotype.org"]="IMPC"
	# in IMPC (not httpS  --- hmm all three IRI exist)
	prefix["http://www.mousephenotype.org"]="IMPC"
	# note in curie_map IMPC is:
	# http://www.mousephenotype.org/data/genes/

	# in panther
	# prefix["http://identifiers.org/wormbase/"]="WormBase"
	# note in curie_map WormBase is
	# 'https://www.wormbase.org/get?name='

	# various, transient?
    prefix["http://www.ncbi.nlm.nih.gov/gene/"]="NCBIGene"
    prefix["http://www.ncbi.nlm.nih.gov/genome/"]="NCBIGenome"
    prefix["http://www.ncbi.nlm.nih.gov/assembly?term="]="NCBIAssembly"
	# kegg
	prefix["http://www.genome.jp/kegg/pathway/map/map"]="KEGG-img"
	# in EOM
	prefix['https://elementsofmorphology.nih.gov/images/terms/']="EOM_IMG"

	# playing with the idea of a LOCAL identifier
    # not the same as a bnode in that tools won't rewrite identifier
	# and their IRI are unroutable, i.e in same machine (or local net)
	# this is motivated in part by not wanting to publish
	# urls to our own servers which go nowhere.
	prefix["https://127.0.0.1/.well-known/genid"]="BNODE"  # exists, phase out
	prefix["http://0.0.0.0/.well-known/genid"]="BNODE"     # prefer
	prefix["http://0.0.0.0/"]="LCL"	                       # ID halfway house

	# LCL's obvious down side is zero options for global collisions
	# best you can do is go the uuid which is ugly, or
	# belive your obscure but readable string _is_ a special snowflake
}

# main loop
# parse and stash the curie yaml file (first file)
# YAML format is tic delimited word (the curi prefix)
# a colon, whitespace
# 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

### subject predicate and object are all uri
(FNR != NR) && /^<[^>]*> <[^>]+> <[^>]+> \.$/ {
	s = contract(stripid(trim($1)))
	p =  final(trim($2))
	ns = contract(stripid(trim($2)))
	o = contract(stripid(trim($3)))
	edgelist[s,ns ":" p,o]++
	done[NR]=1
}
### subject & predicate are uri but the object is a literal
(FNR != NR) && /^<[^>]*> <[^>]*> "[^"]*".*\.$/ {
	s = contract(stripid(trim($1)))
	p = final(trim($2))
	ns = contract(stripid(trim($2)))
	edgelist[s, ns ":" p, "LITERAL"]++
	done[NR]=1
}
### subject is a bare blank node, predicate and object are uri
(FNR != NR) && /^_:[^ ]* <[^>]*> <[^>]*> \.$/ {
	# once our bnode syntax is uniform we may want more info out of it
	# s = contract(stripid($1))
	p =  final(trim($2))
	ns = contract(stripid(trim($2)))
	### Object (like subject)
	o = contract(stripid(trim($3)))
	edgelist["BNODE",ns ":" p,o]++
	done[NR]=1
}
### subject & predicate are uri & object is a bare blank node
(FNR != NR) && /^<[^>]*> <[^>]*> _:[^ ]* \.$/ {
	s = contract(stripid(trim($1)))
	p =  final(trim($2))
	ns = contract(stripid(trim($2)))
	#o = contract(stripid($3))
	edgelist[s,ns ":" p,"BNODE"]++
	done[NR]=1
}
### subject and object are a bare blank nodes, predicate is a uri
(FNR != NR) && /^_:[^ ]* <[^>]*> _:[^ ]* \.$/ {
	# s = contract(stripid($1))
	p =  final(trim($2))
	ns = contract(stripid(trim($2)))
	# o = contract(stripid($3))
	edgelist["BNODE",ns ":" p,"BNODE"]++
	done[NR]=1
}
### subject is a bare blank node, predicate is a uri & the object is a literal
(FNR != NR) && /^_:[^ ]* <[^>]*> "[^"]*".*\.$/ {
	# s = contract(stripid($1))
	p = final(trim($2))
	ns = contract(stripid(trim($2)))
	edgelist["BNODE", ns ":" p, "LITERAL"]++
	done[NR]=1
}

# print anything else so it makes itself known
(FNR != NR) && (done[NR]<1) && (NF>1){
	printf("ERROR? in %s at line %i:  %s\n",FILENAME,FNR,$0) > "/dev/stderr"
}

# output graphviz dot file, include edge counts
END{
	print "digraph {"
	print "rankdir=LR;"
	print "charset=\"utf-8\";"
	# sort the edges to facilitate future inter dot comparisons
	n=asorti(edgelist, sortlist)
	for (i=1; i<=n; i++) {
		edge=sortlist[i]
		split(edge ,spo, SUBSEP);
		print simplify(spo[1]) " -> " simplify(spo[3]) \
		" [label=\"" deoboify(spo[2]) " (" edgelist[edge] ")\"];"
	}
	print "LITERAL [shape=record];"
	print "labelloc=\"t\";"
	title = final(FILENAME)
	datestamp = strftime("%Y%m%d", systime())
	print "label=\"" substr(title,1,length(title)-3) " (" datestamp ")\";"
	print "}"
}

#! /usr/bin/gawk -f

#  Reduce the subject and object of RDF triples (ntriples format)
#  down to their curie prefix (or literal object)
#  Reduce predicates to the specific term 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 (t-box) as opposed to
#  a data uri (a-box).

#  Post processing to augment predicate identifiers
#  with their labels seems to improve usefulness.

function usage(){
	print "usage: ntriple2dot.awk prefix_baseurl.yaml rdf.nt > dot.gv"
}

##########################################################
# 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 local identifier

# this may need to be called more than once since
# some identifiers may have embedded delimiters other uri use differently
function stripid(uri,  delim, char, max, c, l){
	# <_:blanknode> are not allowed in ntriples (but may happen anyway)
	if(0 < match(uri, /^_:|^https:\/\/monarchinitiative.org\/.well-known\/genid\//))
		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 (C-lang identifier rules)
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){
	u = uri
	# shorten till longest uri in curi map is found (or not)

	while(!(u in prefix) &&  length(u))
		u = stripid(substr(u,1,length(u)-1))
	if(u in prefix)
		return prefix[u]
	else{
		# printf("WARN  %s\n", uri) > "/dev/stderr"
		return simplify(uri)
	}
}

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

# fix curie namespace when redundant due to OBO  i.e RO:RO_123

function deoboify(curie,  a){
	split(curie, a , ":")
	if(match(a[2], a[1]"_") > 0){
		sub("_", ":", a[2]);
		curie=a[2]
	}
	return curie
}

BEGIN{
	# exceptions
	prefix["BNODE"]="BNODE"  # is a fixed point
	prefix["https://monarchinitiative.org/.well-known/genid"]="BNODE"
	prefix["https_archive_monarchinitiative_org_"]="MonarchArchive"
	############################################################
	# Often re-visit whether these exceptions are still necessary
	# they may have been moved into the curie prefix mapping file
	# or addressed in a local translation table
    # https://raw.githubusercontent.com/monarch-initiative/dipper/master/dipper/curie_map.yaml

	# in mgi
	prefix["https://www.mousephenotype.org"]="IMPC"
	# in IMPC (not httpS)
	prefix["http://www.mousephenotype.org"]="IMPC"
	# note in curie_map IMPC is:
	# http://www.mousephenotype.org/data/genes/

	# in panther
	# prefix["http://identifiers.org/wormbase/"]="WormBase"
	# note in curie_map WormBase is
	# 'https://www.wormbase.org/get?name='

	# in GWAScatalog
	prefix["http://www.ncbi.nlm.nih.gov/SNP/"]="dbSNP"
	# note in curie_map dbSNP is
	# 'http://www.ncbi.nlm.nih.gov/projects/SNP/snp_ref.cgi?rs='

	# Ensembl  transient
	prefix["http://identifiers.org/ensembl/"]="ENSEMBL"
	# various, transient
    prefix["http://www.ncbi.nlm.nih.gov/gene/"]="NCBIGene"
	# kegg
	prefix["http://identifiers.org/ec-code/"]="EC"
	# ensembl
	prefix["http://identifiers.org/hgnc/HGNC:"]="HGNC"

	# playing with the idea of a LOCAL identifier
    # not the same as a bnode in that tools won't rewrite identifier
	# and their IRI are unroutable, i.e in same machine (or local net)
	# this is motivated in part by not wanting to publish
	# urls to our own servers which go nowhere.
	prefix["https://127.0.0.1/.well-known/genid"]="BNODE"  # exists, phase out
	prefix["http://0.0.0.0/.well-known/genid"]="BNODE"     # prefer
	prefix["http://0.0.0.0/"]="LCL"	                       # ID halfway house

	# LCL's obvious down side is zero options for global collisions
	# best you can do is go the uuid which is ugly, or
	# belive your obscure but readable string _is_ a special snowflake
}

# main loop
# parse and stash the curie yaml file (first file)
# YAML format is tic delimited word (the curi prefix)
# a colon, whitespace
# 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

### subject predicate and object are all uri
(FNR != NR) && /^<[^>]*> <[^>]+> <[^>]+> \.$/ {
	s = contract(stripid(trim($1)))
	p =  final(trim($2))
	ns = contract(stripid(trim($2)))
	o = contract(stripid(trim($3)))
	edgelist[s,ns ":" p,o]++
	done[NR]=1
}
### subject & predicate are uri but the object is a literal
(FNR != NR) && /^<[^>]*> <[^>]*> "[^"]*".*\.$/ {
	s = contract(stripid(trim($1)))
	p = final(trim($2))
	ns = contract(stripid(trim($2)))
	edgelist[s, ns ":" p, "LITERAL"]++
	done[NR]=1
}
### subject is a bare blank node, predicate and object are uri
(FNR != NR) && /^_:[^ ]* <[^>]*> <[^>]*> \.$/ {
	# once our bnode syntax is uniform we may want more info out of it
	# s = contract(stripid($1))
	p =  final(trim($2))
	ns = contract(stripid(trim($2)))
	### Object (like subject)
	o = contract(stripid(trim($3)))
	edgelist["BNODE",ns ":" p,o]++
	done[NR]=1
}
### subject & predicate are uri & object is a bare blank node
(FNR != NR) && /^<[^>]*> <[^>]*> _:[^ ]* \.$/ {
	s = contract(stripid(trim($1)))
	p =  final(trim($2))
	ns = contract(stripid(trim($2)))
	#o = contract(stripid($3))
	edgelist[s,ns ":" p,"BNODE"]++
	done[NR]=1
}
### subject and object are a bare blank nodes, predicate is a uri
(FNR != NR) && /^_:[^ ]* <[^>]*> _:[^ ]* \.$/ {
	# s = contract(stripid($1))
	p =  final(trim($2))
	ns = contract(stripid(trim($2)))
	# o = contract(stripid($3))
	edgelist["BNODE",ns ":" p,"BNODE"]++
	done[NR]=1
}
### subject is a bare blank node, predicate is a uri & the object is a literal
(FNR != NR) && /^_:[^ ]* <[^>]*> "[^"]*".*\.$/ {
	# s = contract(stripid($1))
	p = final(trim($2))
	ns = contract(stripid(trim($2)))
	edgelist["BNODE", ns ":" p, "LITERAL"]++
	done[NR]=1
}

# print anything else so it makes itself known
(FNR != NR) && (done[NR]<1) && (NF>1){
	printf("ERROR? in %s at line %i:  %s\n",FILENAME,FNR,$0) > "/dev/stderr"
}

# output graphviz dot file, include edge counts
END{
	print "digraph {"
	print "rankdir=LR;"
	print "charset=\"utf-8\";"
	# sort the edges to facilitate future inter dot comparisons
	n=asorti(edgelist, sortlist)
	for (i=1; i<=n; i++) {
		edge=sortlist[i]
		split(edge ,spo, SUBSEP);
		print simplify(spo[1]) " -> " simplify(spo[3]) \
		" [label=\"" deoboify(spo[2]) " (" edgelist[edge] ")\"];"
	}
	print "LITERAL [shape=record];"
	print "labelloc=\"t\";"
	title = final(FILENAME)
	datestamp = strftime("%Y%m%d", systime())
	print "label=\"" substr(title,1,length(title)-3) " (" datestamp ")\";"
	print "}"
}


Update generate_netbsd_ioctls.awk for NetBSD 8.99.25

Add dynamic detection of header files in /usr/include.
Handle "nvlist_ref_t" needed by npf(4) ioctl(2) operations.

git-svn-id: c199f293c43da69278bea8e88f92242bf3aa95f7@345715 91177308-0d34-0410-b5e6-96231b3b80d8

#!/usr/bin/awk -f

#===-- generate_netbsd_ioctls.awk ------------------------------------------===#
#
#                     The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
#
# This file is a generator of:
#  - include/sanitizer/sanitizer_interceptors_ioctl_netbsd.inc
#
# This script reads public headers from a NetBSD host.
#
#===------------------------------------------------------------------------===#

BEGIN {
  # harcode the script name
  script_name = "generate_netbsd_ioctls.awk"
  outputinc = "../lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc"

  # assert that we are in the directory with scripts
  in_utils = system("test -f " script_name " && exit 1 || exit 0")
  if (in_utils == 0) {
    usage()
  }

  # assert 0 argument passed
  if (ARGC != 1) {
    usage()
  }

  # accept overloading CLANGFORMAT from environment
  clangformat = "clang-format"
  if ("CLANGFORMAT" in ENVIRON) {
    clangformat = ENVIRON["CLANGFORMAT"]
  }

  # accept overloading ROOTDIR from environment
  rootdir = "/usr/include/"
  if ("ROOTDIR" in ENVIRON) {
    rootdir = ENVIRON["ROOTDIR"]
  }

  # detect and register files to detect ioctl() definitions
  ARGC = 1
  cmd = "find " rootdir " -type f -name '*.h'"
  while (cmd | getline) {
    ARGV[ARGC++] = $0
  }
  close(cmd)

  ioctl_table_max = 0
}

# Scan RCS ID
FNR == 1 {
  fname[ioctl_table_max] = substr(FILENAME, length(rootdir) + 1)
}

# _IO
/[^a-zA-Z0-9_]_IO[W]*[R]*[ ]*\(/ && $2 ~ /^[A-Z_]+$/ {
  if ($0 ~ /RAIDFRAME_GET_ACCTOTALS/ ||
      $0 ~ /ALTQATTACH/ ||
      $0 ~ /ALTQDETACH/ ||
      $0 ~ /ALTQENABLE/ ||
      $0 ~ /ALTQDISABLE/ ||
      $0 ~ /ALTQCLEAR/ ||
      $0 ~ /ALTQCONFIG/ ||
      $0 ~ /ALTQADDCLASS/ ||
      $0 ~ /ALTQMODCLASS/ ||
      $0 ~ /ALTQDELCLASS/ ||
      $0 ~ /ALTQADDFILTER/ ||
      $0 ~ /ALTQDELFILTER/ ||
      $0 ~ /ALTQGETSTATS/ ||
      $0 ~ /ALTQGETCNTR/ ||
      $0 ~ /HFSC_IF_ATTACH/ ||
      $0 ~ /HFSC_MOD_CLASS/ ||
      $0 ~ /HLCD_DISPCTL/ ||
      $0 ~ /HLCD_RESET/ ||
      $0 ~ /HLCD_CLEAR/ ||
      $0 ~ /HLCD_CURSOR_LEFT/ ||
      $0 ~ /HLCD_CURSOR_RIGHT/ ||
      $0 ~ /HLCD_GET_CURSOR_POS/ ||
      $0 ~ /HLCD_SET_CURSOR_POS/ ||
      $0 ~ /HLCD_GETC/ ||
      $0 ~ /HLCD_PUTC/ ||
      $0 ~ /HLCD_SHIFT_LEFT/ ||
      $0 ~ /HLCD_SHIFT_RIGHT/ ||
      $0 ~ /HLCD_HOME/ ||
      $0 ~ /HLCD_WRITE/ ||
      $0 ~ /HLCD_READ/ ||
      $0 ~ /HLCD_REDRAW/ ||
      $0 ~ /HLCD_WRITE_INST/ ||
      $0 ~ /HLCD_WRITE_DATA/ ||
      $0 ~ /HLCD_GET_INFO/ ||
      $0 ~ /HLCD_GET_CHIPNO/ ||
      $0 ~ /HLCD_SET_CHIPNO/ ||
      $0 ~ /RAIDFRAME_TEST_ACC/ ||
      $0 ~ /FBIOGINFO/ ||
      $0 ~ /FBIOSATTR/ ||
      $0 ~ /OBIOCDISK/ ||
      $0 ~ /OBIOCVOL/ ||
      $0 ~ /BIOCSORTIMEOUT/ ||
      $0 ~ /BIOCGORTIMEOUT/ ||
      $0 ~ /PPPIOCSPASS/ ||
      $0 ~ /PPPIOCSACTIVE/ ||
      $0 ~ /PPPIOCSIPASS/ ||
      $0 ~ /PPPIOCSOPASS/ ||
      $0 ~ /PPPIOCSIACTIVE/ ||
      $0 ~ /PPPIOCSOACTIVE/ ||
      $0 ~ /SIOCPROXY/ ||
      $0 ~ /SIOCXRAWATM/ ||
      $0 ~ /AGPIOC_RESERVE/ ||
      $0 ~ /AGPIOC_PROTECT/ ||
      $0 ~ /CDIOCREADSUBCHANNEL_BUF/ ||
      $0 ~ /CDIOREADTOCENTRIES_BUF/ ||
      $0 ~ /MMCGETDISCINFO/ ||
      $0 ~ /MMCGETTRACKINFO/ ||
      $0 ~ /MMCOP/ ||
      $0 ~ /MMCSETUPWRITEPARAMS/ ||
      $0 ~ /DIOCGPARTINFO/ ||
      $0 ~ /ODIOCGDINFO/ ||
      $0 ~ /ODIOCSDINFO/ ||
      $0 ~ /ODIOCWDINFO/ ||
      $0 ~ /ODIOCGDEFLABEL/ ||
      $0 ~ /GPIOPINREAD/ ||
      $0 ~ /GPIOPINWRITE/ ||
      $0 ~ /GPIOPINTOGGLE/ ||
      $0 ~ /GPIOPINCTL/ ||
      $0 ~ /GPIODETACH/ ||
      $0 ~ /SEQUENCER_PERCMODE/ ||
      $0 ~ /SEQUENCER_TESTMIDI/ ||
      $0 ~ /SEQUENCER_MIDI_INFO/ ||
      $0 ~ /SEQUENCER_ID/ ||
      $0 ~ /SEQUENCER_CONTROL/ ||
      $0 ~ /SEQUENCER_REMOVESAMPLE/ ||
      $0 ~ /EVTCHN_RESET/ ||
      $0 ~ /EVTCHN_BIND/ ||
      $0 ~ /EVTCHN_UNBIND/) {
    # broken entry, incomplete definition of the 3rd parameterm etc
    next
  }

  if ($0 ~ /APM_IOC_STANDBY/ ||
      $0 ~ /APM_IOC_SUSPEND/ ||
      $0 ~ /SCIOC_USE_ADF/ ||
      $0 ~ /SCBUSIOLLSCAN/ ||
      $0 ~ /UTOPPYIOCANCEL/ ||
      $0 ~ /JOY_GET_X_OFFSET/ ||
      $0 ~ /CHIOGPICKER/ ||
      $0 ~ /SLIOCGUNIT/ ||
      $0 ~ /SATIOSBUFSIZE/ ||
      $0 ~ /TUNSLMODE/ ||
      $0 ~ /CBQ_IF_ATTACH/ ||
      $0 ~ /CDNR_IF_ATTACH/ ||
      $0 ~ /RIO_IF_ATTACH/ ||
      $0 ~ /CBQ_IF_DETACH/ ||
      $0 ~ /HFSC_IF_DETACH/ ||
      $0 ~ /WFQ_IF_DETACH/ ||
      $0 ~ /RIO_IF_DETACH/ ||
      $0 ~ /FIFOQ_IF_DETACH/ ||
      $0 ~ /RED_IF_DETACH/ ||
      $0 ~ /CDNR_ENABLE/ ||
      $0 ~ /HFSC_ENABLE/ ||
      $0 ~ /WFQ_ENABLE/ ||
      $0 ~ /RIO_ENABLE/ ||
      $0 ~ /FIFOQ_ENABLE/ ||
      $0 ~ /RED_ENABLE/ ||
      $0 ~ /BLUE_ENABLE/ ||
      $0 ~ /CDNR_DISABLE/ ||
      $0 ~ /HFSC_DISABLE/ ||
      $0 ~ /WFQ_DISABLE/ ||
      $0 ~ /RIO_DISABLE/ ||
      $0 ~ /FIFOQ_DISABLE/ ||
      $0 ~ /PRIQ_DISABLE/ ||
      $0 ~ /CDNR_DEL_FILTER/ ||
      $0 ~ /JOBS_DEL_CLASS/ ||
      $0 ~ /JOBS_DEL_FILTER/ ||
      $0 ~ /JOBS_GETSTATS/ ||
      $0 ~ /WFQ_GET_STATS/ ||
      $0 ~ /CBQ_ADD_FILTER/ ||
      $0 ~ /HFSC_ADD_FILTER/ ||
      $0 ~ /JOBS_ADD_FILTER/ ||
      $0 ~ /RED_IF_ATTACH/ ||
      $0 ~ /FIFOQ_IF_ATTACH/ ||
      $0 ~ /BLUE_IF_DETACH/ ||
      $0 ~ /CBQ_DISABLE/ ||
      $0 ~ /RED_DISABLE/ ||
      $0 ~ /CBQ_CLEAR_HIERARCHY/ ||
      $0 ~ /HFSC_DEL_CLASS/ ||
      $0 ~ /PRIQ_IF_DETACH/ ||
      $0 ~ /PRIQ_ENABLE/ ||
      $0 ~ /WFQ_IF_ATTACH/ ||
      $0 ~ /POWER_IOC_GET_TYPE_WITH_LOSSAGE/ ||
      $0 ~ /HFSC_DEL_FILTER/) {
    # There are entries with duplicate codes.. disable the less used ones
    next
  }

  if ($2 in known) {
    # Avoid duplicates
    # There are entries compatible with K&R and ANSI preprocessor
    next
  }

  known[$2] = 1

  ioctl_name[ioctl_table_max] = $2

  split($3, a, "(")
  a3 = a[1]
  if (a3 ~ /_IO[ ]*$/) {
    ioctl_mode[ioctl_table_max] = "NONE"
  } else if (a3 ~ /_IOR[ ]*$/) {
    ioctl_mode[ioctl_table_max] = "WRITE"
  } else if (a3 ~ /_IOW[ ]*$/) {
    ioctl_mode[ioctl_table_max] = "READ"
  } else if (a3 ~ /_IOWR[ ]*$/) {
    ioctl_mode[ioctl_table_max] = "READWRITE"
  } else {
    print "Unknown mode, cannot parse: '" $3 "'"
  }

  # This !NONE check allows to skip some unparsable entries
  if (ioctl_mode[ioctl_table_max] != "NONE") {
    n = split($0, a, ",")
    if (n == 3) {
      gsub(/^[ ]+/, "", a[3])
      match(a[3], /[a-zA-Z0-9_* ]+/)
      type = get_type(substr(a[3], 0, RLENGTH))
      ioctl_type[ioctl_table_max] = type
    }
  }

  ioctl_table_max++
}

END {
  # empty files?
  if (NR < 1 && !abnormal_exit) {
    usage()
  }

  # Handle abnormal exit
  if (abnormal_exit) {
    exit(abnormal_exit)
  }

  # Generate sanitizer_interceptors_ioctl_netbsd.inc

  # open pipe
  cmd = clangformat " > " outputinc

  pcmd("//===-- sanitizer_interceptors_ioctl_netbsd.inc -----------------*- C++ -*-===//")
  pcmd("//")
  pcmd("//                     The LLVM Compiler Infrastructure")
  pcmd("//")
  pcmd("// This file is distributed under the University of Illinois Open Source")
  pcmd("// License. See LICENSE.TXT for details.")
  pcmd("//")
  pcmd("//===----------------------------------------------------------------------===//")
  pcmd("//")
  pcmd("// Ioctl handling in common sanitizer interceptors.")
  pcmd("//===----------------------------------------------------------------------===//")
  pcmd("")
  pcmd("#if SANITIZER_NETBSD")
  pcmd("")
  pcmd("#include \"sanitizer_flags.h\"")
  pcmd("")
  pcmd("struct ioctl_desc {")
  pcmd("  unsigned req;")
  pcmd("  // FIXME: support read+write arguments. Currently READWRITE and WRITE do the")
  pcmd("  // same thing.")
  pcmd("  // XXX: The declarations below may use WRITE instead of READWRITE, unless")
  pcmd("  // explicitly noted.")
  pcmd("  enum {")
  pcmd("    NONE,")
  pcmd("    READ,")
  pcmd("    WRITE,")
  pcmd("    READWRITE,")
  pcmd("    CUSTOM")
  pcmd("  } type : 3;")
  pcmd("  unsigned size : 29;")
  pcmd("  const char* name;")
  pcmd("};")
  pcmd("")
  pcmd("const unsigned ioctl_table_max = " ioctl_table_max ";")
  pcmd("static ioctl_desc ioctl_table[ioctl_table_max];")
  pcmd("static unsigned ioctl_table_size = 0;")
  pcmd("")
  pcmd("// This can not be declared as a global, because references to struct_*_sz")
  pcmd("// require a global initializer. And this table must be available before global")
  pcmd("// initializers are run.")
  pcmd("static void ioctl_table_fill() {")
  pcmd("#define _(rq, tp, sz)                                    \\")
  pcmd("  if (IOCTL_##rq != IOCTL_NOT_PRESENT) {                 \\")
  pcmd("    CHECK(ioctl_table_size < ioctl_table_max);           \\")
  pcmd("    ioctl_table[ioctl_table_size].req = IOCTL_##rq;      \\")
  pcmd("    ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \\")
  pcmd("    ioctl_table[ioctl_table_size].size = sz;             \\")
  pcmd("    ioctl_table[ioctl_table_size].name = #rq;            \\")
  pcmd("    ++ioctl_table_size;                                  \\")
  pcmd("  }")
  pcmd("")

  for (i = 0; i < ioctl_table_max; i++) {
    if (i in fname) {
      pcmd("  /* Entries from file: " fname[i] " */")
    }

    if (i in ioctl_type) {
      type = ioctl_type[i]
    } else {
      type = "0"
    }

    pcmd("  _(" ioctl_name[i] ", " ioctl_mode[i] "," type ");")
  }

  pcmd("#undef _")
  pcmd("}")
  pcmd("")
  pcmd("static bool ioctl_initialized = false;")
  pcmd("")
  pcmd("struct ioctl_desc_compare {")
  pcmd("  bool operator()(const ioctl_desc& left, const ioctl_desc& right) const {")
  pcmd("    return left.req < right.req;")
  pcmd("  }")
  pcmd("};")
  pcmd("")
  pcmd("static void ioctl_init() {")
  pcmd("  ioctl_table_fill();")
  pcmd("  Sort(ioctl_table, ioctl_table_size, ioctl_desc_compare());")
  pcmd("")
  pcmd("  bool bad = false;")
  pcmd("  for (unsigned i = 0; i < ioctl_table_size - 1; ++i) {")
  pcmd("    if (ioctl_table[i].req >= ioctl_table[i + 1].req) {")
  pcmd("      Printf(\"Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\\n\",")
  pcmd("             ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name,")
  pcmd("             ioctl_table[i + 1].name);")
  pcmd("      bad = true;")
  pcmd("    }")
  pcmd("  }")
  pcmd("")
  pcmd("  if (bad) Die();")
  pcmd("")
  pcmd("  ioctl_initialized = true;")
  pcmd("}")
  pcmd("")
  pcmd("static const ioctl_desc *ioctl_table_lookup(unsigned req) {")
  pcmd("  int left = 0;")
  pcmd("  int right = ioctl_table_size;")
  pcmd("  while (left < right) {")
  pcmd("    int mid = (left + right) / 2;")
  pcmd("    if (ioctl_table[mid].req < req)")
  pcmd("      left = mid + 1;")
  pcmd("    else")
  pcmd("      right = mid;")
  pcmd("  }")
  pcmd("  if (left == right && ioctl_table[left].req == req)")
  pcmd("    return ioctl_table + left;")
  pcmd("  else")
  pcmd("    return nullptr;")
  pcmd("}")
  pcmd("")
  pcmd("static bool ioctl_decode(unsigned req, ioctl_desc *desc) {")
  pcmd("  CHECK(desc);")
  pcmd("  desc->req = req;")
  pcmd("  desc->name = \"<DECODED_IOCTL>\";")
  pcmd("  desc->size = IOC_SIZE(req);")
  pcmd("  // Sanity check.")
  pcmd("  if (desc->size > 0xFFFF) return false;")
  pcmd("  unsigned dir = IOC_DIR(req);")
  pcmd("  switch (dir) {")
  pcmd("    case IOC_NONE:")
  pcmd("      desc->type = ioctl_desc::NONE;")
  pcmd("      break;")
  pcmd("    case IOC_READ | IOC_WRITE:")
  pcmd("      desc->type = ioctl_desc::READWRITE;")
  pcmd("      break;")
  pcmd("    case IOC_READ:")
  pcmd("      desc->type = ioctl_desc::WRITE;")
  pcmd("      break;")
  pcmd("    case IOC_WRITE:")
  pcmd("      desc->type = ioctl_desc::READ;")
  pcmd("      break;")
  pcmd("    default:")
  pcmd("      return false;")
  pcmd("  }")
  pcmd("  // Size can be 0 iff type is NONE.")
  pcmd("  if ((desc->type == IOC_NONE) != (desc->size == 0)) return false;")
  pcmd("  // Sanity check.")
  pcmd("  if (IOC_TYPE(req) == 0) return false;")
  pcmd("  return true;")
  pcmd("}")
  pcmd("")
  pcmd("static const ioctl_desc *ioctl_lookup(unsigned req) {")
  pcmd("  const ioctl_desc *desc = ioctl_table_lookup(req);")
  pcmd("  if (desc) return desc;")
  pcmd("")
  pcmd("  // Try stripping access size from the request id.")
  pcmd("  desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT));")
  pcmd("  // Sanity check: requests that encode access size are either read or write and")
  pcmd("  // have size of 0 in the table.")
  pcmd("  if (desc && desc->size == 0 &&")
  pcmd("      (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE ||")
  pcmd("       desc->type == ioctl_desc::READ))")
  pcmd("    return desc;")
  pcmd("  return nullptr;")
  pcmd("}")
  pcmd("")
  pcmd("static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,")
  pcmd("                             unsigned request, void *arg) {")
  pcmd("  if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) {")
  pcmd("    unsigned size = desc->size ? desc->size : IOC_SIZE(request);")
  pcmd("    COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size);")
  pcmd("  }")
  pcmd("  if (desc->type != ioctl_desc::CUSTOM)")
  pcmd("    return;")
  pcmd("  if (request == IOCTL_SIOCGIFCONF) {")
  pcmd("    struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;")
  pcmd("    COMMON_INTERCEPTOR_READ_RANGE(ctx, (char*)&ifc->ifc_len,")
  pcmd("                                  sizeof(ifc->ifc_len));")
  pcmd("  }")
  pcmd("}")
  pcmd("")
  pcmd("static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d,")
  pcmd("                              unsigned request, void *arg) {")
  pcmd("  if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) {")
  pcmd("    // FIXME: add verbose output")
  pcmd("    unsigned size = desc->size ? desc->size : IOC_SIZE(request);")
  pcmd("    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size);")
  pcmd("  }")
  pcmd("  if (desc->type != ioctl_desc::CUSTOM)")
  pcmd("    return;")
  pcmd("  if (request == IOCTL_SIOCGIFCONF) {")
  pcmd("    struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;")
  pcmd("    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len);")
  pcmd("  }")
  pcmd("}")
  pcmd("")
  pcmd("#endif // SANITIZER_NETBSD")

  close(cmd)
}

function usage()
{
  print "Usage: " script_name
  abnormal_exit = 1
  exit 1
}

function pcmd(string)
{
  print string | cmd
}

function get_type(string)
{
  if (string == "int") {
    return "sizeof(int)"
  } else if (string == "unsigned int" || string == "u_int" || string == "uint") {
    return "sizeof(unsigned int)"
  } else if (string == "long") {
    return "sizeof(long)"
  } else if (string == "unsigned long" || string == "u_long") {
    return "sizeof(unsigned long)"
  } else if (string == "short") {
    return "sizeof(short)"
  } else if (string == "unsigned short") {
    return "sizeof(unsigned short)"
  } else if (string == "char") {
    return "sizeof(char)"
  } else if (string == "signed char") {
    return "sizeof(signed char)"
  } else if (string == "unsigned char") {
    return "sizeof(unsigned char)"
  } else if (string == "uint8_t") {
    return "sizeof(u8)"
  } else if (string == "uint16_t") {
    return "sizeof(u16)"
  } else if (string == "u_int32_t" || string == "uint32_t") {
    return "sizeof(u32)"
  } else if (string ~ /\*$/) {
    return "sizeof(uptr)"
  } else if (string == "off_t") {
    return "sizeof(uptr)"
  } else if (string == "pid_t" || string == "kbd_t") {
    return "sizeof(int)"
  } else if (string == "daddr_t" || string == "dev_t") {
    return "sizeof(u64)"
  } else if (substr(string, 0, 7) == "struct " ) {
    gsub(/ /, "", string)
    return "struct_" substr(string, 7) "_sz"
  } else if (string == "scsireq_t") {
    return "struct_scsireq_sz"
  } else if (string == "tone_t") {
    return "struct_tone_sz"
  } else if (string == "union twe_statrequest") {
    return "union_twe_statrequest_sz"
  } else if (string == "usb_device_descriptor_t") {
    return "struct_usb_device_descriptor_sz"
  } else if (string == "v4l2_std_id") {
    return "sizeof(u64)"
  } else if (string == "vtmode_t") {
    return "struct_vt_mode_sz"
  } else if (string == "_old_mixer_info") {
    return "struct__old_mixer_info_sz"
  } else if (string == "agp_allocate") {
    return "struct__agp_allocate_sz"
  } else if (string == "agp_bind") {
    return "struct__agp_bind_sz"
  } else if (string == "agp_info") {
    return "struct__agp_info_sz"
  } else if (string == "agp_region") {
    return "struct__agp_region_sz"
  } else if (string == "agp_setup") {
    return "struct__agp_setup_sz"
  } else if (string == "agp_unbind") {
    return "struct__agp_unbind_sz"
  } else if (string == "atareq_t") {
    return "struct_atareq_sz"
  } else if (string == "cpustate_t") {
    return "struct_cpustate_sz"
  } else if (string == "dmx_caps_t") {
    return "struct_dmx_caps_sz"
  } else if (string == "dmx_source_t") {
    return "enum_dmx_source_sz"
  } else if (string == "dvd_authinfo") {
    return "union_dvd_authinfo_sz"
  } else if (string == "dvd_struct") {
    return "union_dvd_struct_sz"
  } else if (string == "enum v4l2_priority") {
    return "enum_v4l2_priority_sz"
  } else if (string == "envsys_basic_info_t") {
    return "struct_envsys_basic_info_sz"
  } else if (string == "envsys_tre_data_t") {
    return "struct_envsys_tre_data_sz"
  } else if (string == "ext_accm") {
    return "(8 * sizeof(u32))"
  } else if (string == "fe_sec_mini_cmd_t") {
    return "enum_fe_sec_mini_cmd_sz"
  } else if (string == "fe_sec_tone_mode_t") {
    return "enum_fe_sec_tone_mode_sz"
  } else if (string == "fe_sec_voltage_t") {
    return "enum_fe_sec_voltage_sz"
  } else if (string == "fe_status_t") {
    return "enum_fe_status_sz"
  } else if (string == "gdt_ctrt_t") {
    return "struct_gdt_ctrt_sz"
  } else if (string == "gdt_event_t") {
    return "struct_gdt_event_sz"
  } else if (string == "gdt_osv_t") {
    return "struct_gdt_osv_sz"
  } else if (string == "gdt_rescan_t") {
    return "struct_gdt_rescan_sz"
  } else if (string == "gdt_statist_t") {
    return "struct_gdt_statist_sz"
  } else if (string == "gdt_ucmd_t") {
    return "struct_gdt_ucmd_sz"
  } else if (string == "iscsi_conn_status_parameters_t") {
    return "struct_iscsi_conn_status_parameters_sz"
  } else if (string == "iscsi_get_version_parameters_t") {
    return "struct_iscsi_get_version_parameters_sz"
  } else if (string == "iscsi_iocommand_parameters_t") {
    return "struct_iscsi_iocommand_parameters_sz"
  } else if (string == "iscsi_login_parameters_t") {
    return "struct_iscsi_login_parameters_sz"
  } else if (string == "iscsi_logout_parameters_t") {
    return "struct_iscsi_logout_parameters_sz"
  } else if (string == "iscsi_register_event_parameters_t") {
    return "struct_iscsi_register_event_parameters_sz"
  } else if (string == "iscsi_remove_parameters_t") {
    return "struct_iscsi_remove_parameters_sz"
  } else if (string == "iscsi_send_targets_parameters_t") {
    return "struct_iscsi_send_targets_parameters_sz"
  } else if (string == "iscsi_set_node_name_parameters_t") {
    return "struct_iscsi_set_node_name_parameters_sz"
  } else if (string == "iscsi_wait_event_parameters_t") {
    return "struct_iscsi_wait_event_parameters_sz"
  } else if (string == "isp_stats_t") {
    return "struct_isp_stats_sz"
  } else if (string == "lsenable_t") {
    return "struct_lsenable_sz"
  } else if (string == "lsdisable_t") {
    return "struct_lsdisable_sz"
  } else if (string == "mixer_ctrl_t") {
    return "struct_mixer_ctrl_sz"
  } else if (string == "mixer_devinfo_t") {
    return "struct_mixer_devinfo_sz"
  } else if (string == "mpu_command_rec") {
    return "struct_mpu_command_rec_sz"
  } else if (string == "rndstat_t") {
    return "struct_rndstat_sz"
  } else if (string == "rndstat_name_t") {
    return "struct_rndstat_name_sz"
  } else if (string == "rndctl_t") {
    return "struct_rndctl_sz"
  } else if (string == "rnddata_t") {
    return "struct_rnddata_sz"
  } else if (string == "rndpoolstat_t") {
    return "struct_rndpoolstat_sz"
  } else if (string == "rndstat_est_t") {
    return "struct_rndstat_est_sz"
  } else if (string == "rndstat_est_name_t") {
    return "struct_rndstat_est_name_sz"
  } else if (string == "pps_params_t") {
    return "struct_pps_params_sz"
  } else if (string == "pps_info_t") {
    return "struct_pps_info_sz"
  } else if (string == "linedn_t") {
    return "(32 * sizeof(char))"
  } else if (string == "mixer_info") {
    return "struct_mixer_info_sz"
  } else if (string == "RF_SparetWait_t") {
    return "struct_RF_SparetWait_sz"
  } else if (string == "RF_ComponentLabel_t") {
    return "struct_RF_ComponentLabel_sz"
  } else if (string == "RF_SingleComponent_t") {
    return "struct_RF_SingleComponent_sz"
  } else if (string == "RF_ProgressInfo_t") {
    return "struct_RF_ProgressInfo_sz"
  } else if (string == "nvlist_ref_t") {
    return "struct_nvlist_ref_sz"
  } else {
    print "Unrecognized entry: " string
    print "Aborting"
    abnormal_exit = 1
    exit 1
  }

  return string
}

#!/usr/bin/awk -f

#===-- generate_netbsd_ioctls.awk ------------------------------------------===#
#
#                     The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
#
# This file is a generator of:
#  - include/sanitizer/sanitizer_interceptors_ioctl_netbsd.inc
#
# This script reads public headers from a NetBSD host.
#
#===------------------------------------------------------------------------===#

BEGIN {
  # harcode the script name
  script_name = "generate_netbsd_ioctls.awk"
  outputinc = "../lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc"

  # assert that we are in the directory with scripts
  in_utils = system("test -f " script_name " && exit 1 || exit 0")
  if (in_utils == 0) {
    usage()
  }

  # assert 0 argument passed
  if (ARGC != 1) {
    usage()
  }

  # accept overloading CLANGFORMAT from environment
  clangformat = "clang-format"
  if ("CLANGFORMAT" in ENVIRON) {
    clangformat = ENVIRON["CLANGFORMAT"]
  }

  # accept overloading ROOTDIR from environment
  rootdir = "/usr/include/"
  if ("ROOTDIR" in ENVIRON) {
    rootdir = ENVIRON["ROOTDIR"]
  }

  # hardcode list of headers with ioctl(2) entries
  # List generated manually with the following script:
  #   for w in `find /usr/include/ -type f -name '*.h' -exec echo {} \;`; \
  #   do awk '/[^a-zA-Z0-9_]_IO[W]*[R]*[ ]*\(/ && $2 ~ /^[A-Z_]+$/ {got=1} END{if(got) {print ARGV[1]}}' $w; \
  #   done|awk '{print "  ARGV[ARGC++] = rootdir \"" substr($0, 14) "\""}'

  ARGV[ARGC++] = rootdir "altq/altq_afmap.h"
  ARGV[ARGC++] = rootdir "altq/altq.h"
  ARGV[ARGC++] = rootdir "altq/altq_blue.h"
  ARGV[ARGC++] = rootdir "altq/altq_cbq.h"
  ARGV[ARGC++] = rootdir "altq/altq_cdnr.h"
  ARGV[ARGC++] = rootdir "altq/altq_fifoq.h"
  ARGV[ARGC++] = rootdir "altq/altq_hfsc.h"
  ARGV[ARGC++] = rootdir "altq/altq_jobs.h"
  ARGV[ARGC++] = rootdir "altq/altq_priq.h"
  ARGV[ARGC++] = rootdir "altq/altq_red.h"
  ARGV[ARGC++] = rootdir "altq/altq_rio.h"
  ARGV[ARGC++] = rootdir "altq/altq_wfq.h"
  ARGV[ARGC++] = rootdir "crypto/cryptodev.h"
  ARGV[ARGC++] = rootdir "dev/apm/apmio.h"
  ARGV[ARGC++] = rootdir "dev/dm/netbsd-dm.h"
  ARGV[ARGC++] = rootdir "dev/dmover/dmover_io.h"
  ARGV[ARGC++] = rootdir "dev/dtv/dtvio_demux.h"
  ARGV[ARGC++] = rootdir "dev/dtv/dtvio_frontend.h"
  ARGV[ARGC++] = rootdir "dev/filemon/filemon.h"
  ARGV[ARGC++] = rootdir "dev/hdaudio/hdaudioio.h"
  ARGV[ARGC++] = rootdir "dev/hdmicec/hdmicecio.h"
  ARGV[ARGC++] = rootdir "dev/hpc/hpcfbio.h"
  ARGV[ARGC++] = rootdir "dev/i2o/iopio.h"
  ARGV[ARGC++] = rootdir "dev/ic/athioctl.h"
  ARGV[ARGC++] = rootdir "dev/ic/bt8xx.h"
  ARGV[ARGC++] = rootdir "dev/ic/hd44780var.h"
  ARGV[ARGC++] = rootdir "dev/ic/icp_ioctl.h"
  ARGV[ARGC++] = rootdir "dev/ic/isp_ioctl.h"
  ARGV[ARGC++] = rootdir "dev/ic/mlxio.h"
  ARGV[ARGC++] = rootdir "dev/ic/nvmeio.h"
  ARGV[ARGC++] = rootdir "dev/ir/irdaio.h"
  ARGV[ARGC++] = rootdir "dev/isa/satlinkio.h"
  ARGV[ARGC++] = rootdir "dev/isa/isvio.h"
  ARGV[ARGC++] = rootdir "dev/isa/wtreg.h"
  ARGV[ARGC++] = rootdir "dev/iscsi/iscsi_ioctl.h"
  ARGV[ARGC++] = rootdir "dev/ofw/openfirmio.h"
  ARGV[ARGC++] = rootdir "dev/pci/amrio.h"
  ARGV[ARGC++] = rootdir "dev/pci/mlyio.h"
  ARGV[ARGC++] = rootdir "dev/pci/pciio.h"
  ARGV[ARGC++] = rootdir "dev/pci/tweio.h"
  ARGV[ARGC++] = rootdir "dev/pcmcia/if_cnwioctl.h"
  ARGV[ARGC++] = rootdir "dev/pcmcia/if_rayreg.h"
  ARGV[ARGC++] = rootdir "dev/raidframe/raidframeio.h"
  ARGV[ARGC++] = rootdir "dev/sbus/mbppio.h"
  ARGV[ARGC++] = rootdir "dev/scsipi/ses.h"
  ARGV[ARGC++] = rootdir "dev/sun/disklabel.h"
  ARGV[ARGC++] = rootdir "dev/sun/fbio.h"
  ARGV[ARGC++] = rootdir "dev/sun/kbio.h"
  ARGV[ARGC++] = rootdir "dev/sun/vuid_event.h"
  ARGV[ARGC++] = rootdir "dev/tc/sticio.h"
  ARGV[ARGC++] = rootdir "dev/usb/ukyopon.h"
  ARGV[ARGC++] = rootdir "dev/usb/urio.h"
  ARGV[ARGC++] = rootdir "dev/usb/usb.h"
  ARGV[ARGC++] = rootdir "dev/usb/utoppy.h"
  ARGV[ARGC++] = rootdir "dev/vme/xio.h"
  ARGV[ARGC++] = rootdir "dev/wscons/wsdisplay_usl_io.h"
  ARGV[ARGC++] = rootdir "dev/wscons/wsconsio.h"
  ARGV[ARGC++] = rootdir "dev/biovar.h"
  ARGV[ARGC++] = rootdir "dev/md.h"
  ARGV[ARGC++] = rootdir "dev/ccdvar.h"
  ARGV[ARGC++] = rootdir "dev/cgdvar.h"
  ARGV[ARGC++] = rootdir "dev/fssvar.h"
  ARGV[ARGC++] = rootdir "dev/bluetooth/btdev.h"
  ARGV[ARGC++] = rootdir "dev/bluetooth/btsco.h"
  ARGV[ARGC++] = rootdir "dev/kttcpio.h"
  ARGV[ARGC++] = rootdir "dev/lockstat.h"
  ARGV[ARGC++] = rootdir "dev/vndvar.h"
  ARGV[ARGC++] = rootdir "dev/spkrio.h"
  ARGV[ARGC++] = rootdir "net/bpf.h"
  ARGV[ARGC++] = rootdir "net/if_atm.h"
  ARGV[ARGC++] = rootdir "net/if_gre.h"
  ARGV[ARGC++] = rootdir "net/if_ppp.h"
  ARGV[ARGC++] = rootdir "net/npf.h"
  ARGV[ARGC++] = rootdir "net/if_pppoe.h"
  ARGV[ARGC++] = rootdir "net/if_sppp.h"
  ARGV[ARGC++] = rootdir "net/if_srt.h"
  ARGV[ARGC++] = rootdir "net/if_tap.h"
  ARGV[ARGC++] = rootdir "net/if_tun.h"
  ARGV[ARGC++] = rootdir "net/pfvar.h"
  ARGV[ARGC++] = rootdir "net/slip.h"
  ARGV[ARGC++] = rootdir "netbt/hci.h"
  ARGV[ARGC++] = rootdir "netinet/ip_nat.h"
  ARGV[ARGC++] = rootdir "netinet/ip_proxy.h"
  ARGV[ARGC++] = rootdir "netinet6/in6_var.h"
  ARGV[ARGC++] = rootdir "netnatm/natm.h"
  ARGV[ARGC++] = rootdir "netsmb/smb_dev.h"
  ARGV[ARGC++] = rootdir "sys/agpio.h"
  ARGV[ARGC++] = rootdir "sys/audioio.h"
  ARGV[ARGC++] = rootdir "sys/ataio.h"
  ARGV[ARGC++] = rootdir "sys/cdio.h"
  ARGV[ARGC++] = rootdir "sys/chio.h"
  ARGV[ARGC++] = rootdir "sys/clockctl.h"
  ARGV[ARGC++] = rootdir "sys/cpuio.h"
  ARGV[ARGC++] = rootdir "sys/dkio.h"
  ARGV[ARGC++] = rootdir "sys/drvctlio.h"
  ARGV[ARGC++] = rootdir "sys/dvdio.h"
  ARGV[ARGC++] = rootdir "sys/envsys.h"
  ARGV[ARGC++] = rootdir "sys/event.h"
  ARGV[ARGC++] = rootdir "sys/fdio.h"
  ARGV[ARGC++] = rootdir "sys/filio.h"
  ARGV[ARGC++] = rootdir "sys/gpio.h"
  ARGV[ARGC++] = rootdir "sys/ioctl.h"
  ARGV[ARGC++] = rootdir "sys/ioctl_compat.h"
  ARGV[ARGC++] = rootdir "sys/joystick.h"
  ARGV[ARGC++] = rootdir "sys/ksyms.h"
  ARGV[ARGC++] = rootdir "sys/lua.h"
  ARGV[ARGC++] = rootdir "sys/midiio.h"
  ARGV[ARGC++] = rootdir "sys/mtio.h"
  ARGV[ARGC++] = rootdir "sys/power.h"
  ARGV[ARGC++] = rootdir "sys/radioio.h"
  ARGV[ARGC++] = rootdir "sys/rndio.h"
  ARGV[ARGC++] = rootdir "sys/scanio.h"
  ARGV[ARGC++] = rootdir "sys/scsiio.h"
  ARGV[ARGC++] = rootdir "sys/sockio.h"
  ARGV[ARGC++] = rootdir "sys/timepps.h"
  ARGV[ARGC++] = rootdir "sys/ttycom.h"
  ARGV[ARGC++] = rootdir "sys/verified_exec.h"
  ARGV[ARGC++] = rootdir "sys/videoio.h"
  ARGV[ARGC++] = rootdir "sys/wdog.h"
  ARGV[ARGC++] = rootdir "soundcard.h"
  ARGV[ARGC++] = rootdir "xen/xenio.h"

  ioctl_table_max = 0
}

# Scan RCS ID
FNR == 1 {
  fname[ioctl_table_max] = substr(FILENAME, length(rootdir) + 1)
}

# _IO
/[^a-zA-Z0-9_]_IO[W]*[R]*[ ]*\(/ && $2 ~ /^[A-Z_]+$/ {
  if ($0 ~ /RAIDFRAME_GET_ACCTOTALS/ ||
      $0 ~ /ALTQATTACH/ ||
      $0 ~ /ALTQDETACH/ ||
      $0 ~ /ALTQENABLE/ ||
      $0 ~ /ALTQDISABLE/ ||
      $0 ~ /ALTQCLEAR/ ||
      $0 ~ /ALTQCONFIG/ ||
      $0 ~ /ALTQADDCLASS/ ||
      $0 ~ /ALTQMODCLASS/ ||
      $0 ~ /ALTQDELCLASS/ ||
      $0 ~ /ALTQADDFILTER/ ||
      $0 ~ /ALTQDELFILTER/ ||
      $0 ~ /ALTQGETSTATS/ ||
      $0 ~ /ALTQGETCNTR/ ||
      $0 ~ /HFSC_IF_ATTACH/ ||
      $0 ~ /HFSC_MOD_CLASS/ ||
      $0 ~ /HLCD_DISPCTL/ ||
      $0 ~ /HLCD_RESET/ ||
      $0 ~ /HLCD_CLEAR/ ||
      $0 ~ /HLCD_CURSOR_LEFT/ ||
      $0 ~ /HLCD_CURSOR_RIGHT/ ||
      $0 ~ /HLCD_GET_CURSOR_POS/ ||
      $0 ~ /HLCD_SET_CURSOR_POS/ ||
      $0 ~ /HLCD_GETC/ ||
      $0 ~ /HLCD_PUTC/ ||
      $0 ~ /HLCD_SHIFT_LEFT/ ||
      $0 ~ /HLCD_SHIFT_RIGHT/ ||
      $0 ~ /HLCD_HOME/ ||
      $0 ~ /HLCD_WRITE/ ||
      $0 ~ /HLCD_READ/ ||
      $0 ~ /HLCD_REDRAW/ ||
      $0 ~ /HLCD_WRITE_INST/ ||
      $0 ~ /HLCD_WRITE_DATA/ ||
      $0 ~ /HLCD_GET_INFO/ ||
      $0 ~ /HLCD_GET_CHIPNO/ ||
      $0 ~ /HLCD_SET_CHIPNO/ ||
      $0 ~ /RAIDFRAME_TEST_ACC/ ||
      $0 ~ /FBIOGINFO/ ||
      $0 ~ /FBIOSATTR/ ||
      $0 ~ /OBIOCDISK/ ||
      $0 ~ /OBIOCVOL/ ||
      $0 ~ /BIOCSORTIMEOUT/ ||
      $0 ~ /BIOCGORTIMEOUT/ ||
      $0 ~ /PPPIOCSPASS/ ||
      $0 ~ /PPPIOCSACTIVE/ ||
      $0 ~ /PPPIOCSIPASS/ ||
      $0 ~ /PPPIOCSOPASS/ ||
      $0 ~ /PPPIOCSIACTIVE/ ||
      $0 ~ /PPPIOCSOACTIVE/ ||
      $0 ~ /SIOCPROXY/ ||
      $0 ~ /SIOCXRAWATM/ ||
      $0 ~ /AGPIOC_RESERVE/ ||
      $0 ~ /AGPIOC_PROTECT/ ||
      $0 ~ /CDIOCREADSUBCHANNEL_BUF/ ||
      $0 ~ /CDIOREADTOCENTRIES_BUF/ ||
      $0 ~ /MMCGETDISCINFO/ ||
      $0 ~ /MMCGETTRACKINFO/ ||
      $0 ~ /MMCOP/ ||
      $0 ~ /MMCSETUPWRITEPARAMS/ ||
      $0 ~ /DIOCGPARTINFO/ ||
      $0 ~ /ODIOCGDINFO/ ||
      $0 ~ /ODIOCSDINFO/ ||
      $0 ~ /ODIOCWDINFO/ ||
      $0 ~ /ODIOCGDEFLABEL/ ||
      $0 ~ /GPIOPINREAD/ ||
      $0 ~ /GPIOPINWRITE/ ||
      $0 ~ /GPIOPINTOGGLE/ ||
      $0 ~ /GPIOPINCTL/ ||
      $0 ~ /GPIODETACH/ ||
      $0 ~ /SEQUENCER_PERCMODE/ ||
      $0 ~ /SEQUENCER_TESTMIDI/ ||
      $0 ~ /SEQUENCER_MIDI_INFO/ ||
      $0 ~ /SEQUENCER_ID/ ||
      $0 ~ /SEQUENCER_CONTROL/ ||
      $0 ~ /SEQUENCER_REMOVESAMPLE/ ||
      $0 ~ /EVTCHN_RESET/ ||
      $0 ~ /EVTCHN_BIND/ ||
      $0 ~ /EVTCHN_UNBIND/) {
    # broken entry, incomplete definition of the 3rd parameterm etc
    next
  }

  if ($0 ~ /APM_IOC_STANDBY/ ||
      $0 ~ /APM_IOC_SUSPEND/ ||
      $0 ~ /SCIOC_USE_ADF/ ||
      $0 ~ /SCBUSIOLLSCAN/ ||
      $0 ~ /UTOPPYIOCANCEL/ ||
      $0 ~ /JOY_GET_X_OFFSET/ ||
      $0 ~ /CHIOGPICKER/ ||
      $0 ~ /SLIOCGUNIT/ ||
      $0 ~ /SATIOSBUFSIZE/ ||
      $0 ~ /TUNSLMODE/ ||
      $0 ~ /CBQ_IF_ATTACH/ ||
      $0 ~ /CDNR_IF_ATTACH/ ||
      $0 ~ /RIO_IF_ATTACH/ ||
      $0 ~ /CBQ_IF_DETACH/ ||
      $0 ~ /HFSC_IF_DETACH/ ||
      $0 ~ /WFQ_IF_DETACH/ ||
      $0 ~ /RIO_IF_DETACH/ ||
      $0 ~ /FIFOQ_IF_DETACH/ ||
      $0 ~ /RED_IF_DETACH/ ||
      $0 ~ /CDNR_ENABLE/ ||
      $0 ~ /HFSC_ENABLE/ ||
      $0 ~ /WFQ_ENABLE/ ||
      $0 ~ /RIO_ENABLE/ ||
      $0 ~ /FIFOQ_ENABLE/ ||
      $0 ~ /RED_ENABLE/ ||
      $0 ~ /BLUE_ENABLE/ ||
      $0 ~ /CDNR_DISABLE/ ||
      $0 ~ /HFSC_DISABLE/ ||
      $0 ~ /WFQ_DISABLE/ ||
      $0 ~ /RIO_DISABLE/ ||
      $0 ~ /FIFOQ_DISABLE/ ||
      $0 ~ /PRIQ_DISABLE/ ||
      $0 ~ /CDNR_DEL_FILTER/ ||
      $0 ~ /JOBS_DEL_CLASS/ ||
      $0 ~ /JOBS_DEL_FILTER/ ||
      $0 ~ /JOBS_GETSTATS/ ||
      $0 ~ /WFQ_GET_STATS/ ||
      $0 ~ /CBQ_ADD_FILTER/ ||
      $0 ~ /HFSC_ADD_FILTER/ ||
      $0 ~ /JOBS_ADD_FILTER/ ||
      $0 ~ /RED_IF_ATTACH/ ||
      $0 ~ /FIFOQ_IF_ATTACH/ ||
      $0 ~ /BLUE_IF_DETACH/ ||
      $0 ~ /CBQ_DISABLE/ ||
      $0 ~ /RED_DISABLE/ ||
      $0 ~ /CBQ_CLEAR_HIERARCHY/ ||
      $0 ~ /HFSC_DEL_CLASS/ ||
      $0 ~ /PRIQ_IF_DETACH/ ||
      $0 ~ /PRIQ_ENABLE/ ||
      $0 ~ /WFQ_IF_ATTACH/ ||
      $0 ~ /POWER_IOC_GET_TYPE_WITH_LOSSAGE/ ||
      $0 ~ /HFSC_DEL_FILTER/) {
    # There are entries with duplicate codes.. disable the less used ones
    next
  }

  if ($2 in known) {
    # Avoid duplicates
    # There are entries compatible with K&R and ANSI preprocessor
    next
  }

  known[$2] = 1

  ioctl_name[ioctl_table_max] = $2

  split($3, a, "(")
  a3 = a[1]
  if (a3 ~ /_IO[ ]*$/) {
    ioctl_mode[ioctl_table_max] = "NONE"
  } else if (a3 ~ /_IOR[ ]*$/) {
    ioctl_mode[ioctl_table_max] = "WRITE"
  } else if (a3 ~ /_IOW[ ]*$/) {
    ioctl_mode[ioctl_table_max] = "READ"
  } else if (a3 ~ /_IOWR[ ]*$/) {
    ioctl_mode[ioctl_table_max] = "READWRITE"
  } else {
    print "Unknown mode, cannot parse: '" $3 "'"
  }

  # This !NONE check allows to skip some unparsable entries
  if (ioctl_mode[ioctl_table_max] != "NONE") {
    n = split($0, a, ",")
    if (n == 3) {
      gsub(/^[ ]+/, "", a[3])
      match(a[3], /[a-zA-Z0-9_* ]+/)
      type = get_type(substr(a[3], 0, RLENGTH))
      ioctl_type[ioctl_table_max] = type
    }
  }

  ioctl_table_max++
}

END {
  # empty files?
  if (NR < 1 && !abnormal_exit) {
    usage()
  }

  # Handle abnormal exit
  if (abnormal_exit) {
    exit(abnormal_exit)
  }

  # Generate sanitizer_interceptors_ioctl_netbsd.inc

  # open pipe
  cmd = clangformat " > " outputinc

  pcmd("//===-- sanitizer_interceptors_ioctl_netbsd.inc -----------------*- C++ -*-===//")
  pcmd("//")
  pcmd("//                     The LLVM Compiler Infrastructure")
  pcmd("//")
  pcmd("// This file is distributed under the University of Illinois Open Source")
  pcmd("// License. See LICENSE.TXT for details.")
  pcmd("//")
  pcmd("//===----------------------------------------------------------------------===//")
  pcmd("//")
  pcmd("// Ioctl handling in common sanitizer interceptors.")
  pcmd("//===----------------------------------------------------------------------===//")
  pcmd("")
  pcmd("#if SANITIZER_NETBSD")
  pcmd("")
  pcmd("#include \"sanitizer_flags.h\"")
  pcmd("")
  pcmd("struct ioctl_desc {")
  pcmd("  unsigned req;")
  pcmd("  // FIXME: support read+write arguments. Currently READWRITE and WRITE do the")
  pcmd("  // same thing.")
  pcmd("  // XXX: The declarations below may use WRITE instead of READWRITE, unless")
  pcmd("  // explicitly noted.")
  pcmd("  enum {")
  pcmd("    NONE,")
  pcmd("    READ,")
  pcmd("    WRITE,")
  pcmd("    READWRITE,")
  pcmd("    CUSTOM")
  pcmd("  } type : 3;")
  pcmd("  unsigned size : 29;")
  pcmd("  const char* name;")
  pcmd("};")
  pcmd("")
  pcmd("const unsigned ioctl_table_max = " ioctl_table_max ";")
  pcmd("static ioctl_desc ioctl_table[ioctl_table_max];")
  pcmd("static unsigned ioctl_table_size = 0;")
  pcmd("")
  pcmd("// This can not be declared as a global, because references to struct_*_sz")
  pcmd("// require a global initializer. And this table must be available before global")
  pcmd("// initializers are run.")
  pcmd("static void ioctl_table_fill() {")
  pcmd("#define _(rq, tp, sz)                                    \\")
  pcmd("  if (IOCTL_##rq != IOCTL_NOT_PRESENT) {                 \\")
  pcmd("    CHECK(ioctl_table_size < ioctl_table_max);           \\")
  pcmd("    ioctl_table[ioctl_table_size].req = IOCTL_##rq;      \\")
  pcmd("    ioctl_table[ioctl_table_size].type = ioctl_desc::tp; \\")
  pcmd("    ioctl_table[ioctl_table_size].size = sz;             \\")
  pcmd("    ioctl_table[ioctl_table_size].name = #rq;            \\")
  pcmd("    ++ioctl_table_size;                                  \\")
  pcmd("  }")
  pcmd("")

  for (i = 0; i < ioctl_table_max; i++) {
    if (i in fname) {
      pcmd("  /* Entries from file: " fname[i] " */")
    }

    if (i in ioctl_type) {
      type = ioctl_type[i]
    } else {
      type = "0"
    }

    pcmd("  _(" ioctl_name[i] ", " ioctl_mode[i] "," type ");")
  }

  pcmd("#undef _")
  pcmd("}")
  pcmd("")
  pcmd("static bool ioctl_initialized = false;")
  pcmd("")
  pcmd("struct ioctl_desc_compare {")
  pcmd("  bool operator()(const ioctl_desc& left, const ioctl_desc& right) const {")
  pcmd("    return left.req < right.req;")
  pcmd("  }")
  pcmd("};")
  pcmd("")
  pcmd("static void ioctl_init() {")
  pcmd("  ioctl_table_fill();")
  pcmd("  Sort(ioctl_table, ioctl_table_size, ioctl_desc_compare());")
  pcmd("")
  pcmd("  bool bad = false;")
  pcmd("  for (unsigned i = 0; i < ioctl_table_size - 1; ++i) {")
  pcmd("    if (ioctl_table[i].req >= ioctl_table[i + 1].req) {")
  pcmd("      Printf(\"Duplicate or unsorted ioctl request id %x >= %x (%s vs %s)\\n\",")
  pcmd("             ioctl_table[i].req, ioctl_table[i + 1].req, ioctl_table[i].name,")
  pcmd("             ioctl_table[i + 1].name);")
  pcmd("      bad = true;")
  pcmd("    }")
  pcmd("  }")
  pcmd("")
  pcmd("  if (bad) Die();")
  pcmd("")
  pcmd("  ioctl_initialized = true;")
  pcmd("}")
  pcmd("")
  pcmd("static const ioctl_desc *ioctl_table_lookup(unsigned req) {")
  pcmd("  int left = 0;")
  pcmd("  int right = ioctl_table_size;")
  pcmd("  while (left < right) {")
  pcmd("    int mid = (left + right) / 2;")
  pcmd("    if (ioctl_table[mid].req < req)")
  pcmd("      left = mid + 1;")
  pcmd("    else")
  pcmd("      right = mid;")
  pcmd("  }")
  pcmd("  if (left == right && ioctl_table[left].req == req)")
  pcmd("    return ioctl_table + left;")
  pcmd("  else")
  pcmd("    return nullptr;")
  pcmd("}")
  pcmd("")
  pcmd("static bool ioctl_decode(unsigned req, ioctl_desc *desc) {")
  pcmd("  CHECK(desc);")
  pcmd("  desc->req = req;")
  pcmd("  desc->name = \"<DECODED_IOCTL>\";")
  pcmd("  desc->size = IOC_SIZE(req);")
  pcmd("  // Sanity check.")
  pcmd("  if (desc->size > 0xFFFF) return false;")
  pcmd("  unsigned dir = IOC_DIR(req);")
  pcmd("  switch (dir) {")
  pcmd("    case IOC_NONE:")
  pcmd("      desc->type = ioctl_desc::NONE;")
  pcmd("      break;")
  pcmd("    case IOC_READ | IOC_WRITE:")
  pcmd("      desc->type = ioctl_desc::READWRITE;")
  pcmd("      break;")
  pcmd("    case IOC_READ:")
  pcmd("      desc->type = ioctl_desc::WRITE;")
  pcmd("      break;")
  pcmd("    case IOC_WRITE:")
  pcmd("      desc->type = ioctl_desc::READ;")
  pcmd("      break;")
  pcmd("    default:")
  pcmd("      return false;")
  pcmd("  }")
  pcmd("  // Size can be 0 iff type is NONE.")
  pcmd("  if ((desc->type == IOC_NONE) != (desc->size == 0)) return false;")
  pcmd("  // Sanity check.")
  pcmd("  if (IOC_TYPE(req) == 0) return false;")
  pcmd("  return true;")
  pcmd("}")
  pcmd("")
  pcmd("static const ioctl_desc *ioctl_lookup(unsigned req) {")
  pcmd("  const ioctl_desc *desc = ioctl_table_lookup(req);")
  pcmd("  if (desc) return desc;")
  pcmd("")
  pcmd("  // Try stripping access size from the request id.")
  pcmd("  desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT));")
  pcmd("  // Sanity check: requests that encode access size are either read or write and")
  pcmd("  // have size of 0 in the table.")
  pcmd("  if (desc && desc->size == 0 &&")
  pcmd("      (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE ||")
  pcmd("       desc->type == ioctl_desc::READ))")
  pcmd("    return desc;")
  pcmd("  return nullptr;")
  pcmd("}")
  pcmd("")
  pcmd("static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,")
  pcmd("                             unsigned request, void *arg) {")
  pcmd("  if (desc->type == ioctl_desc::READ || desc->type == ioctl_desc::READWRITE) {")
  pcmd("    unsigned size = desc->size ? desc->size : IOC_SIZE(request);")
  pcmd("    COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size);")
  pcmd("  }")
  pcmd("  if (desc->type != ioctl_desc::CUSTOM)")
  pcmd("    return;")
  pcmd("  if (request == IOCTL_SIOCGIFCONF) {")
  pcmd("    struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;")
  pcmd("    COMMON_INTERCEPTOR_READ_RANGE(ctx, (char*)&ifc->ifc_len,")
  pcmd("                                  sizeof(ifc->ifc_len));")
  pcmd("  }")
  pcmd("}")
  pcmd("")
  pcmd("static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d,")
  pcmd("                              unsigned request, void *arg) {")
  pcmd("  if (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READWRITE) {")
  pcmd("    // FIXME: add verbose output")
  pcmd("    unsigned size = desc->size ? desc->size : IOC_SIZE(request);")
  pcmd("    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size);")
  pcmd("  }")
  pcmd("  if (desc->type != ioctl_desc::CUSTOM)")
  pcmd("    return;")
  pcmd("  if (request == IOCTL_SIOCGIFCONF) {")
  pcmd("    struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;")
  pcmd("    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifc->ifc_ifcu.ifcu_req, ifc->ifc_len);")
  pcmd("  }")
  pcmd("}")
  pcmd("")
  pcmd("#endif // SANITIZER_NETBSD")

  close(cmd)
}

function usage()
{
  print "Usage: " script_name
  abnormal_exit = 1
  exit 1
}

function pcmd(string)
{
  print string | cmd
}

function get_type(string)
{
  if (string == "int") {
    return "sizeof(int)"
  } else if (string == "unsigned int" || string == "u_int" || string == "uint") {
    return "sizeof(unsigned int)"
  } else if (string == "long") {
    return "sizeof(long)"
  } else if (string == "unsigned long" || string == "u_long") {
    return "sizeof(unsigned long)"
  } else if (string == "short") {
    return "sizeof(short)"
  } else if (string == "unsigned short") {
    return "sizeof(unsigned short)"
  } else if (string == "char") {
    return "sizeof(char)"
  } else if (string == "signed char") {
    return "sizeof(signed char)"
  } else if (string == "unsigned char") {
    return "sizeof(unsigned char)"
  } else if (string == "uint8_t") {
    return "sizeof(u8)"
  } else if (string == "uint16_t") {
    return "sizeof(u16)"
  } else if (string == "u_int32_t" || string == "uint32_t") {
    return "sizeof(u32)"
  } else if (string ~ /\*$/) {
    return "sizeof(uptr)"
  } else if (string == "off_t") {
    return "sizeof(uptr)"
  } else if (string == "pid_t" || string == "kbd_t") {
    return "sizeof(int)"
  } else if (string == "daddr_t" || string == "dev_t") {
    return "sizeof(u64)"
  } else if (substr(string, 0, 7) == "struct " ) {
    gsub(/ /, "", string)
    return "struct_" substr(string, 7) "_sz"
  } else if (string == "scsireq_t") {
    return "struct_scsireq_sz"
  } else if (string == "tone_t") {
    return "struct_tone_sz"
  } else if (string == "union twe_statrequest") {
    return "union_twe_statrequest_sz"
  } else if (string == "usb_device_descriptor_t") {
    return "struct_usb_device_descriptor_sz"
  } else if (string == "v4l2_std_id") {
    return "sizeof(u64)"
  } else if (string == "vtmode_t") {
    return "struct_vt_mode_sz"
  } else if (string == "_old_mixer_info") {
    return "struct__old_mixer_info_sz"
  } else if (string == "agp_allocate") {
    return "struct__agp_allocate_sz"
  } else if (string == "agp_bind") {
    return "struct__agp_bind_sz"
  } else if (string == "agp_info") {
    return "struct__agp_info_sz"
  } else if (string == "agp_region") {
    return "struct__agp_region_sz"
  } else if (string == "agp_setup") {
    return "struct__agp_setup_sz"
  } else if (string == "agp_unbind") {
    return "struct__agp_unbind_sz"
  } else if (string == "atareq_t") {
    return "struct_atareq_sz"
  } else if (string == "cpustate_t") {
    return "struct_cpustate_sz"
  } else if (string == "dmx_caps_t") {
    return "struct_dmx_caps_sz"
  } else if (string == "dmx_source_t") {
    return "enum_dmx_source_sz"
  } else if (string == "dvd_authinfo") {
    return "union_dvd_authinfo_sz"
  } else if (string == "dvd_struct") {
    return "union_dvd_struct_sz"
  } else if (string == "enum v4l2_priority") {
    return "enum_v4l2_priority_sz"
  } else if (string == "envsys_basic_info_t") {
    return "struct_envsys_basic_info_sz"
  } else if (string == "envsys_tre_data_t") {
    return "struct_envsys_tre_data_sz"
  } else if (string == "ext_accm") {
    return "(8 * sizeof(u32))"
  } else if (string == "fe_sec_mini_cmd_t") {
    return "enum_fe_sec_mini_cmd_sz"
  } else if (string == "fe_sec_tone_mode_t") {
    return "enum_fe_sec_tone_mode_sz"
  } else if (string == "fe_sec_voltage_t") {
    return "enum_fe_sec_voltage_sz"
  } else if (string == "fe_status_t") {
    return "enum_fe_status_sz"
  } else if (string == "gdt_ctrt_t") {
    return "struct_gdt_ctrt_sz"
  } else if (string == "gdt_event_t") {
    return "struct_gdt_event_sz"
  } else if (string == "gdt_osv_t") {
    return "struct_gdt_osv_sz"
  } else if (string == "gdt_rescan_t") {
    return "struct_gdt_rescan_sz"
  } else if (string == "gdt_statist_t") {
    return "struct_gdt_statist_sz"
  } else if (string == "gdt_ucmd_t") {
    return "struct_gdt_ucmd_sz"
  } else if (string == "iscsi_conn_status_parameters_t") {
    return "struct_iscsi_conn_status_parameters_sz"
  } else if (string == "iscsi_get_version_parameters_t") {
    return "struct_iscsi_get_version_parameters_sz"
  } else if (string == "iscsi_iocommand_parameters_t") {
    return "struct_iscsi_iocommand_parameters_sz"
  } else if (string == "iscsi_login_parameters_t") {
    return "struct_iscsi_login_parameters_sz"
  } else if (string == "iscsi_logout_parameters_t") {
    return "struct_iscsi_logout_parameters_sz"
  } else if (string == "iscsi_register_event_parameters_t") {
    return "struct_iscsi_register_event_parameters_sz"
  } else if (string == "iscsi_remove_parameters_t") {
    return "struct_iscsi_remove_parameters_sz"
  } else if (string == "iscsi_send_targets_parameters_t") {
    return "struct_iscsi_send_targets_parameters_sz"
  } else if (string == "iscsi_set_node_name_parameters_t") {
    return "struct_iscsi_set_node_name_parameters_sz"
  } else if (string == "iscsi_wait_event_parameters_t") {
    return "struct_iscsi_wait_event_parameters_sz"
  } else if (string == "isp_stats_t") {
    return "struct_isp_stats_sz"
  } else if (string == "lsenable_t") {
    return "struct_lsenable_sz"
  } else if (string == "lsdisable_t") {
    return "struct_lsdisable_sz"
  } else if (string == "mixer_ctrl_t") {
    return "struct_mixer_ctrl_sz"
  } else if (string == "mixer_devinfo_t") {
    return "struct_mixer_devinfo_sz"
  } else if (string == "mpu_command_rec") {
    return "struct_mpu_command_rec_sz"
  } else if (string == "rndstat_t") {
    return "struct_rndstat_sz"
  } else if (string == "rndstat_name_t") {
    return "struct_rndstat_name_sz"
  } else if (string == "rndctl_t") {
    return "struct_rndctl_sz"
  } else if (string == "rnddata_t") {
    return "struct_rnddata_sz"
  } else if (string == "rndpoolstat_t") {
    return "struct_rndpoolstat_sz"
  } else if (string == "rndstat_est_t") {
    return "struct_rndstat_est_sz"
  } else if (string == "rndstat_est_name_t") {
    return "struct_rndstat_est_name_sz"
  } else if (string == "pps_params_t") {
    return "struct_pps_params_sz"
  } else if (string == "pps_info_t") {
    return "struct_pps_info_sz"
  } else if (string == "linedn_t") {
    return "(32 * sizeof(char))"
  } else if (string == "mixer_info") {
    return "struct_mixer_info_sz"
  } else if (string == "RF_SparetWait_t") {
    return "struct_RF_SparetWait_sz"
  } else if (string == "RF_ComponentLabel_t") {
    return "struct_RF_ComponentLabel_sz"
  } else if (string == "RF_SingleComponent_t") {
    return "struct_RF_SingleComponent_sz"
  } else if (string == "RF_ProgressInfo_t") {
    return "struct_RF_ProgressInfo_sz"
  } else {
    print "Unrecognized entry: " string
    print "Aborting"
    abnormal_exit = 1
    exit 1
  }

  return string
}