Add show durations

Add show durations

# Produce a raw data spreadsheet from URLs found in $SHOW_URLS
#
# Note that IN_CANADA affects processing.
#
# INVOCATION:
#    while read -r line; do
#        curl -sS "$line" |
#            awk -v ERRORS=$ERRORS -v RAW_TITLES=$RAW_TITLES -f getAcornFrom-showPages.awk >>$UNSORTED
#        ((lastRow++))
#    done <"$SHOW_URLS"

#   Field Names
#        1 Title (link)    2 Seasons    3 Episodes    4 Duration    5 Description

# Extract the show title
/meta property="og:title/ {
    split ($0,fld,"\"")
    showTitle = fld[4]
    sub (/^Watch /,"",showTitle)
    sub (/ on Acorn TV$/,"",showTitle)
    gsub (/&/,"\\&",showTitle)
    gsub (/"/,"\"\"",showTitle)
    gsub (/'/,"'",showTitle)
    if (match (showTitle, /^The /)) {
        showTitle = substr(showTitle, 5) ", The"
    }
    print showTitle >> RAW_TITLES
    # print "==> showTitle = " showTitle " -- " FILENAME > "/dev/stderr"
    next
}

# Extract the show URL
/meta property="og:url/ {
    split ($0,fld,"\"")
    showURL = fld[4]
    # print "==> showURL = " showURL " -- " FILENAME > "/dev/stderr"
    # Create shorter URL by removing https://
    shortURL = showURL
    sub (/.*acorn\.tv/,"acorn.tv",shortURL)
    next
}

# Extract the number of episodes in the show
/itemprop="numberOfEpisodes"/ {
    episodeLinesFound += 1
    split ($0,fld,"\"")
    if (episodeLinesFound == 1) {
        showEpisodes = fld[4]
        if (showEpisodes == "") {
            printf ("==> Blank showEpisodes in numberOfEpisodes: %s\t%s\n", shortURL, showTitle) >> ERRORS
        }
        # print "==> showEpisodes = " showEpisodes " -- " FILENAME > "/dev/stderr"
    }
    if (episodeLinesFound != 1) {
        seasonEpisodes = seasonEpisodes "+" fld[4]
        if (seasonEpisodes == "") {
            printf ("==> Blank seasonEpisodes in numberOfEpisodes: %s\t%s\n", shortURL, showTitle) >> ERRORS
        }
        # print "==> seasonEpisodes = " seasonEpisodes " -- " FILENAME > "/dev/stderr"
    }
    next
}

# Extract the number of seasons in the show
/itemprop="numberOfSeasons"/ {
    seasonLinesFound += 1
    split ($0,fld,"\"")
    showSeasons = fld[4]
    if (showSeasons == "") {
        printf ("==> Blank showSeasons in numberOfSeasons: %s\t%s\n", shortURL, showTitle) >> ERRORS
    }
    # print "==> showSeasons = " showSeasons " -- " FILENAME > "/dev/stderr"
    next
}

# Extract the show description
/id="franchise-description"/ {
    descriptionLinesFound += 1
    # get rid of boilerplate
    split ($0,fld,"[<>]")
    showDescription = fld[3]
    # fix sloppy input spacing
    gsub (/ \./,".",showDescription)
    gsub (/  */," ",showDescription)
    sub (/^ */,"",showDescription)
    sub (/ *$/,"",showDescription)
    # fix funky HTML characters
    gsub (/&/,"\\&",showDescription)
    gsub (/"/,"\"\"",showDescription)
    gsub (/'/,"'",showDescription)
    # fix unmatched quotes
    numQuotes = gsub(/"/,"\"",showDescription)
    if ((numQuotes % 2) == 1) {
        printf ("==> Changed unmatched quote (%d): %d\t%s\t%s\t%s\n", numQuotes, shortURL, \
                showTitle) >> ERRORS
        showDescription = showDescription " \""
    }
    # print "==> showDescription = " showDescription " -- " FILENAME > "/dev/stderr"
    next
}

# Extract the episode duration
/<meta itemprop="timeRequired"/ {
    durationLinesFound += 1
    split ($0,fld,"\"")
    split (fld[4],tm,/[TMS]/)
    secs = tm[3]
    mins = tm[2] + int(secs / 60)
    hrs =  int(mins / 60)
    secs %= 60; mins %= 60
    #
    showSecs += secs
    showMins += mins + int(showSecs / 60)
    showHrs += hrs + int(showMins / 60)
    showSecs %= 60; showMins %= 60
    #
    episodeDuration = sprintf ("%02d:%02d:%02d", hrs, mins, secs)
    if (episodeDuration == "00:00:00")
        printf ("==> Blank episode duration: %s  %s\n", shortURL, showTitle) >> ERRORS
    next
}

/<footer>/ {
    if (episodeLinesFound == 0) {
        printf ("==> No numberOfEpisodes: %s\t%s\n", shortURL, showTitle) >> ERRORS
    }
    if (seasonLinesFound == 0) {
        printf ("==> No numberOfSeasons: %s\t%s\n", shortURL, showTitle) >> ERRORS
    }
    if (descriptionLinesFound == 0) {
        printf ("==> No franchise-description: %s\t%s\n", shortURL, showTitle) >> ERRORS
    }
    if (durationLinesFound == 0) {
        printf ("==> No durations: %s\t%s\n", shortURL, showTitle) >> ERRORS
    }
    showLink = "=HYPERLINK(\"" showURL "\";\"" showTitle "\")"
    showDuration = sprintf ("%02d:%02d:%02d", showHrs, showMins, showSecs)
    # Title	Seasons	Episodes	Duration	Description
    printf ("%s\t%s\t=%s\t%s\t%s\n", showLink, showSeasons, seasonEpisodes, showDuration, showDescription)
    # printf ("%s\t%s\t=%s\t%s\t%s\n", showLink, showSeasons, showEpisodes, showDuration, showDescription)
    # Make sure there is no carryover
    showTitle = ""
    showURL = ""
    shortURL = ""
    showLink = ""
    showSeasons = ""
    showEpisodes = ""
    seasonEpisodes = ""
    showSecs = 0
    showMins = 0
    showHrs = 0
    showDuration = ""
    showDescription = ""
    #
    episodeLinesFound = 0
    seasonLinesFound = 0
    descriptionLinesFound  = 0
}

# Produce a raw data spreadsheet from URLs found in $SHOW_URLS
#
# Note that IN_CANADA affects processing.
#
# INVOCATION:
#    while read -r line; do
#        curl -sS "$line" |
#            awk -v ERRORS=$ERRORS -v RAW_TITLES=$RAW_TITLES -f getAcornFrom-showPages.awk >>$UNSORTED
#        ((lastRow++))
#    done <"$SHOW_URLS"

#   Field Names
#        1 Title (link)    2 Seasons    3 Episodes    4 Duration    5 Description

# Extract the show title
/meta property="og:title/ {
    split ($0,fld,"\"")
    showTitle = fld[4]
    sub (/^Watch /,"",showTitle)
    sub (/ on Acorn TV$/,"",showTitle)
    gsub (/&/,"\\&",showTitle)
    gsub (/"/,"\"\"",showTitle)
    gsub (/'/,"'",showTitle)
    if (match (showTitle, /^The /)) {
        showTitle = substr(showTitle, 5) ", The"
    }
    print showTitle >> RAW_TITLES
    # print "==> showTitle = " showTitle " -- " FILENAME > "/dev/stderr"
    next
}

# Extract the show URL
/meta property="og:url/ {
    split ($0,fld,"\"")
    showURL = fld[4]
    # print "==> showURL = " showURL " -- " FILENAME > "/dev/stderr"
    # Create shorter URL by removing https://
    shortURL = showURL
    sub (/.*acorn\.tv/,"acorn.tv",shortURL)
    next
}

# Extract the number of episodes in the show
/itemprop="numberOfEpisodes"/ {
    episodeLinesFound += 1
    split ($0,fld,"\"")
    if (episodeLinesFound == 1) {
        showEpisodes = fld[4]
        if (showEpisodes == "") {
            printf ("==> Blank showEpisodes in numberOfEpisodes: %s\t%s\n", shortURL, showTitle) >> ERRORS
        }
        # print "==> showEpisodes = " showEpisodes " -- " FILENAME > "/dev/stderr"
    }
    if (episodeLinesFound != 1) {
        seasonEpisodes = seasonEpisodes "+" fld[4]
        if (seasonEpisodes == "") {
            printf ("==> Blank seasonEpisodes in numberOfEpisodes: %s\t%s\n", shortURL, showTitle) >> ERRORS
        }
        # print "==> seasonEpisodes = " seasonEpisodes " -- " FILENAME > "/dev/stderr"
    }
    next
}

# Extract the number of seasons in the show
/itemprop="numberOfSeasons"/ {
    seasonLinesFound += 1
    split ($0,fld,"\"")
    showSeasons = fld[4]
    if (showSeasons == "") {
        printf ("==> Blank showSeasons in numberOfSeasons: %s\t%s\n", shortURL, showTitle) >> ERRORS
    }
    # print "==> showSeasons = " showSeasons " -- " FILENAME > "/dev/stderr"
    next
}

# Extract the show description
/id="franchise-description"/ {
    descriptionLinesFound += 1
    # get rid of boilerplate
    split ($0,fld,"[<>]")
    showDescription = fld[3]
    # fix sloppy input spacing
    gsub (/ \./,".",showDescription)
    gsub (/  */," ",showDescription)
    sub (/^ */,"",showDescription)
    sub (/ *$/,"",showDescription)
    # fix funky HTML characters
    gsub (/&/,"\\&",showDescription)
    gsub (/"/,"\"\"",showDescription)
    gsub (/'/,"'",showDescription)
    # fix unmatched quotes
    numQuotes = gsub(/"/,"\"",showDescription)
    if ((numQuotes % 2) == 1) {
        printf ("==> Changed unmatched quote (%d): %d\t%s\t%s\t%s\n", numQuotes, shortURL, \
                showTitle) >> ERRORS
        showDescription = showDescription " \""
    }
    # print "==> showDescription = " showDescription " -- " FILENAME > "/dev/stderr"
    next
}

/<footer>/ {
    if (episodeLinesFound == 0) {
        printf ("==> No numberOfEpisodes: %s\t%s\n", shortURL, showTitle) >> ERRORS
    }
    if (seasonLinesFound == 0) {
        printf ("==> No numberOfSeasons: %s\t%s\n", shortURL, showTitle) >> ERRORS
    }
    if (descriptionLinesFound == 0) {
        printf ("==> No franchise-description: %s\t%s\n", shortURL, showTitle) >> ERRORS
    }
    showLink = "=HYPERLINK(\"" showURL "\";\"" showTitle "\")"
    # Title	Seasons	Episodes	Duration	Description
    printf ("%s\t%s\t=%s\t%s\n", showLink, showSeasons, seasonEpisodes, showDescription)
    # printf ("%s\t%s\t=%s\t%s\t%s\n", showLink, showSeasons, seasonEpisodes, showDuration, showDescription)
    # printf ("%s\t%s\t=%s\t%s\t%s\n", showLink, showSeasons, showEpisodes, showDuration, showDescription)
    # Make sure there is no carryover
    showTitle = ""
    showURL = ""
    shortURL = ""
    showLink = ""
    showSeasons = ""
    showEpisodes = ""
    seasonEpisodes = ""
    showDuration = ""
    showDescription = ""
    #
    episodeLinesFound = 0
    seasonLinesFound = 0
    descriptionLinesFound  = 0
}


Bugfix

Bugfix

#! /usr/bin/awk -f
#
# Extracts the /**-denoted comments from a source file.
# https://github.com/wernsey/d.awk
#
# (c) 2016 Werner Stoop
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved. This file is offered as-is,
# without any warranty.

!in_comment && /\/\*\*/ {
	in_comment = 1;
	sub(/\/\*\*/,"");
}
in_comment && /\*\// { in_comment = 0; }
in_comment && /^[[:space:]]*\*/ {
	sub(/^[[:space:]]*\*/,"");
}
in_comment { print; }

#! /usr/bin/awk -f
#
# Extracts the /**-denoted comments from a source file.
# https://github.com/wernsey/d.awk
#
# (c) 2016 Werner Stoop
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved. This file is offered as-is,
# without any warranty.

!in_comment && /\/\*\*/ {
	in_comment = 1;
	sub(/\/\*\*/,"");
}
in_comment && /\*\// { in_comment = 0; }
in_comment && /^[[:space:]]*\*/ {
	sub(/^[[:space:]]*\*/,"");
	print;
}


Fix tests

Fix tests

Due to some formating changes, the output comparison was not working.

#!/bin/awk
BEGIN {
	show = 0
}

$0 ~ /info core: starting single threaded processing/ {
	show = 1;
	next;
}

$0 ~ /info core: unload module/ {
	show = 0;
	next;
}

$0 ~ /^debug packet:/ {
	next;
}

$0 ~ /^debug rule:/ {
	next;
}

{
	if (show == 2) {
		print;
	}
	else if (show == 1) {
		show = 2
	}
}

#!/bin/awk
BEGIN {
	show = 0
}

$0 ~ /info core: starting single threaded processing/ {
	show = 1;
	next;
}

$0 ~ /info core: unload module/ {
	show = 0;
	next;
}

$0 ~ /^debug packet:/ {
	next;
}

$0 ~ /^debug rule:/ {
	next;
}

{
	if (show != 0) {
		print;
	}
}


Correct error in number variables printed

git-svn-id: 293778eaa97c8c94097d610b1bd5133a8f478f36@23949 4f837ed2-42f5-46e7-a7a5-fa17313484d4

#!/usr/bin/awk -f
# cat *.tdb | tdbout -t publisher,plugin,publisher:info[contract],year,publisher:info[tester],status,publisher:info[back]

BEGIN {
  FS="\t"
  pn = 0
}

{
  # add a loop to add line only if ending year is gt or eq to contract year
  end_year = 0
  incontract = 0
  if ($7 > 1900) {
    test_year = $7
  } else {
    test_year = $3
  }
  if (length($4) > 3) {
    end_year = substr($4,length($4)-3,4)
  }
  if (end_year >= test_year) {
    incontract = 1
  }

  #if ((substr($4,1,4) >= $3) || ((length($4) == 9) && (substr($4,6,4) >= $3))) {
  if (incontract == 1) {
      nn = split($2,na,/\./)
      lp2 = na[nn]
    if (!(($1,lp2,$3,$7,$4) in b)) {
      p[pn] = $1
      n[pn] = lp2
  #    n[pn] = $2
      t[pn] = $3
      k[pn] = $7
      d[pn] = $4
      r[pn] = $5
      pn++
    }
    b[$1,lp2,$3,$7,$4]++
    c[$1,lp2,$3,$7,$4,$6]++
    x[$6]++
    tt++
  }
}

END {
  s[0] = "expected"
  s[1] = "exists"
  s[2] = "manifest"
  s[3] = "wanted"
  s[4] = "crawling"
  s[5] = "testing"
  s[6] = "notReady"
  s[7] = "released"
  s[8] = "down"
  s[9] = "superseded"
  s[10] = "zapped"
  sn = 11

  sc[0] = "expe"
  sc[1] = "exis"
  sc[2] = "mani"
  sc[3] = "want"
  sc[4] = "craw"
  sc[5] = "test"
  sc[6] = "notR"
  sc[7] = "rele"
  sc[8] = "down"
  sc[9] = "supe"
  sc[10] = "zapp"
  scn = 11

  #print out header
  printf "Publisher\tPlugin\tContr\tBack\tYear\tT\tTotal"
  for (j = 0 ; j < scn ; j++) {
    if (x[s[j]] > 0) {
    printf "\t%s", sc[j]
    }
  }
  printf "\n"

  #print out publisher, plugin, contract year, back, year, tester, total aus
  for (i = 0 ; i < pn ; i++) {
    printf "%s\t%s\t%s\t%s\t%s\t%s\t%d", p[i], n[i], t[i], k[i], d[i], r[i], b[p[i],n[i],t[i],k[i],d[i]]
    for (j = 0 ; j < sn ; j++) {
      if (x[s[j]] > 0){
      if (c[p[i],n[i],t[i],k[i],d[i],s[j]] == 0) {
      printf "\t.."
    } else {
        printf "\t%d", c[p[i],n[i],t[i],k[i],d[i],s[j]]
      }
    }
    }
    printf "\n"
  }
    #print out bottom line sums
    printf "Publisher\tPlugin\tContr\tBack\tYear\tT\t%d", tt
    for (j = 0 ; j < sn ; j++) {
      if (x[s[j]] > 0) {
        printf "\t%d", x[s[j]]
      }
    }

  printf "\n"
}

#!/usr/bin/awk -f
# cat *.tdb | tdbout -t publisher,plugin,publisher:info[contract],year,publisher:info[tester],status,publisher:info[back]

BEGIN {
  FS="\t"
  pn = 0
}

{
  # add a loop to add line only if ending year is gt or eq to contract year
  end_year = 0
  incontract = 0
  if ($7 > 1900) {
    test_year = $7
  } else {
    test_year = $3
  }
  if (length($4) > 3) {
    end_year = substr($4,length($4)-3,4)
  }
  if (end_year >= test_year) {
    incontract = 1
  }

  #if ((substr($4,1,4) >= $3) || ((length($4) == 9) && (substr($4,6,4) >= $3))) {
  if (incontract == 1) {
      nn = split($2,na,/\./)
      lp2 = na[nn]
    if (!(($1,lp2,$3,$7,$4) in b)) {
      p[pn] = $1
      n[pn] = lp2
  #    n[pn] = $2
      t[pn] = $3
      k[pn] = $7
      d[pn] = $4
      r[pn] = $5
      pn++
    }
    b[$1,lp2,$3,$7,$4]++
    c[$1,lp2,$3,$7,$4,$6]++
    x[$6]++
    tt++
  }
}

END {
  s[0] = "expected"
  s[1] = "exists"
  s[2] = "manifest"
  s[3] = "wanted"
  s[4] = "crawling"
  s[5] = "testing"
  s[6] = "notReady"
  s[7] = "released"
  s[8] = "down"
  s[9] = "superseded"
  s[10] = "zapped"
  sn = 11

  sc[0] = "expe"
  sc[1] = "exis"
  sc[2] = "mani"
  sc[3] = "want"
  sc[4] = "craw"
  sc[5] = "test"
  sc[6] = "notR"
  sc[7] = "rele"
  sc[8] = "down"
  sc[9] = "supe"
  sc[10] = "zapp"
  scn = 11

  #print out header
  printf "Publisher\tPlugin\tContr\tBack\tYear\tT\tTotal"
  for (j = 0 ; j < scn ; j++) {
    if (x[s[j]] > 0) {
    printf "\t%s", sc[j]
    }
  }
  printf "\n"

  #print out publisher, plugin, contract year, back, year, tester, total aus
  for (i = 0 ; i < pn ; i++) {
    printf "%s\t%s\t%s\t%s\t%s\t%s\t%d", p[i], n[i], t[i], k[i], d[i], r[i], b[p[i],n[i],t[i],d[i]]
    for (j = 0 ; j < sn ; j++) {
      if (x[s[j]] > 0){
      if (c[p[i],n[i],t[i],k[i],d[i],s[j]] == 0) {
      printf "\t.."
    } else {
        printf "\t%d", c[p[i],n[i],t[i],k[i],d[i],s[j]]
      }
    }
    }
    printf "\n"
  }
    #print out bottom line sums
    printf "Publisher\tPlugin\tContr\tBack\tYear\tT\t%d", tt
    for (j = 0 ; j < sn ; j++) {
      if (x[s[j]] > 0) {
        printf "\t%d", x[s[j]]
      }
    }

  printf "\n"
}


Translators/BingTranslator: fix #110

Translators/BingTranslator: fix #110

####################################################################
# BingTranslator.awk                                               #
####################################################################
#
# Last Updated: 11 Mar 2016
# http://ssl.microsofttranslator.com/dynamic/226010/js/LandingPage.js
BEGIN { provides("bing") }

function genRTTAppId(    content, group, header, isBody) {
    HttpProtocol = "http://"
    HttpHost = "ssl.microsofttranslator.com"
    HttpPort = 80
    LandingPage = "/dynamic/226010/js/LandingPage.js"

    if (Option["proxy"]) {
        match(Option["proxy"], /^(http:\/*)?([^\/]*):([^\/:]*)/, HttpProxySpec)
        HttpService = "/inet/tcp/0/" HttpProxySpec[2] "/" HttpProxySpec[3]
        HttpPathPrefix = HttpProtocol HttpHost
    } else {
        HttpService = "/inet/tcp/0/" HttpHost "/" HttpPort
        HttpPathPrefix = ""
    }

    header = "GET " LandingPage " HTTP/1.1\n"                           \
        "Host: " HttpHost "\n"                                          \
        "Connection: close\n"
    if (Option["user-agent"])
        header = header "User-Agent: " Option["user-agent"] "\n"

    content = NULLSTR; isBody = 0
    print header |& HttpService
    while ((HttpService |& getline) > 0) {
        if (isBody)
            content = content ? content "\n" $0 : $0
        else if (length($0) <= 1)
            isBody = 1
        l(sprintf("%4s bytes > %s", length($0), length($0) < 1024 ? $0 : "..."))
    }
    close(HttpService)

    match(content, /rttAppId:"([^"]+)"/, group)
    if (group[1]) {
        RTTAppId = group[1]
    } else {
        e("[ERROR] Oops! Something went wrong and I can't translate it for you :(")
        exit 1
    }
}

function bingInit() {
    genRTTAppId() # generate a one-time key

    HttpProtocol = "http://"
    HttpHost = "api.microsofttranslator.com"
    HttpPort = 80
}

function bingRequestUrl(text, sl, tl, hl) {
    # Quick hack: Bing doesn't have an "auto" language code
    if (sl == "auto") sl = NULLSTR

    return HttpPathPrefix "/v2/ajax.svc/TranslateArray2?"               \
        "appId="  preprocess(parameterize(RTTAppId, "\""))              \
        "&from="  preprocess(parameterize(sl, "\""))                    \
        "&to="    preprocess(parameterize(tl, "\""))                    \
        "&texts=" preprocess("[" parameterize(text, "\"") "]")
}

function bingTTSUrl(text, tl,    narrator) {
    narrator = Option["narrator"] ~ /^[AFaf]/ ? "female" : "male"

    return HttpProtocol HttpHost "/v2/http.svc/speak?" "appId=" RTTAppId \
        "&language=" tl "&text=" preprocess(text)                       \
        "&format=audio/mp3" "&options=MinSize|" narrator
}

function bingWebTranslateUrl(uri, sl, tl, hl) {
    return "http://www.microsofttranslator.com/bv.aspx?"        \
        "from=" sl "&to=" tl "&a=" uri
}

# Get the translation of a string.
function bingTranslate(text, sl, tl, hl,
                       isVerbose, toSpeech, returnPlaylist, returnIl,
                       ####
                       r,
                       content, tokens, ast,
                       _sl, _tl, _hl, il,
                       translation,
                       wShowOriginal, wShowTranslation, wShowLanguages,
                       group, temp) {
    if (!getCode(tl)) {
        # Check if target language is supported
        w("[WARNING] Unknown target language code: " tl)
    } else if (isRTL(tl)) {
        # Check if target language is R-to-L
        if (!FriBidi)
            w("[WARNING] " getName(tl) " is a right-to-left language, but FriBidi is not found.")
    }
    _sl = getCode(sl); if (!_sl) _sl = sl
    _tl = getCode(tl); if (!_tl) _tl = tl
    _hl = getCode(hl); if (!_hl) _hl = hl

    content = getResponse(text, _sl, _tl, _hl)
    # Strip the content and get a valid JSON string
    match(content, /(\[.*\])$/, group)
    if (!group[0]) {
        # Display the error message
        match(content, /"(.*)"$/, group)
        gsub(/\\u000d/, "\r", group[1])
        gsub(/\\u000a/, "\n", group[1])
        e("[ERROR] " group[1])
        ExitCode = 1
        return
    }
    content = group[1]
    tokenize(tokens, content)
    parseJson(ast, tokens)

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

    translation = unparameterize(ast[0 SUBSEP 0 SUBSEP "TranslatedText"])

    returnIl[0] = il = unparameterize(ast[0 SUBSEP 0 SUBSEP "From"])
    if (Option["verbose"] < 0)
        return getList(il)

    # Generate output
    if (!isVerbose) {
        # Brief mode
        r = translation

    } else {
        # Verbose mode
        wShowOriginal = Option["show-original"]
        wShowTranslation = Option["show-translation"]
        wShowLanguages = Option["show-languages"]

        if (wShowOriginal) {
            # Display: original text
            if (r) r = r RS RS
            r = r m("-- display original text")
            r = r prettify("original", s(text, il))
        }

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

        if (wShowLanguages) {
            # Display: source language -> target language
            if (r) r = r RS RS
            r = r m("-- display source language -> target language")
            temp = Option["fmt-languages"]
            if (!temp) temp = "[ %s -> %t ]"
            split(temp, group, /(%s|%S|%t|%T)/)
            r = r prettify("languages", group[1])
            if (temp ~ /%s/)
                r = r prettify("languages-sl", getDisplay(il))
            if (temp ~ /%S/)
                r = r prettify("languages-sl", getName(il))
            r = r prettify("languages", group[2])
            if (temp ~ /%t/)
                r = r prettify("languages-tl", getDisplay(tl))
            if (temp ~ /%T/)
                r = r prettify("languages-tl", getName(tl))
            r = r prettify("languages", group[3])
        }
    }

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

    return r
}

####################################################################
# BingTranslator.awk                                               #
####################################################################
#
# Last Updated: 26 Dec 2015
# https://www.bing.com/translator/dynamic/226010/js/LandingPage.js
BEGIN { provides("bing") }

function genRTTAppId(    content, group, header, isBody) {
    HttpProtocol = "http://"
    HttpHost = "www.bing.com"
    HttpPort = 80
    LandingPage = "/translator/dynamic/226010/js/LandingPage.js"

    if (Option["proxy"]) {
        match(Option["proxy"], /^(http:\/*)?([^\/]*):([^\/:]*)/, HttpProxySpec)
        HttpService = "/inet/tcp/0/" HttpProxySpec[2] "/" HttpProxySpec[3]
        HttpPathPrefix = HttpProtocol HttpHost
    } else {
        HttpService = "/inet/tcp/0/" HttpHost "/" HttpPort
        HttpPathPrefix = ""
    }

    header = "GET " LandingPage " HTTP/1.1\n"                           \
        "Host: " HttpHost "\n"                                          \
        "Connection: close\n"
    if (Option["user-agent"])
        header = header "User-Agent: " Option["user-agent"] "\n"

    content = NULLSTR; isBody = 0
    print header |& HttpService
    while ((HttpService |& getline) > 0) {
        if (isBody)
            content = content ? content "\n" $0 : $0
        else if (length($0) <= 1)
            isBody = 1
        l(sprintf("%4s bytes > %s", length($0), length($0) < 1024 ? $0 : "..."))
    }
    close(HttpService)

    match(content, /rttAppId:"([^"]+)"/, group)
    if (group[1]) {
        RTTAppId = group[1]
    } else {
        e("[ERROR] Oops! Something went wrong and I can't translate it for you :(")
        exit 1
    }
}

function bingInit() {
    genRTTAppId() # generate a one-time key

    HttpProtocol = "http://"
    HttpHost = "api.microsofttranslator.com"
    HttpPort = 80
}

function bingRequestUrl(text, sl, tl, hl) {
    # Quick hack: Bing doesn't have an "auto" language code
    if (sl == "auto") sl = NULLSTR

    return HttpPathPrefix "/v2/ajax.svc/TranslateArray2?"               \
        "appId="  preprocess(parameterize(RTTAppId, "\""))              \
        "&from="  preprocess(parameterize(sl, "\""))                    \
        "&to="    preprocess(parameterize(tl, "\""))                    \
        "&texts=" preprocess("[" parameterize(text, "\"") "]")
}

function bingTTSUrl(text, tl,    narrator) {
    narrator = Option["narrator"] ~ /^[AFaf]/ ? "female" : "male"

    return HttpProtocol HttpHost "/v2/http.svc/speak?" "appId=" RTTAppId \
        "&language=" tl "&text=" preprocess(text)                       \
        "&format=audio/mp3" "&options=MinSize|" narrator
}

function bingWebTranslateUrl(uri, sl, tl, hl) {
    return "http://www.microsofttranslator.com/bv.aspx?"        \
        "from=" sl "&to=" tl "&a=" uri
}

# Get the translation of a string.
function bingTranslate(text, sl, tl, hl,
                       isVerbose, toSpeech, returnPlaylist, returnIl,
                       ####
                       r,
                       content, tokens, ast,
                       _sl, _tl, _hl, il,
                       translation,
                       wShowOriginal, wShowTranslation, wShowLanguages,
                       group, temp) {
    if (!getCode(tl)) {
        # Check if target language is supported
        w("[WARNING] Unknown target language code: " tl)
    } else if (isRTL(tl)) {
        # Check if target language is R-to-L
        if (!FriBidi)
            w("[WARNING] " getName(tl) " is a right-to-left language, but FriBidi is not found.")
    }
    _sl = getCode(sl); if (!_sl) _sl = sl
    _tl = getCode(tl); if (!_tl) _tl = tl
    _hl = getCode(hl); if (!_hl) _hl = hl

    content = getResponse(text, _sl, _tl, _hl)
    # Strip the content and get a valid JSON string
    match(content, /(\[.*\])$/, group)
    if (!group[0]) {
        # Display the error message
        match(content, /"(.*)"$/, group)
        gsub(/\\u000d/, "\r", group[1])
        gsub(/\\u000a/, "\n", group[1])
        e("[ERROR] " group[1])
        ExitCode = 1
        return
    }
    content = group[1]
    tokenize(tokens, content)
    parseJson(ast, tokens)

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

    translation = unparameterize(ast[0 SUBSEP 0 SUBSEP "TranslatedText"])

    returnIl[0] = il = unparameterize(ast[0 SUBSEP 0 SUBSEP "From"])
    if (Option["verbose"] < 0)
        return getList(il)

    # Generate output
    if (!isVerbose) {
        # Brief mode
        r = translation

    } else {
        # Verbose mode
        wShowOriginal = Option["show-original"]
        wShowTranslation = Option["show-translation"]
        wShowLanguages = Option["show-languages"]

        if (wShowOriginal) {
            # Display: original text
            if (r) r = r RS RS
            r = r m("-- display original text")
            r = r prettify("original", s(text, il))
        }

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

        if (wShowLanguages) {
            # Display: source language -> target language
            if (r) r = r RS RS
            r = r m("-- display source language -> target language")
            temp = Option["fmt-languages"]
            if (!temp) temp = "[ %s -> %t ]"
            split(temp, group, /(%s|%S|%t|%T)/)
            r = r prettify("languages", group[1])
            if (temp ~ /%s/)
                r = r prettify("languages-sl", getDisplay(il))
            if (temp ~ /%S/)
                r = r prettify("languages-sl", getName(il))
            r = r prettify("languages", group[2])
            if (temp ~ /%t/)
                r = r prettify("languages-tl", getDisplay(tl))
            if (temp ~ /%T/)
                r = r prettify("languages-tl", getName(tl))
            r = r prettify("languages", group[3])
        }
    }

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

    return r
}


Remove reorder.awk script

Remove reorder.awk script

#!/usr/bin/awk -f
BEGIN { FS=","; OFS=","; }

(FNR > 1) {
	stdCov[$1] = $4;
	dynCov[$1] = $14;
	caddyCov[$1] = $24;

	stdPapiTime[$1] = $5;
	dynPapiTime[$1] = $15;
	caddyPapiTime[$1] = $25;

	stdTime[$1]= $6;
	dynTime[$1]= $16;
	caddyTime[$1]= $26;

	stdCalls[$1] = $10;
	dynCalls[$1] = $20;
	caddyCalls[$1] = $30;
}

END {
	printf "%s, %s, %s, %s, %s, %s\n",
		"Name", "Class", "ExecCov", "Time", "PapiTime", "Calls";

	for (p in stdCov) {
		printf "%s, %s, %s, %s, %s, %s\n",
			p, "Static", stdCov[p], stdTime[p], stdPapiTime[p], stdCalls[p];

		printf "%s, %s, %s, %s, %s, %s\n",
		    p, "Algebraic", caddyCov[p], caddyTime[p], caddyPapiTime[p], caddyCalls[p];

		printf "%s, %s, %s, %s, %s, %s\n",
			p, "Dynamic" , dynCov[p], dynTime[p], dynPapiTime[p], dynCalls[p];

		#printf "%s, %s, %s, %s, %s, %s\n",
		#	p, "Raw"     , "0", rawTime[p], "0", "0";
	}
}


Support perforce-style diffs in determining modified line ranges.

PiperOrigin-RevId: 304687721

#!/usr/bin/awk -f
# Copyright 2020 The Verible Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Converts a unified-diff into file names and their modified line ranges.
# This supports reading the output of 'git diff', but should handle most
# variants of diffs.
# Note, however, that git diffs shows files as being prefixed with "a/" and "b/",
# so the caller of this script will need to adjust filenames accordingly.
# The output style of line ranges is suitable for 'verilog_format --lines=...'
#
# usage: awk -f (this_script) < file.diff
#
# Changed lines are those that start with '+' in unified diffs.
# Ranges can be compact: N,P-Q
# Prints one file per line, e.g.:
#   abc.sv 5,10-12,18,21-22
#   xyz.sv 232-245
# New files (diffed vs. /dev/null) will appear without line ranges:
#   new_file.sv
#
# TODO(fangism): use or write a proper diff/patch-reader library (C++)

BEGIN {
  expect_filename = 0;
  active_range = 0;
  seen_file = 0;
}

# Detect whether this entry is a new file.
/^---/ {
  is_new_file = ($2 == "/dev/null");
}

# contains filename at $2
/^+++/ {
  if (expect_filename) {
    filename = $2;
    if (seen_file) print "";
    printf(filename " ");
    expect_filename = 0;
    seen_range = 0;
    seen_file = 1;
  }
}

# given:
# @@ -L,J +R,K
# R is the next starting line number in the next chunk
/^@@ / {
  split($3, a, ",");
  left_current_line = substr(a[1], 2) - 1;
  right_current_line = left_current_line;
  active_range = 0;
}

# seen in 'git diff'
# diff before-file after-file
/^diff/ {
  auto_flush_range();
  expect_filename = 1;
}

# seen in 'p4 diff'
# ==== //depot/...#N - /local/path/to/file ====
/^==== .* ====$/ {
  auto_flush_range();
  expect_filename = 1;
}

# + lines are after change only
/^+/ {
  if (!expect_filename) {
    ++right_current_line;
    if (!active_range) {
      modified_from = right_current_line;
    }
    active_range = 1;
  }
}

# print the most recent completed range
function flush_range() {
  if (!is_new_file) {
    if (seen_range) printf(",");
    modified_to = right_current_line;
    if (modified_from == modified_to) printf(modified_from);
    else printf(modified_from "-" modified_to);
  }
  seen_range = 1;
  active_range = 0;
}

function auto_flush_range() {
  if (active_range) {
    flush_range();
  }
}

# <space> lines in unified diffs are common to both before/after
/^ / {
  auto_flush_range();
  ++left_current_line;
  ++right_current_line;
}

# - lines are before change only
/^-/ {
  auto_flush_range();
  ++left_current_line;
}

END {
  # if diff ends with an active range, print it.
  auto_flush_range();
  print "";
}

#!/usr/bin/awk -f
# Copyright 2020 The Verible Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Converts a unified-diff into file names and their modified line ranges.
# This supports reading the output of 'git diff', but should handle most
# variants of diffs.
# Note, however, that git diffs shows files as being prefixed with "a/" and "b/",
# so the caller of this script will need to adjust filenames accordingly.
# The output style of line ranges is suitable for 'verilog_format --lines=...'
#
# usage: awk -f (this_script) < file.diff
#
# Changed lines are those that start with '+' in unified diffs.
# Ranges can be compact: N,P-Q
# Prints one file per line, e.g.:
#   abc.sv 5,10-12,18,21-22
#   xyz.sv 232-245
# New files (diffed vs. /dev/null) will appear without line ranges:
#   new_file.sv
#
# TODO(fangism): use or write a proper diff/patch-reader library (C++)

BEGIN {
  expect_filename = 0;
  active_range = 0;
  seen_file = 0;
}

# Detect whether this entry is a new file.
/^---/ {
  is_new_file = ($2 == "/dev/null");
}

# contains filename at $2
/^+++/ {
  if (expect_filename) {
    filename = $2;
    if (seen_file) print "";
    printf(filename " ");
    expect_filename = 0;
    seen_range = 0;
    seen_file = 1;
  }
}

# given:
# @@ -L,J +R,K
# R is the next starting line number in the next chunk
/^@@ / {
  split($3, a, ",");
  left_current_line = substr(a[1], 2) - 1;
  right_current_line = left_current_line;
  active_range = 0;
}

# diff before-file after-file
/^diff/ {
  auto_flush_range();
  expect_filename = 1;
}

# + lines are after change only
/^+/ {
  if (!expect_filename) {
    ++right_current_line;
    if (!active_range) {
      modified_from = right_current_line;
    }
    active_range = 1;
  }
}

# print the most recent completed range
function flush_range() {
  if (!is_new_file) {
    if (seen_range) printf(",");
    modified_to = right_current_line;
    if (modified_from == modified_to) printf(modified_from);
    else printf(modified_from "-" modified_to);
  }
  seen_range = 1;
  active_range = 0;
}

function auto_flush_range() {
  if (active_range) {
    flush_range();
  }
}

# <space> lines in unified diffs are common to both before/after
/^ / {
  auto_flush_range();
  ++left_current_line;
  ++right_current_line;
}

# - lines are before change only
/^-/ {
  auto_flush_range();
  ++left_current_line;
}

END {
  # if diff ends with an active range, print it.
  auto_flush_range();
  print "";
}


Added from to the prints.

Added from to the prints.

#![$2] += $NF }
$0 ~ "^Time edu.berkeley.cs.amplab.carat." {
  k = $2
  if ($0 ~ "^Time edu.berkeley.cs.amplab.carat.* from ")
    k = $2" "$4
  sums[k] += $NF
  count[k] += 1
}
$0 ~ "^Time spark.timeseries." {
  k = $2
  if ($0 ~ "^Time spark.timeseries.* from ")
    k = $2" "$4
  sums[k] += $NF
  count[k] += 1
}

END {
  for (k in sums){
    name=k
    gsub("edu.berkeley.cs.amplab.carat.", "", name)
    gsub("spark.timeseries.", "", name)
    print sums[k], sums[k]/count[k], name
  }
}

#![$2] += $NF }
$0 ~ "^Time edu.berkeley.cs.amplab.carat." {
  sums[$2] += $NF
  count[$2] += 1
}
$0 ~ "^Time spark.timeseries." {
  sums[$2] += $NF
  count[$2] += 1
}

END {
  for (k in sums){
    name=k
    gsub("edu.berkeley.cs.amplab.carat.", "", name)
    gsub("spark.timeseries.", "", name)
    print sums[k], sums[k]/count[k], name
  }
}


TestUtils: add test case for curl() (thanks to httpbin.org)

@include "include/Utils"

BEGIN {
    START_TEST("Utils.awk")

    T("GawkVersion", 1)
    {
        initGawk()
        assertTrue(GawkVersion ~ "^4.")
    }

    T("Rlwrap", 1)
    {
        initRlwrap()
        assertEqual(Rlwrap, "rlwrap")
    }

    T("Emacs", 1)
    {
        initEmacs()
        assertEqual(Emacs, "emacs")
    }

    T("newerVersion()", 5)
    {
        assertTrue(newerVersion("0.9", "0.8"))
        assertTrue(newerVersion("0.9.0.1", "0.9.0"))
        assertTrue(newerVersion("1.0", "0.9.9999"))
        assertTrue(newerVersion("1.9.9999", "1.9.10"))
        assertTrue(newerVersion("2", "1.9.9999"))
    }

    T("curl()", 1)
    {
        delete tokens; delete ast
        tokenize(tokens, curl("https://httpbin.org/get"))
        parseJson(ast, tokens)
        assertEqual(unparameterize(ast[0 SUBSEP "url"]),
                    "https://httpbin.org/get")
    }

    T("dump()", 3)
    {
        delete group
        assertEqual(dump("a", group), 1)

        delete group
        assertEqual(dump("Århus", group), 6)

        delete group
        assertEqual(dump("안녕하세요 세계", group), 22)
    }

    T("base64()", 1)
    {
        assertEqual(base64("ninja"), "bmluamE=")
    }

    #T("uprintf", 1)
    #{
    #    assertEqual(uprintf("Ma\\u00f1ana"), "Mañana")
    #}

    END_TEST()
}

@include "include/Utils"

BEGIN {
    START_TEST("Utils.awk")

    T("GawkVersion", 1)
    {
        initGawk()
        assertTrue(GawkVersion ~ "^4.")
    }

    T("Rlwrap", 1)
    {
        initRlwrap()
        assertEqual(Rlwrap, "rlwrap")
    }

    T("Emacs", 1)
    {
        initEmacs()
        assertEqual(Emacs, "emacs")
    }

    T("newerVersion()", 5)
    {
        assertTrue(newerVersion("0.9", "0.8"))
        assertTrue(newerVersion("0.9.0.1", "0.9.0"))
        assertTrue(newerVersion("1.0", "0.9.9999"))
        assertTrue(newerVersion("1.9.9999", "1.9.10"))
        assertTrue(newerVersion("2", "1.9.9999"))
    }

    T("dump()", 3)
    {
        delete group
        assertEqual(dump("a", group), 1)

        delete group
        assertEqual(dump("Århus", group), 6)

        delete group
        assertEqual(dump("안녕하세요 세계", group), 22)
    }

    T("base64()", 1)
    {
        assertEqual(base64("ninja"), "bmluamE=")
    }

    #T("uprintf", 1)
    #{
    #    assertEqual(uprintf("Ma\\u00f1ana"), "Mañana")
    #}

    END_TEST()
}


Java bindings: The DOT constants should be ints (not bytes) so that DOTC (256) can be represented. (dm)

###############################################################################
# libbrlapi - A library providing access to braille terminals for applications.
#
# Copyright (C) 2006-2020 by
#   Samuel Thibault <Samuel.Thibault@ens-lyon.org>
#   Sébastien Hinderer <Sebastien.Hinderer@ens-lyon.org>
#
# libbrlapi comes with ABSOLUTELY NO WARRANTY.
#
# This is free software, placed under the terms of the
# GNU Lesser General Public License, as published by the Free Software
# Foundation; either version 2.1 of the License, or (at your option) any
# later version. Please see the file LICENSE-LGPL for details.
#
# Web Page: http://brltty.app/
#
# This software is maintained by Dave Mielke <dave@mielke.cc>.
###############################################################################

BEGIN {
  print "package org.a11y.brlapi;"
  print ""
  print "public interface Constants {"
}

END {
  print "}"
}

function brlCommand(name, symbol, value, help) {
  writeCommandDefinition(name, value, help)
}

function brlBlock(name, symbol, value, help) {
  if (name == "PASSCHAR") return
  if (name == "PASSKEY") return

  writeCommandDefinition(name, "(" value " << KEY_CMD_BLK_SHIFT)", help)
}

function brlKey(name, symbol, value, help) {
}

function brlFlag(name, symbol, value, help) {
  if (value ~ /^0[xX][0-9a-fA-F]+0000$/) {
    value = hexadecimalValue(substr(value, 1, length(value)-4))
    if (name ~ /^CHAR_/) {
      name = substr(name, 6)
    } else {
      value = value "00"
    }
  } else if (value ~ /^\(/) {
    gsub("BRL_FLG_", "KEY_FLG_", value)
  } else {
    return
  }
  writeJavaConstant("int", "KEY_FLG_" name, value, help)
}

function brlDot(number, symbol, value, help) {
  writeJavaConstant("int", "DOT" number, value, help)
}

function apiConstant(name, symbol, value, help) {
  writeJavaConstant("int", name, value, help);
}

function apiMask(name, symbol, value, help) {
  writeJavaConstant("long", "KEY_" name, hexadecimalValue(value) "L");
}

function apiShift(name, symbol, value, help) {
  writeJavaConstant("int", "KEY_" name, hexadecimalValue(value));
}

function apiType(name, symbol, value, help) {
  writeJavaConstant("int", "KEY_TYPE_" name, hexadecimalValue(value));
}

function apiKey(name, symbol, value, help) {
  value = hexadecimalValue(value)

  if (name == "FUNCTION") {
    for (i=0; i<35; ++i) {
      writeKeyDefinition("F" (i+1), "(" value " + " i ")")
    }
  } else {
    writeKeyDefinition(name, value)
  }
}

function apiRangeType(name, symbol, value, help) {
  writeJavaConstant("int", "rangeType_" name, value, help)
}

function writeCommandDefinition(name, value, help) {
  writeJavaConstant("int", "KEY_CMD_" name, value, help)
}

function writeKeyDefinition(name, value) {
  writeJavaConstant("int", "KEY_SYM_" name, value)
}

function writeJavaConstant(type, name, value, help) {
  writeJavadocComment(help)
  print "  " type " " name " = " value ";"
}

function writeJavadocComment(text) {
  if (length(text) > 0) print "  /** " text " */"
}

function hexadecimalValue(value) {
  value = tolower(value)
  gsub("x0+", "x", value)
  gsub("x$", "x0", value)
  return value
}

###############################################################################
# libbrlapi - A library providing access to braille terminals for applications.
#
# Copyright (C) 2006-2020 by
#   Samuel Thibault <Samuel.Thibault@ens-lyon.org>
#   Sébastien Hinderer <Sebastien.Hinderer@ens-lyon.org>
#
# libbrlapi comes with ABSOLUTELY NO WARRANTY.
#
# This is free software, placed under the terms of the
# GNU Lesser General Public License, as published by the Free Software
# Foundation; either version 2.1 of the License, or (at your option) any
# later version. Please see the file LICENSE-LGPL for details.
#
# Web Page: http://brltty.app/
#
# This software is maintained by Dave Mielke <dave@mielke.cc>.
###############################################################################

BEGIN {
  print "package org.a11y.brlapi;"
  print ""
  print "public interface Constants {"
}

END {
  print "}"
}

function brlCommand(name, symbol, value, help) {
  writeCommandDefinition(name, value, help)
}

function brlBlock(name, symbol, value, help) {
  if (name == "PASSCHAR") return
  if (name == "PASSKEY") return

  writeCommandDefinition(name, "(" value " << KEY_CMD_BLK_SHIFT)", help)
}

function brlKey(name, symbol, value, help) {
}

function brlFlag(name, symbol, value, help) {
  if (value ~ /^0[xX][0-9a-fA-F]+0000$/) {
    value = hexadecimalValue(substr(value, 1, length(value)-4))
    if (name ~ /^CHAR_/) {
      name = substr(name, 6)
    } else {
      value = value "00"
    }
  } else if (value ~ /^\(/) {
    gsub("BRL_FLG_", "KEY_FLG_", value)
  } else {
    return
  }
  writeJavaConstant("int", "KEY_FLG_" name, value, help)
}

function brlDot(number, symbol, value, help) {
  writeJavaConstant("byte", "DOT" number, "(byte) (" value ")", help)
}

function apiConstant(name, symbol, value, help) {
  writeJavaConstant("int", name, value, help);
}

function apiMask(name, symbol, value, help) {
  writeJavaConstant("long", "KEY_" name, hexadecimalValue(value) "L");
}

function apiShift(name, symbol, value, help) {
  writeJavaConstant("int", "KEY_" name, hexadecimalValue(value));
}

function apiType(name, symbol, value, help) {
  writeJavaConstant("int", "KEY_TYPE_" name, hexadecimalValue(value));
}

function apiKey(name, symbol, value, help) {
  value = hexadecimalValue(value)

  if (name == "FUNCTION") {
    for (i=0; i<35; ++i) {
      writeKeyDefinition("F" (i+1), "(" value " + " i ")")
    }
  } else {
    writeKeyDefinition(name, value)
  }
}

function apiRangeType(name, symbol, value, help) {
  writeJavaConstant("int", "rangeType_" name, value, help)
}

function writeCommandDefinition(name, value, help) {
  writeJavaConstant("int", "KEY_CMD_" name, value, help)
}

function writeKeyDefinition(name, value) {
  writeJavaConstant("int", "KEY_SYM_" name, value)
}

function writeJavaConstant(type, name, value, help) {
  writeJavadocComment(help)
  print "  " type " " name " = " value ";"
}

function writeJavadocComment(text) {
  if (length(text) > 0) print "  /** " text " */"
}

function hexadecimalValue(value) {
  value = tolower(value)
  gsub("x0+", "x", value)
  gsub("x$", "x0", value)
  return value
}