Translators/BingTranslator: show error if statusCode is 400

####################################################################
# BingTranslator.awk                                               #
####################################################################
#
# Last Updated: 8 Jun 2022
BEGIN { provides("bing") }

function bingInit() {
    HttpProtocol = "http://"
    HttpHost = "www.bing.com"
    HttpPort = 80
}

# Set IG, IID, and BingTokenKey (a URL-encoded string containing token and key).
function bingSetup(    ast, content, cookie, group, header, isBody, key,
                       location, status, token, tokens, url) {
    url = HttpPathPrefix "/translator"

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

    cookie = NULLSTR
    print header |& HttpService
    while ((HttpService |& getline) > 0) {
        match($0, /Set-Cookie: ([^;]*);/, group)
        if (group[1]) {
            cookie = cookie (cookie ?  "; " : NULLSTR) group[1]
        }
        if (isBody)
            content = content ? content "\n" $0 : $0
        else if (length($0) <= 1)
            isBody = 1
        else { # interesting fields in header
            match($0, /^HTTP[^ ]* ([^ ]*)/, group)
            if (RSTART) status = group[1]
            match($0, /^Location: (.*)/, group)
            if (RSTART) location = squeeze(group[1]) # squeeze the URL!
        }
        l(sprintf("%4s bytes > %s", length($0), length($0) < 1024 ? $0 : "..."))
    }
    close(HttpService)

    if ((status == "301" || status == "302") && location)
        content = curl(location)
    # FIXME: cookie
    Cookie = cookie

    match(content, /IG:"([^"]+)"/, group)
    if (group[1]) {
        IG = group[1]
        l(IG, "IG")
    } else {
        e("[ERROR] Failed to extract IG.")
        exit 1
    }

    match(content, /data-iid="([^"]+)"/, group)
    if (group[1]) {
        IID = group[1]
        l(IID, "IID")
    } else {
        e("[ERROR] Failed to extract IID.")
        exit 1
    }

    match(content, /params_RichTranslateHelper = ([^;]+);/, group)
    if (group[1]) {
        tokenize(tokens, group[1])
        parseJson(ast, tokens)
        key = ast[0 SUBSEP 0]
        token = unparameterize(ast[0 SUBSEP 1])
        BingTokenKey = sprintf("&token=%s&key=%s", quote(token), quote(key))
        l(BingTokenKey, "BingTokenKey")
    } else {
        e("[ERROR] Failed to extract token & key.")
        exit 1
    }
}

# FIXME!
function bingTTSUrl(text, tl,
                    ####
                    country, gender, i, group,
                    header, content, isBody) {
    gender = "female"
    country = NULLSTR
    split(Option["narrator"], group, ",")
    for (i in group) {
        if (group[i] ~ /^(f(emale)?|w(oman)?)$/)
            gender = "female"
        else if (group[i] ~ /^m(ale|an)?$/)
            gender = "male"
        else
            country = group[i]
    }

    # Automatic ISO country code
    if (country) tl = tl "-" country
    else if (tl == "ar") tl = tl "-EG" # sometimes doesn't work. Why?
    else if (tl == "da") tl = tl "-DK"
    else if (tl == "de") tl = tl "-DE"
    else if (tl == "en") tl = tl "-US"
    else if (tl == "es") tl = tl "-ES"
    else if (tl == "fi") tl = tl "-FI"
    else if (tl == "fr") tl = tl "-FR"
    else if (tl == "it") tl = tl "-IT"
    else if (tl == "ja") tl = tl "-JP"
    else if (tl == "ko") tl = tl "-KR"
    else if (tl == "nl") tl = tl "-NL"
    else if (tl == "nb") tl = tl "-NO" # Norwegian Bokmål
    else if (tl == "pl") tl = tl "-PL"
    else if (tl == "pt") tl = tl "-PT"
    else if (tl == "ru") tl = tl "-RU"
    else if (tl == "sv") tl = tl "-SE"
    else if (tl == "yue") ;
    else if (tl == "zh") tl = tl "-CN"

    header = "GET " "/tspeak?"                                          \
        "&language=" tl "&text=" preprocess(text)                       \
        "&options=" gender "&format=audio%2Fmp3" " HTTP/1.1\r\n"        \
        "Host: " HttpHost "\r\n"                                        \
        "Connection: close\r\n"
    if (Option["user-agent"])
        header = header "User-Agent: " Option["user-agent"] "\r\n"
    if (Cookie)
        header = header "Cookie: " Cookie "\r\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), $0))
    }
    close(HttpService)

    if (!TempFile)
        TempFile = getOutput("mktemp")
    printf("%s", content) > TempFile
    close(TempFile)
    return TempFile
}

function bingWebTranslateUrl(uri, sl, tl, hl,    _sl, _tl) {
    # Hot-patches for language codes
    _sl = sl; _tl = tl
    if (_sl == "zh")    _sl = "zh-CHS" # still old format
    if (_sl == "zh-CN") _sl = "zh-CHS"
    if (_sl == "zh-TW") _sl = "zh-CHT"
    if (_tl == "zh")    _tl = "zh-CHS"
    if (_tl == "zh-CN") _tl = "zh-CHS"
    if (_tl == "zh-TW") _tl = "zh-CHT"

    return "https://www.translatetheweb.com/?" "from=" _sl "&to=" _tl "&a=" uri
}

# [OBSOLETE?] Old dictionary API (via HTTP GET).
function bingRequestUrl(text, sl, tl, hl) {
    return HttpPathPrefix "/translator/api/Dictionary/Lookup?"  \
        "from=" sl "&to=" tl "&text=" preprocess(text)
}

# Main Bing Translator API (via HTTP POST).
function bingPostRequestUrl(text, sl, tl, hl, type) {
    if (type == "lookup")
        return HttpPathPrefix "/tlookupv3"
    #else if (type == "transliterate")
    #    return HttpPathPrefix "/ttransliteratev3"
    else # type == "translate"
        return HttpPathPrefix "/ttranslatev3" sprintf("?IG=%s&IID=%s", IG, IID)
}

function bingPostRequestContentType(text, sl, tl, hl, type) {
    return "application/x-www-form-urlencoded"
}

function bingPostRequestUserAgent(text, sl, tl, hl, type) {
    return ""
}

function bingPostRequestBody(text, sl, tl, hl, type) {
    if (type == "lookup")
        return "&text=" quote(text) "&from=" sl "&to=" tl
    #else if (type == "transliterate")
    #    return "&text=" quote(text) "&language=" sl "&toScript=" "latn"
    else # type == "translate"
        return "&text=" quote(text) "&fromLang=" sl "&to=" tl BingTokenKey
}

# Get the translation of a string.
function bingTranslate(text, sl, tl, hl,
                       isVerbose, toSpeech, returnPlaylist, returnIl,
                       ####
                       r,
                       content, tokens, ast, dicContent, dicTokens, dicAst,
                       _sl, _tl, _hl, il, isPhonetic,
                       translation, phonetics, oPhonetics,
                       wordClasses, words, wordBackTranslations,
                       wShowOriginal, wShowOriginalPhonetics,
                       wShowTranslation, wShowTranslationPhonetics,
                       wShowLanguages, wShowDictionary,
                       i, j, k, group, temp, saveSortedIn) {
    isPhonetic = match(tl, /^@/)
    tl = substr(tl, 1 + isPhonetic)

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

    bingSetup()

    # Hot-patches for Bing's own translator language codes
    # See: <https://docs.microsoft.com/en-us/azure/cognitive-services/Translator/language-support>
    if (_sl == "auto")  _sl = "auto-detect"
    if (_sl == "tl")    _sl = "fil" # Bing uses 'fil' for Filipino
    if (_sl == "hmn")   _sl = "mww" # Bing uses 'mww' for Hmong Daw
    if (_sl == "ku")    _sl = "kmr" # Bing uses 'kmr' for Northern Kurdish
    else if (_sl == "ckb") _sl = "ku" # and 'ku' for Central Kurdish
    if (_sl == "mn")    _sl = "mn-Cyrl" # Bing uses 'mn-Cyrl' for Mongolian (Cyrillic)
    if (_sl == "no")    _sl = "nb"  # Bing uses Norwegian Bokmål
    # Bing uses 'pt' or 'pt-br' for Brazilian Portuguese, 'pt-pt' for European Portuguese
    if (_sl == "pt-BR") _sl = "pt" # just pt-br
    else if (_sl == "pt-PT") _sl = "pt" # FIXME: support pt-pt
    if (_sl == "zh-CN") _sl = "zh-Hans"
    if (_sl == "zh-TW") _sl = "zh-Hant"
    if (_tl == "tl")    _tl = "fil"
    if (_tl == "hmn")   _tl = "mww"
    if (_tl == "ku")    _tl = "kmr"
    else if (_tl == "ckb") _tl = "ku"
    if (_tl == "mn")    _tl = "mn-Cyrl"
    if (_tl == "no")    _tl = "nb"
    if (_tl == "pt-BR") _tl = "pt"
    else if (_tl == "pt-PT") _tl = "pt-pt"
    if (_tl == "zh-CN") _tl = "zh-Hans"
    if (_tl == "zh-TW") _tl = "zh-Hant"

    # Translation
    content = postResponse(text, _sl, _tl, _hl, "translate")
    if (content == "") {
        # Empty content. Assume "301 Moved Permanently" and use cn.bing.com
        HttpHost = "cn.bing.com"
        # Just dirty hack
        if (Option["proxy"]) {
            HttpPathPrefix = HttpProtocol HttpHost
        } else {
            HttpService = "/" "inet" "/tcp/0/" HttpHost "/" HttpPort  # FIXME: inet version
        }

        # Try again
        content = postResponse(text, _sl, _tl, _hl, "translate")
    }
    if (Option["dump"])
        return content
    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
    }

    if (ast[0 SUBSEP "statusCode"] == "400") {
        e("[ERROR] " ucfirst(Option["engine"]) " does not support the specified language(s)")
        ExitCode = 1
        return
    }

    translation = unparameterize(ast[0 SUBSEP 0 SUBSEP "translations" SUBSEP 0 SUBSEP "text"])

    returnIl[0] = il = _sl == "auto-detect" ?
        unparameterize(ast[0 SUBSEP 0 SUBSEP "detectedLanguage" SUBSEP "language"]) : _sl
    if (Option["verbose"] < -1)
        return il
    if (Option["verbose"] < 0)
        return getList(il)

    # Transliteration
    wShowTranslationPhonetics = Option["show-translation-phonetics"]
    if (wShowTranslationPhonetics) {
        split(_tl, group, "-")
        #content = postResponse(translation, group[1], group[1], _hl, "transliterate")
        #phonetics = unparameterize(content)
        phonetics = unparameterize(ast[0 SUBSEP 0 SUBSEP "translations" SUBSEP 0 SUBSEP "transliteration" \
                                       SUBSEP "text"])
        if (phonetics == translation) phonetics = ""
    }

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

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

    } else {
        # Verbose mode

        wShowOriginal = Option["show-original"]
        wShowTranslation = Option["show-translation"]
        wShowLanguages = Option["show-languages"]
        wShowDictionary = Option["show-dictionary"]

        # Transliteration (original)
        wShowOriginalPhonetics = Option["show-original-phonetics"]
        if (wShowOriginalPhonetics) {
            split(_sl, group, "-")
            #content = postResponse(text, group[1], group[1], _hl, "transliterate")
            #oPhonetics = unparameterize(content)
            delete ast  # purge old AST
            content = postResponse(text, il, il, _hl, "translate")
            tokenize(tokens, content)
            parseJson(ast, tokens)
            oPhonetics = unparameterize(ast[0 SUBSEP 0 SUBSEP "translations" SUBSEP 0 \
                                            SUBSEP "transliteration" SUBSEP "text"])
            if (oPhonetics == text) oPhonetics = ""
        }

        if (!oPhonetics) wShowOriginalPhonetics = 0
        if (!phonetics) wShowTranslationPhonetics = 0

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

        if (wShowTranslation) {
            # Display: major translation & phonetics
            if (r) r = r RS RS
            r = r m("-- display major translation")
            r = r prettify("translation", s(translation, tl))
            if (wShowTranslationPhonetics)
                r = r RS prettify("translation-phonetics", showPhonetics(join(phonetics, " "), 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 (wShowDictionary) {
            # Dictionary API
            dicContent = postResponse(text, il, _tl, _hl, "lookup")
            if (dicContent != "") {
                tokenize(dicTokens, dicContent)
                parseJson(dicAst, dicTokens)

                l(dicContent, "dicContent", 1, 1)
                l(dicTokens, "dicTokens", 1, 0, 1)
                l(dicAst, "dicAst")

                saveSortedIn = PROCINFO["sorted_in"]
                PROCINFO["sorted_in"] = "compareByIndexFields"
                for (i in dicAst) {
                    if (match(i, "^0" SUBSEP "0" SUBSEP "translations" SUBSEP "([[:digit:]]+)" SUBSEP \
                              "posTag$", group))
                        wordClasses[group[1]] = tolower(literal(dicAst[i]))
                }
                for (i in dicAst) {
                    if (match(i, "^0" SUBSEP "0" SUBSEP "translations" SUBSEP "([[:digit:]]+)" SUBSEP \
                              "displayTarget$", group))
                        words[wordClasses[group[1]]][group[1]] = literal(dicAst[i])
                    if (match(i, "^0" SUBSEP "0" SUBSEP "translations" SUBSEP "([[:digit:]]+)" SUBSEP \
                              "backTranslations" SUBSEP "([[:digit:]]+)" SUBSEP "displayText$", group))
                        wordBackTranslations[wordClasses[group[1]]][group[1]][group[2]] = literal(dicAst[i])
                }
                PROCINFO["sorted_in"] = saveSortedIn

                # Display: dictionary entries
                if (r) r = r RS
                r = r m("-- display dictionary entries")
                for (i = 0; i < length(words); i++) {
                    r = (i > 0 ? r RS : r) RS prettify("dictionary-word-class", s(wordClasses[i], hl))

                    for (j in words[wordClasses[i]]) {
                        r = r RS prettify("dictionary-word", ins(1, words[wordClasses[i]][j], tl))

                        if (isRTL(il))
                            explanation = join(wordBackTranslations[wordClasses[i]][j], ", ")
                        else {
                            explanation = prettify("dictionary-explanation-item",
                                                   wordBackTranslations[wordClasses[i]][j][0])
                            for (k = 1; k < length(wordBackTranslations[wordClasses[i]][j]); k++)
                                explanation = explanation prettify("dictionary-explanation", ", ") \
                                    prettify("dictionary-explanation-item",
                                             wordBackTranslations[wordClasses[i]][j][k])
                        }

                        if (isRTL(il))
                            r = r RS prettify("dictionary-explanation-item", ins(2, explanation, il))
                        else
                            r = r RS ins(2, explanation)
                    }
                }
            }
        }
    }

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

    return r
}

####################################################################
# BingTranslator.awk                                               #
####################################################################
#
# Last Updated: 8 Jun 2022
BEGIN { provides("bing") }

function bingInit() {
    HttpProtocol = "http://"
    HttpHost = "www.bing.com"
    HttpPort = 80
}

# Set IG, IID, and BingTokenKey (a URL-encoded string containing token and key).
function bingSetup(    ast, content, cookie, group, header, isBody, key,
                       location, status, token, tokens, url) {
    url = HttpPathPrefix "/translator"

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

    cookie = NULLSTR
    print header |& HttpService
    while ((HttpService |& getline) > 0) {
        match($0, /Set-Cookie: ([^;]*);/, group)
        if (group[1]) {
            cookie = cookie (cookie ?  "; " : NULLSTR) group[1]
        }
        if (isBody)
            content = content ? content "\n" $0 : $0
        else if (length($0) <= 1)
            isBody = 1
        else { # interesting fields in header
            match($0, /^HTTP[^ ]* ([^ ]*)/, group)
            if (RSTART) status = group[1]
            match($0, /^Location: (.*)/, group)
            if (RSTART) location = squeeze(group[1]) # squeeze the URL!
        }
        l(sprintf("%4s bytes > %s", length($0), length($0) < 1024 ? $0 : "..."))
    }
    close(HttpService)

    if ((status == "301" || status == "302") && location)
        content = curl(location)
    # FIXME: cookie
    Cookie = cookie

    match(content, /IG:"([^"]+)"/, group)
    if (group[1]) {
        IG = group[1]
        l(IG, "IG")
    } else {
        e("[ERROR] Failed to extract IG.")
        exit 1
    }

    match(content, /data-iid="([^"]+)"/, group)
    if (group[1]) {
        IID = group[1]
        l(IID, "IID")
    } else {
        e("[ERROR] Failed to extract IID.")
        exit 1
    }

    match(content, /params_RichTranslateHelper = ([^;]+);/, group)
    if (group[1]) {
        tokenize(tokens, group[1])
        parseJson(ast, tokens)
        key = ast[0 SUBSEP 0]
        token = unparameterize(ast[0 SUBSEP 1])
        BingTokenKey = sprintf("&token=%s&key=%s", quote(token), quote(key))
        l(BingTokenKey, "BingTokenKey")
    } else {
        e("[ERROR] Failed to extract token & key.")
        exit 1
    }
}

# FIXME!
function bingTTSUrl(text, tl,
                    ####
                    country, gender, i, group,
                    header, content, isBody) {
    gender = "female"
    country = NULLSTR
    split(Option["narrator"], group, ",")
    for (i in group) {
        if (group[i] ~ /^(f(emale)?|w(oman)?)$/)
            gender = "female"
        else if (group[i] ~ /^m(ale|an)?$/)
            gender = "male"
        else
            country = group[i]
    }

    # Automatic ISO country code
    if (country) tl = tl "-" country
    else if (tl == "ar") tl = tl "-EG" # sometimes doesn't work. Why?
    else if (tl == "da") tl = tl "-DK"
    else if (tl == "de") tl = tl "-DE"
    else if (tl == "en") tl = tl "-US"
    else if (tl == "es") tl = tl "-ES"
    else if (tl == "fi") tl = tl "-FI"
    else if (tl == "fr") tl = tl "-FR"
    else if (tl == "it") tl = tl "-IT"
    else if (tl == "ja") tl = tl "-JP"
    else if (tl == "ko") tl = tl "-KR"
    else if (tl == "nl") tl = tl "-NL"
    else if (tl == "nb") tl = tl "-NO" # Norwegian Bokmål
    else if (tl == "pl") tl = tl "-PL"
    else if (tl == "pt") tl = tl "-PT"
    else if (tl == "ru") tl = tl "-RU"
    else if (tl == "sv") tl = tl "-SE"
    else if (tl == "yue") ;
    else if (tl == "zh") tl = tl "-CN"

    header = "GET " "/tspeak?"                                          \
        "&language=" tl "&text=" preprocess(text)                       \
        "&options=" gender "&format=audio%2Fmp3" " HTTP/1.1\r\n"        \
        "Host: " HttpHost "\r\n"                                        \
        "Connection: close\r\n"
    if (Option["user-agent"])
        header = header "User-Agent: " Option["user-agent"] "\r\n"
    if (Cookie)
        header = header "Cookie: " Cookie "\r\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), $0))
    }
    close(HttpService)

    if (!TempFile)
        TempFile = getOutput("mktemp")
    printf("%s", content) > TempFile
    close(TempFile)
    return TempFile
}

function bingWebTranslateUrl(uri, sl, tl, hl,    _sl, _tl) {
    # Hot-patches for language codes
    _sl = sl; _tl = tl
    if (_sl == "zh")    _sl = "zh-CHS" # still old format
    if (_sl == "zh-CN") _sl = "zh-CHS"
    if (_sl == "zh-TW") _sl = "zh-CHT"
    if (_tl == "zh")    _tl = "zh-CHS"
    if (_tl == "zh-CN") _tl = "zh-CHS"
    if (_tl == "zh-TW") _tl = "zh-CHT"

    return "https://www.translatetheweb.com/?" "from=" _sl "&to=" _tl "&a=" uri
}

# [OBSOLETE?] Old dictionary API (via HTTP GET).
function bingRequestUrl(text, sl, tl, hl) {
    return HttpPathPrefix "/translator/api/Dictionary/Lookup?"  \
        "from=" sl "&to=" tl "&text=" preprocess(text)
}

# Main Bing Translator API (via HTTP POST).
function bingPostRequestUrl(text, sl, tl, hl, type) {
    if (type == "lookup")
        return HttpPathPrefix "/tlookupv3"
    #else if (type == "transliterate")
    #    return HttpPathPrefix "/ttransliteratev3"
    else # type == "translate"
        return HttpPathPrefix "/ttranslatev3" sprintf("?IG=%s&IID=%s", IG, IID)
}

function bingPostRequestContentType(text, sl, tl, hl, type) {
    return "application/x-www-form-urlencoded"
}

function bingPostRequestUserAgent(text, sl, tl, hl, type) {
    return ""
}

function bingPostRequestBody(text, sl, tl, hl, type) {
    if (type == "lookup")
        return "&text=" quote(text) "&from=" sl "&to=" tl
    #else if (type == "transliterate")
    #    return "&text=" quote(text) "&language=" sl "&toScript=" "latn"
    else # type == "translate"
        return "&text=" quote(text) "&fromLang=" sl "&to=" tl BingTokenKey
}

# Get the translation of a string.
function bingTranslate(text, sl, tl, hl,
                       isVerbose, toSpeech, returnPlaylist, returnIl,
                       ####
                       r,
                       content, tokens, ast, dicContent, dicTokens, dicAst,
                       _sl, _tl, _hl, il, isPhonetic,
                       translation, phonetics, oPhonetics,
                       wordClasses, words, wordBackTranslations,
                       wShowOriginal, wShowOriginalPhonetics,
                       wShowTranslation, wShowTranslationPhonetics,
                       wShowLanguages, wShowDictionary,
                       i, j, k, group, temp, saveSortedIn) {
    isPhonetic = match(tl, /^@/)
    tl = substr(tl, 1 + isPhonetic)

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

    bingSetup()

    # Hot-patches for Bing's own translator language codes
    # See: <https://docs.microsoft.com/en-us/azure/cognitive-services/Translator/language-support>
    if (_sl == "auto")  _sl = "auto-detect"
    if (_sl == "tl")    _sl = "fil" # Bing uses 'fil' for Filipino
    if (_sl == "hmn")   _sl = "mww" # Bing uses 'mww' for Hmong Daw
    if (_sl == "ku")    _sl = "kmr" # Bing uses 'kmr' for Northern Kurdish
    else if (_sl == "ckb") _sl = "ku" # and 'ku' for Central Kurdish
    if (_sl == "mn")    _sl = "mn-Cyrl" # Bing uses 'mn-Cyrl' for Mongolian (Cyrillic)
    if (_sl == "no")    _sl = "nb"  # Bing uses Norwegian Bokmål
    # Bing uses 'pt' or 'pt-br' for Brazilian Portuguese, 'pt-pt' for European Portuguese
    if (_sl == "pt-BR") _sl = "pt" # just pt-br
    else if (_sl == "pt-PT") _sl = "pt" # FIXME: support pt-pt
    if (_sl == "zh-CN") _sl = "zh-Hans"
    if (_sl == "zh-TW") _sl = "zh-Hant"
    if (_tl == "tl")    _tl = "fil"
    if (_tl == "hmn")   _tl = "mww"
    if (_tl == "ku")    _tl = "kmr"
    else if (_tl == "ckb") _tl = "ku"
    if (_tl == "mn")    _tl = "mn-Cyrl"
    if (_tl == "no")    _tl = "nb"
    if (_tl == "pt-BR") _tl = "pt"
    else if (_tl == "pt-PT") _tl = "pt-pt"
    if (_tl == "zh-CN") _tl = "zh-Hans"
    if (_tl == "zh-TW") _tl = "zh-Hant"

    # Translation
    content = postResponse(text, _sl, _tl, _hl, "translate")
    if (content == "") {
        # Empty content. Assume "301 Moved Permanently" and use cn.bing.com
        HttpHost = "cn.bing.com"
        # Just dirty hack
        if (Option["proxy"]) {
            HttpPathPrefix = HttpProtocol HttpHost
        } else {
            HttpService = "/" "inet" "/tcp/0/" HttpHost "/" HttpPort  # FIXME: inet version
        }

        # Try again
        content = postResponse(text, _sl, _tl, _hl, "translate")
    }
    if (Option["dump"])
        return content
    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 "translations" SUBSEP 0 SUBSEP "text"])

    returnIl[0] = il = _sl == "auto-detect" ?
        unparameterize(ast[0 SUBSEP 0 SUBSEP "detectedLanguage" SUBSEP "language"]) : _sl
    if (Option["verbose"] < -1)
        return il
    if (Option["verbose"] < 0)
        return getList(il)

    # Transliteration
    wShowTranslationPhonetics = Option["show-translation-phonetics"]
    if (wShowTranslationPhonetics) {
        split(_tl, group, "-")
        #content = postResponse(translation, group[1], group[1], _hl, "transliterate")
        #phonetics = unparameterize(content)
        phonetics = unparameterize(ast[0 SUBSEP 0 SUBSEP "translations" SUBSEP 0 SUBSEP "transliteration" \
                                       SUBSEP "text"])
        if (phonetics == translation) phonetics = ""
    }

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

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

    } else {
        # Verbose mode

        wShowOriginal = Option["show-original"]
        wShowTranslation = Option["show-translation"]
        wShowLanguages = Option["show-languages"]
        wShowDictionary = Option["show-dictionary"]

        # Transliteration (original)
        wShowOriginalPhonetics = Option["show-original-phonetics"]
        if (wShowOriginalPhonetics) {
            split(_sl, group, "-")
            #content = postResponse(text, group[1], group[1], _hl, "transliterate")
            #oPhonetics = unparameterize(content)
            delete ast  # purge old AST
            content = postResponse(text, il, il, _hl, "translate")
            tokenize(tokens, content)
            parseJson(ast, tokens)
            oPhonetics = unparameterize(ast[0 SUBSEP 0 SUBSEP "translations" SUBSEP 0 \
                                            SUBSEP "transliteration" SUBSEP "text"])
            if (oPhonetics == text) oPhonetics = ""
        }

        if (!oPhonetics) wShowOriginalPhonetics = 0
        if (!phonetics) wShowTranslationPhonetics = 0

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

        if (wShowTranslation) {
            # Display: major translation & phonetics
            if (r) r = r RS RS
            r = r m("-- display major translation")
            r = r prettify("translation", s(translation, tl))
            if (wShowTranslationPhonetics)
                r = r RS prettify("translation-phonetics", showPhonetics(join(phonetics, " "), 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 (wShowDictionary) {
            # Dictionary API
            dicContent = postResponse(text, il, _tl, _hl, "lookup")
            if (dicContent != "") {
                tokenize(dicTokens, dicContent)
                parseJson(dicAst, dicTokens)

                l(dicContent, "dicContent", 1, 1)
                l(dicTokens, "dicTokens", 1, 0, 1)
                l(dicAst, "dicAst")

                saveSortedIn = PROCINFO["sorted_in"]
                PROCINFO["sorted_in"] = "compareByIndexFields"
                for (i in dicAst) {
                    if (match(i, "^0" SUBSEP "0" SUBSEP "translations" SUBSEP "([[:digit:]]+)" SUBSEP \
                              "posTag$", group))
                        wordClasses[group[1]] = tolower(literal(dicAst[i]))
                }
                for (i in dicAst) {
                    if (match(i, "^0" SUBSEP "0" SUBSEP "translations" SUBSEP "([[:digit:]]+)" SUBSEP \
                              "displayTarget$", group))
                        words[wordClasses[group[1]]][group[1]] = literal(dicAst[i])
                    if (match(i, "^0" SUBSEP "0" SUBSEP "translations" SUBSEP "([[:digit:]]+)" SUBSEP \
                              "backTranslations" SUBSEP "([[:digit:]]+)" SUBSEP "displayText$", group))
                        wordBackTranslations[wordClasses[group[1]]][group[1]][group[2]] = literal(dicAst[i])
                }
                PROCINFO["sorted_in"] = saveSortedIn

                # Display: dictionary entries
                if (r) r = r RS
                r = r m("-- display dictionary entries")
                for (i = 0; i < length(words); i++) {
                    r = (i > 0 ? r RS : r) RS prettify("dictionary-word-class", s(wordClasses[i], hl))

                    for (j in words[wordClasses[i]]) {
                        r = r RS prettify("dictionary-word", ins(1, words[wordClasses[i]][j], tl))

                        if (isRTL(il))
                            explanation = join(wordBackTranslations[wordClasses[i]][j], ", ")
                        else {
                            explanation = prettify("dictionary-explanation-item",
                                                   wordBackTranslations[wordClasses[i]][j][0])
                            for (k = 1; k < length(wordBackTranslations[wordClasses[i]][j]); k++)
                                explanation = explanation prettify("dictionary-explanation", ", ") \
                                    prettify("dictionary-explanation-item",
                                             wordBackTranslations[wordClasses[i]][j][k])
                        }

                        if (isRTL(il))
                            r = r RS prettify("dictionary-explanation-item", ins(2, explanation, il))
                        else
                            r = r RS ins(2, explanation)
                    }
                }
            }
        }
    }

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

    return r
}


Add Javadoc comments to the constants. (dm)

git-svn-id: 30a5f035a20f1bc647618dbad7eea2a951b61b7c@2613 91a5dbb7-01b9-0310-9b5f-b28072856b6e

###############################################################################
# BRLTTY - A background process providing access to the console screen (when in
#          text mode) for a blind person using a refreshable braille display.
#
# Copyright (C) 1995-2006 by The BRLTTY Developers.
#
# BRLTTY comes with ABSOLUTELY NO WARRANTY.
#
# This is free software, placed under the terms of the
# GNU General Public License, as published by the Free Software
# Foundation.  Please see the file COPYING for details.
#
# Web Page: http://mielke.cc/brltty/
#
# This software is maintained by Dave Mielke <dave@mielke.cc>.
###############################################################################

BEGIN {
  print "public interface BrlapiConstants {"
}

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

  if (value ~ /^0[xX][0-9a-fA-F]+00$/) {
    writeCommandDefinition(name, toupper(value) "00", help)
  }
}

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

function brlFlag(name, symbol, value, help) {
  if (value ~ /^0[xX][0-9a-fA-F]+0000$/) {
    value = toupper(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("KEY_FLG_" name, value, help)
}

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

function apiType(name, symbol, value, help) {
  writeJavaConstant("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 writeCommandDefinition(name, value, help) {
  writeJavaConstant("KEY_CMD_" name, "(KEY_TYPE_CMD | " value ")", help)
}

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

function writeJavaConstant(name, value, help) {
  writeJavadocComment(help)
  print "  public static final int " name " = " value ";"
}

function writeJavadocComment(text) {
  print "  /** " text " */"
}

function hexadecimalValue(value) {
  gsub("[uU]?[lL]*$", "", value)
  return value
}

###############################################################################
# BRLTTY - A background process providing access to the console screen (when in
#          text mode) for a blind person using a refreshable braille display.
#
# Copyright (C) 1995-2006 by The BRLTTY Developers.
#
# BRLTTY comes with ABSOLUTELY NO WARRANTY.
#
# This is free software, placed under the terms of the
# GNU General Public License, as published by the Free Software
# Foundation.  Please see the file COPYING for details.
#
# Web Page: http://mielke.cc/brltty/
#
# This software is maintained by Dave Mielke <dave@mielke.cc>.
###############################################################################

BEGIN {
  print "public interface BrlapiConstants {"
}

END {
  print "}"
}

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

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

  if (value ~ /^0[xX][0-9a-fA-F]+00$/) {
    writeCommandDefinition(name, toupper(value) "00")
  }
}

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

function brlFlag(name, symbol, value, help) {
  if (value ~ /^0[xX][0-9a-fA-F]+0000$/) {
    value = toupper(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("KEY_FLG_" name, value)
}

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

function apiType(name, symbol, value, help) {
  writeJavaConstant("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 writeCommandDefinition(name, value) {
  writeJavaConstant("KEY_CMD_" name, "(KEY_TYPE_CMD | " value ")")
}

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

function writeJavaConstant(name, value) {
  print "  public static final int " name " = " value ";"
}

function hexadecimalValue(value) {
  gsub("[uU]?[lL]*$", "", value)
  return value
}


makeDistortosConfiguration.awk: add missing support for hex numbers

#!/usr/bin/awk -f

#
# file: makeDistortosConfiguration.awk
#
# author: Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
#
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
# distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# date: 2015-08-25
#

BEGIN {
	configPattern = "CONFIG_[A-Za-z0-9_]+"
	booleanTrueConfigPattern = "^" configPattern "=y$"
	booleanFalseConfigPattern = "^" configPattern "=n$"
	notSetConfigPattern = "^# " configPattern " is not set$"
	numericConfigPattern = "^" configPattern "=(([[:digit:]]+)|(0x[[:xdigit:]]+))$"
	stringConfigPattern = "^" configPattern "=\"([^\"\\\\]|\\\\.)*\"$"

	print "/**"
	print " * \\file"
	print " * \\brief distortos configuration"
	print " *"
	print " * \\warning"
	print " * Automatically generated file - do not edit!"
	print " *"
	print " * \\date " strftime("%Y-%m-%d %H:%M:%S")
	print " */"
	print ""
	print "#ifndef INCLUDE_DISTORTOS_DISTORTOSCONFIGURATION_H_"
	print "#define INCLUDE_DISTORTOS_DISTORTOSCONFIGURATION_H_"
	print ""
}

$0 ~ booleanTrueConfigPattern {
	split($0, array, "=")
	print "#define " array[1]
}

$0 ~ booleanFalseConfigPattern {
	split($0, array, "=")
	print "#undef " array[1]
}

$0 ~ notSetConfigPattern {
	print "#undef " $2
}

$0 ~ numericConfigPattern {
	split($0, array, "=")
	print "#define " array[1] " " array[2]
}

$0 ~ stringConfigPattern {
	split($0, array, "=")
	print "#define " array[1] " " array[2]
}

END {
	print ""
	print "#endif	/* INCLUDE_DISTORTOS_DISTORTOSCONFIGURATION_H_ */"
}

#!/usr/bin/awk -f

#
# file: makeDistortosConfiguration.awk
#
# author: Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
#
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
# distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# date: 2015-08-21
#

BEGIN {
	configPattern = "CONFIG_[A-Za-z0-9_]+"
	booleanTrueConfigPattern = "^" configPattern "=y$"
	booleanFalseConfigPattern = "^" configPattern "=n$"
	notSetConfigPattern = "^# " configPattern " is not set$"
	numericConfigPattern = "^" configPattern "=[[:digit:]]+$"
	stringConfigPattern = "^" configPattern "=\"([^\"\\\\]|\\\\.)*\"$"

	print "/**"
	print " * \\file"
	print " * \\brief distortos configuration"
	print " *"
	print " * \\warning"
	print " * Automatically generated file - do not edit!"
	print " *"
	print " * \\date " strftime("%Y-%m-%d %H:%M:%S")
	print " */"
	print ""
	print "#ifndef INCLUDE_DISTORTOS_DISTORTOSCONFIGURATION_H_"
	print "#define INCLUDE_DISTORTOS_DISTORTOSCONFIGURATION_H_"
	print ""
}

$0 ~ booleanTrueConfigPattern {
	split($0, array, "=")
	print "#define " array[1]
}

$0 ~ booleanFalseConfigPattern {
	split($0, array, "=")
	print "#undef " array[1]
}

$0 ~ notSetConfigPattern {
	print "#undef " $2
}

$0 ~ numericConfigPattern {
	split($0, array, "=")
	print "#define " array[1] " " array[2]
}

$0 ~ stringConfigPattern {
	split($0, array, "=")
	print "#define " array[1] " " array[2]
}

END {
	print ""
	print "#endif	/* INCLUDE_DISTORTOS_DISTORTOSCONFIGURATION_H_ */"
}


indentation: fix awful mixture of tabs and spaces

BEGIN {
  n_matches = 0;
  line_pos = 0;
  col_pos = 0;
  COMPACT_HINTS = ENVIRON["COMPACT_HINTS"];

  HINTS[0] = "p"
  HINTS[1] = "o"
  HINTS[2] = "i"
  HINTS[3] = "u"
  HINTS[4] = "l"
  HINTS[5] = "k"
  HINTS[6] = "j"
  HINTS[7] = "t"
  HINTS[8] = "r"
  HINTS[9] = "e"
  HINTS[10] = "wj"
  HINTS[11] = "wt"
  HINTS[12] = "wr"
  HINTS[13] = "we"
  HINTS[14] = "ww"
  HINTS[15] = "wq"
  HINTS[16] = "wf"
  HINTS[17] = "wd"
  HINTS[18] = "ws"
  HINTS[19] = "wa"
  HINTS[20] = "qp"
  HINTS[21] = "qo"
  HINTS[22] = "qi"
  HINTS[23] = "qu"
  HINTS[24] = "ql"
  HINTS[25] = "qk"
  HINTS[26] = "qj"
  HINTS[27] = "qt"
  HINTS[28] = "qr"
  HINTS[29] = "qe"
  HINTS[30] = "qw"
  HINTS[31] = "qq"
  HINTS[32] = "qf"
  HINTS[33] = "qd"
  HINTS[34] = "qs"
  HINTS[35] = "qa"
  HINTS[36] = "fp"
  HINTS[37] = "fo"
  HINTS[38] = "fi"
  HINTS[39] = "fu"
  HINTS[40] = "fl"
  HINTS[41] = "fk"
  HINTS[42] = "fj"
  HINTS[43] = "ft"
  HINTS[44] = "fr"
  HINTS[45] = "fe"
  HINTS[46] = "fw"
  HINTS[47] = "fq"
  HINTS[48] = "ff"
  HINTS[49] = "fd"
  HINTS[50] = "fs"
  HINTS[51] = "fa"
  HINTS[52] = "dp"
  HINTS[53] = "do"
  HINTS[54] = "di"
  HINTS[55] = "du"
  HINTS[56] = "dl"
  HINTS[57] = "dk"
  HINTS[58] = "dj"
  HINTS[59] = "dt"
  HINTS[60] = "dr"
  HINTS[61] = "de"
  HINTS[62] = "dw"
  HINTS[63] = "dq"
  HINTS[64] = "df"
  HINTS[65] = "dd"
  HINTS[66] = "ds"
  HINTS[67] = "da"
  HINTS[68] = "sp"
  HINTS[69] = "so"
  HINTS[70] = "si"
  HINTS[71] = "su"
  HINTS[72] = "sl"
  HINTS[73] = "sk"
  HINTS[74] = "sj"
  HINTS[75] = "st"
  HINTS[76] = "sr"
  HINTS[77] = "se"
  HINTS[78] = "sw"
  HINTS[79] = "sq"
  HINTS[80] = "sf"
  HINTS[81] = "sd"
  HINTS[82] = "ss"
  HINTS[83] = "sa"
  HINTS[84] = "ap"
  HINTS[85] = "ao"
  HINTS[86] = "ai"
  HINTS[87] = "au"
  HINTS[88] = "al"
  HINTS[89] = "ak"
  HINTS[90] = "aj"
  HINTS[91] = "at"
  HINTS[92] = "ar"
  HINTS[93] = "ae"
  HINTS[94] = "aw"
  HINTS[95] = "aq"
  HINTS[96] = "af"
  HINTS[97] = "ad"
  HINTS[98] = "as"
  HINTS[99] = "aa"

  finger_patterns = ENVIRON["FINGER_PATTERNS"];

  if (COMPACT_HINTS) {
    hint_format = "\033[30;1;43m%s\033[0m"
    highlight_format = "\033[1;33m%s\033[0m"
    compound_format = hint_format highlight_format
  } else {
    hint_format = "\033[1;33m[%s]\033[0m"
    highlight_format = "\033[1;33m%s\033[0m "
    compound_format = highlight_format hint_format
  }

  hint_lookup = ""
}

{
  line = $0;
  pos = 0;
  col_pos = 0;
  col_pos_correction = 0;

  output_line = line;

  while (match(line, finger_patterns)) {
    n_matches += 1;

    hint = HINTS[n_matches - 1]
    pos += RSTART;

    col_pos = pos;

    line_match = substr(line, RSTART, RLENGTH);
    full_line_match = line_match

    if (COMPACT_HINTS) {
      hint_len = length(hint)
      line_match = substr(line_match, hint_len + 1, length(line_match) - hint_len);
    }

    col_pos = col_pos + col_pos_correction

    line_pos = NR;

    pre_match = substr(output_line, 0, col_pos - 1);

    if (COMPACT_HINTS) {
      hint_match = sprintf(compound_format, hint, line_match);
    } else {
      hint_match = sprintf(compound_format, line_match, hint);
    }

    post_match = substr(output_line, col_pos + RLENGTH, length(line) - 1);

    output_line = pre_match hint_match post_match;

    line = post_match;

    col_pos_correction += length(sprintf(highlight_format, line_match)) + length(sprintf(hint_format, hint)) - 1;

    hint_lookup = hint_lookup hint ":" full_line_match "\n"
  }

  printf "\n%s", output_line
}

END {
  print hint_lookup | "cat 1>&3"
}


INTEGRATION: CWS localefallback (1.1.386); FILE MERGED 2007/07/05 11:19:59 er 1.1.386.1: beautify output

#!/usr/bin/gawk -f
#// Usage: gawk -f list-locales.awk *.xml
#// Simply create a verbose list of known locales as stated in XML files.
#// Author: Eike Rathke <erack@sun.com>

BEGIN {
    file = ""
    count = 0
}

function init_locale() {
    lcinfo = 0
    inlang = 0
    incoun = 0
    language = ""
    country = ""
}

FILENAME != file {
    printEntry()
    file = FILENAME
    ++count
    init_locale()
}

{
    if ( !lcinfo )
    {
        if ( /<LC_INFO>/ )
            lcinfo = 1
        next
    }
    if ( /<\/LC_INFO>/ )
    {
        lcinfo = 0
        next
    }
    if ( /<Language>/ )
        inlang = 1
    if ( inlang && /<DefaultName>/ )
    {
        split( $0, x, /<|>/ )
        language = x[3]
    }
    if ( /<\/Language>/ )
        inlang = 0
    if ( /<Country>/ )
        incoun = 1
    if ( incoun && /<DefaultName>/ )
    {
        split( $0, x, /<|>/ )
        country = x[3]
    }
    if ( /<\/Country>/ )
        incoun = 0
}

END {
    printEntry()
    print "\n" count " locales"
}

function printEntry() {
    if ( file )
    {
        tmp = file
        gsub( /.*\//, "", tmp )
        gsub( /\.xml/, "", tmp )
        split( tmp, iso, /_/ )
        if ( iso[2] )
            printf( "%3s_%2s: %s - %s\n", iso[1], iso[2], language, country )
        else
            printf( "%3s %2s: %s   %s\n", iso[1], iso[2], language, country )
    }
}

#!/usr/bin/gawk -f
#// Usage: gawk -f list-locales.awk *.xml
#// Simply create a verbose list of known locales as stated in XML files.
#// Author: Eike Rathke <erack@sun.com>

BEGIN {
    lcinfo = 0
    inlang = 0
    incoun = 0
    file = ""
    language = ""
    country = ""
}

FILENAME != file {
    printEntry()
    file = FILENAME
}

{
    if ( !lcinfo )
    {
        if ( /<LC_INFO>/ )
            lcinfo = 1
        next
    }
    if ( /<\/LC_INFO>/ )
    {
        lcinfo = 0
        next
    }
    if ( /<Language>/ )
        inlang = 1
    if ( inlang && /<DefaultName>/ )
    {
        split( $0, x, /<|>/ )
        language = x[3]
    }
    if ( /<\/Language>/ )
        inlang = 0
    if ( /<Country>/ )
        incoun = 1
    if ( incoun && /<DefaultName>/ )
    {
        split( $0, x, /<|>/ )
        country = x[3]
    }
    if ( /<\/Country>/ )
        incoun = 0
}

END {
    printEntry()
}

function printEntry() {
    if ( file )
        printf( "%s: %s %s\n", file, language, country )
}


-Remove count from dsl lastPass script

-Remove count from dsl lastPass script

-Correct regex for comment

        BEGIN{
            LINT=true;
        }

        NR==1{
            print "#!/usr/bin/env python\n\
# -*- coding: utf-8 -*- \n\
###########################################################\n\
#               WARNING: Generated code!                  #\n\
#              **************************                 #\n\
# Manual changes may get lost if file is generated again. #\n\
# Only code inside the [MANUAL] tags will be kept.        #\n\
###########################################################\n\
\n\
from flexbe_core import Behavior, Autonomy, OperatableStateMachine, ConcurrencyContainer, PriorityContainer, Logger\n\
from flexbe_states.decision_state import DecisionState\n\
# Additional imports can be added inside the following tags\n\
# [MANUAL_IMPORT]\n\
\n\
# [/MANUAL_IMPORT]\n\
\n\
\n\
'''\n\
@author: Raphaël Duchaîne\n\
'''\n\
class "$0"SM(Behavior):\n\
    '''\n\
    Behavior to test dsl parsing to flexbe\n\
    '''\n\
\n\
\n\
    def __init__(self):\n\
        super("$0"SM, self).__init__()\n\
        self.name = '"$0"'\n\
\n\
        # parameters of this behavior\n\
\n\
        # references to used behaviors\n\
\n\
        # Additional initialization code can be added inside the following tags\n\
        # [MANUAL_INIT]\n\
    \n\
        # [/MANUAL_INIT]\n\
\n\
        # Behavior comments:\n\
\n\
\n\
\n\
    def create(self):\n\
        # x:1200 y:570, x:12 y:570\n\
        _state_machine = OperatableStateMachine(outcomes=['done', 'failed'], input_keys=['input_value'])\n\
        _state_machine.userdata.input_value = ''";
            for(i=1; i<lineCount-2; i++){
                print "\n\
        # x:130 y:465, x:230 y:465\n\
        _sm_group_0"i" = OperatableStateMachine(outcomes=['done', 'failed'], input_keys=['input_value'])\n\
\n\
        with _sm_group_0"i":\n\
            # x:98 y:96\n\
            OperatableStateMachine.add('0"i"',\n\
                                    DecisionState(outcomes=['done','failed'], conditions=lambda x:'done'),\n\
                                    transitions={'done': 'done', 'failed': 'failed'},\n\
                                    autonomy={'done': Autonomy.Off, 'failed': Autonomy.Off},\n\
                                    remapping={'input_value': 'input_value'})";
            }
            print "\n\
        with _state_machine:";
        }

# /.* \? .* (: .*)?/
        NR>3 && !/^\W*#/{
            parent =$1
            good_child = $3
            bad_child = $5

            print "\n\
            # x:"(180+(NR*25))" y:"((NR-3)*60+34)%500"\n\
            OperatableStateMachine.add('"parent"',\n\
                                    _sm_group_0"NR-3",\n\
                                    transitions={'done': '"good_child"', 'failed': '"bad_child"'},\n\
                                    autonomy={'done': Autonomy.Inherit, 'failed': Autonomy.Inherit},\n\
                                    remapping={'input_value': 'input_value'})";
        }

        END{
            print "\n\
        return _state_machine\n\n";
        }

        BEGIN{
            LINT=true;
        }

        NR==1{
            count=1;
            print "#!/usr/bin/env python\n\
# -*- coding: utf-8 -*- \n\
###########################################################\n\
#               WARNING: Generated code!                  #\n\
#              **************************                 #\n\
# Manual changes may get lost if file is generated again. #\n\
# Only code inside the [MANUAL] tags will be kept.        #\n\
###########################################################\n\
\n\
from flexbe_core import Behavior, Autonomy, OperatableStateMachine, ConcurrencyContainer, PriorityContainer, Logger\n\
from flexbe_states.decision_state import DecisionState\n\
# Additional imports can be added inside the following tags\n\
# [MANUAL_IMPORT]\n\
\n\
# [/MANUAL_IMPORT]\n\
\n\
\n\
'''\n\
@author: Raphaël Duchaîne\n\
'''\n\
class "$0"SM(Behavior):\n\
    '''\n\
    Behavior to test dsl parsing to flexbe\n\
    '''\n\
\n\
\n\
    def __init__(self):\n\
        super("$0"SM, self).__init__()\n\
        self.name = '"$0"'\n\
\n\
        # parameters of this behavior\n\
\n\
        # references to used behaviors\n\
\n\
        # Additional initialization code can be added inside the following tags\n\
        # [MANUAL_INIT]\n\
    \n\
        # [/MANUAL_INIT]\n\
\n\
        # Behavior comments:\n\
\n\
\n\
\n\
    def create(self):\n\
        # x:1200 y:570, x:12 y:570\n\
        _state_machine = OperatableStateMachine(outcomes=['done', 'failed'], input_keys=['input_value'])\n\
        _state_machine.userdata.input_value = ''";
            for(i=1; i<lineCount-2; i++){
                print "\n\
        # x:130 y:465, x:230 y:465\n\
        _sm_group_0"i" = OperatableStateMachine(outcomes=['done', 'failed'], input_keys=['input_value'])\n\
\n\
        with _sm_group_0"i":\n\
            # x:98 y:96\n\
            OperatableStateMachine.add('0"i"',\n\
                                    DecisionState(outcomes=['done','failed'], conditions=lambda x:'done'),\n\
                                    transitions={'done': 'done', 'failed': 'failed'},\n\
                                    autonomy={'done': Autonomy.Off, 'failed': Autonomy.Off},\n\
                                    remapping={'input_value': 'input_value'})";
            }
            print "\n\
        with _state_machine:";
        }

# /.* \? .* (: .*)?/
        NR>3 && $0!~/^\s*#/{
            parent =$1
            good_child = $3
            bad_child = $5

            if($5~/^\s*$/){
                bad_child=$3;
            }

            print "\n\
            # x:"(180+(count*25))" y:"(count*60+34)%1000"\n\
            OperatableStateMachine.add('"parent"',\n\
                                    _sm_group_0"count",\n\
                                    transitions={'done': '"good_child"', 'failed': '"bad_child"'},\n\
                                    autonomy={'done': Autonomy.Inherit, 'failed': Autonomy.Inherit},\n\
                                    remapping={'input_value': 'input_value'})";
            count++;
        }

        END{
            print "\n\
        return _state_machine\n\n";
        }


translate.awk: include "include/GenTK"

translate.awk: include "include/GenTK"

#!/usr/bin/gawk -f

@include "metainfo"

@include "include/Commons"
@include "include/Utils"

@include "include/GenTK"

@include "include/Languages"
@include "include/Help"
@include "include/Parser"
@include "include/Theme"
@include "include/Translate"
@include "include/Script"
@include "include/REPL"

@include "include/Main"

#!/usr/bin/gawk -f

@include "metainfo"

@include "include/Commons"
@include "include/Utils"

@include "include/Languages"
@include "include/Help"
@include "include/Parser"
@include "include/Theme"
@include "include/Translate"
@include "include/Script"
@include "include/REPL"

@include "include/Main"


Parser: add parseJson()

Parser: add parseJson()

####################################################################
# Parser.awk                                                       #
####################################################################

# Tokenize a string and return a token list.
function tokenize(returnTokens, string,
                  delimiters,
                  newlines,
                  quotes,
                  escapeChars,
                  leftBlockComments,
                  rightBlockComments,
                  lineComments,
                  reservedOperators,
                  reservedPatterns,
                  ####
                  blockCommenting,
                  c,
                  currentToken,
                  escaping,
                  i,
                  lineCommenting,
                  p,
                  quoting,
                  r,
                  s,
                  tempGroup,
                  tempPattern,
                  tempString) {
    # Default parameters
    if (!delimiters[0]) {
        delimiters[0] = " "  # whitespace
        delimiters[1] = "\t" # horizontal tab
        delimiters[2] = "\v" # vertical tab
    }
    if (!newlines[0]) {
        newlines[0] = "\n" # line feed
        newlines[1] = "\r" # carriage return
    }
    if (!quotes[0]) {
        quotes[0] = "\"" # double quote
    }
    if (!escapeChars[0]) {
        escapeChars[0] = "\\" # backslash
    }
    if (!leftBlockComments[0]) {
        leftBlockComments[0] = "#|" # Lisp-style extended comment (open)
        leftBlockComments[1] = "/*" # C-style comment (open)
        leftBlockComments[2] = "(*" # ML-style comment (open)
    }
    if (!rightBlockComments[0]) {
        rightBlockComments[0] = "|#" # Lisp-style extended comment (close)
        rightBlockComments[1] = "*/" # C-style comment (close)
        rightBlockComments[2] = "*)" # ML-style comment (close)
    }
    if (!lineComments[0]) {
        lineComments[0] = ";"  # Lisp-style line comment
        lineComments[1] = "//" # C++-style line comment
        lineComments[2] = "#"  # hash comment
    }
    if (!reservedOperators[0]) {
        reservedOperators[0] = "(" #  left parenthesis
        reservedOperators[1] = ")" # right parenthesis
        reservedOperators[2] = "[" #  left bracket
        reservedOperators[3] = "]" # right bracket
        reservedOperators[4] = "{" #  left brace
        reservedOperators[5] = "}" # right brace
        reservedOperators[6] = "," # comma
    }
    if (!reservedPatterns[0]) {
        reservedPatterns[0] = "[+-]?((0|[1-9][0-9]*)|[.][0-9]*|(0|[1-9][0-9]*)[.][0-9]*)([Ee][+-]?[0-9]+)?" # numeric literal (scientific notation possible)
        reservedPatterns[1] = "[+-]?0[0-7]+([.][0-7]*)?" # numeric literal (octal)
        reservedPatterns[2] = "[+-]?0[Xx][0-9A-Fa-f]+([.][0-9A-Fa-f]*)?" # numeric literal (hexadecimal)
    }

    split(string, s, "")
    currentToken = ""
    quoting = escaping = blockCommenting = lineCommenting = 0
    p = 0
    i = 1
    while (i <= length(s)) {
        c = s[i]
        r = substr(string, i)

        if (blockCommenting) {
            if (tempString = startsWithAny(r, rightBlockComments))
                blockCommenting = 0 # block comment ends

            i++

        } else if (lineCommenting) {
            if (belongsTo(c, newlines))
                lineCommenting = 0 # line comment ends

            i++

        } else if (quoting) {
            currentToken = currentToken c

            if (escaping) {
                escaping = 0 # escape ends

            } else {
                if (belongsTo(c, quotes)) {
                    # Finish the current token
                    if (currentToken) {
                        returnTokens[p++] = currentToken
                        currentToken = ""
                    }

                    quoting = 0 # quotation ends

                } else if (belongsTo(c, escapeChars)) {
                    escaping = 1 # escape begins

                } else {
                    # Continue
                }
            }

            i++

        } else {
            if (belongsTo(c, delimiters) || belongsTo(c, newlines)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                    currentToken = ""
                }

                i++

            } else if (belongsTo(c, quotes)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                }

                currentToken = c

                quoting = 1 # quotation begins

                i++

            } else if (tempString = startsWithAny(r, leftBlockComments)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                    currentToken = ""
                }

                blockCommenting = 1 # block comment begins

                i += length(tempString)

            } else if (tempString = startsWithAny(r, lineComments)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                    currentToken = ""
                }

                lineCommenting = 1 # line comment begins

                i += length(tempString)

            } else if (tempString = startsWithAny(r, reservedOperators)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                    currentToken = ""
                }

                # Reserve token
                returnTokens[p++] = tempString

                i += length(tempString)

            } else if (tempPattern = matchesAny(r, reservedPatterns)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                    currentToken = ""
                }

                # Reserve token
                match(r, "^" tempPattern, tempGroup)
                returnTokens[p++] = tempGroup[0]

                i += length(tempGroup[0])

            } else {
                # Continue with the current token
                currentToken = currentToken c

                i++
            }
        }
    }

    # Finish the last token
    if (currentToken)
        returnTokens[p++] = currentToken

}

# Parse a token list of JSON array and return an AST.
function parseJsonArray(returnAST, tokens,
                        leftBrackets,
                        rightBrackets,
                        separators,
                        ####
                        i, j, key, p, stack, token) {
    # Default parameters
    if (!leftBrackets[0]) {
        leftBrackets[0] = "(" # left parenthesis
        leftBrackets[1] = "[" # left bracket
        leftBrackets[2] = "{" # left brace
    }
    if (!rightBrackets[0]) {
        rightBrackets[0] = ")" # right parenthesis
        rightBrackets[1] = "]" # right bracket
        rightBrackets[2] = "}" # right brace
    }
    if (!separators[0]) {
        separators[0] = "," # comma
    }

    stack[p = 0] = 0
    for (i = 0; i < length(tokens); i++) {
        token = tokens[i]

        if (belongsTo(token, leftBrackets))
            stack[++p] = 0
        else if (belongsTo(token, rightBrackets))
            --p
        else if (belongsTo(token, separators))
            stack[p]++
        else {
            key = stack[0]
            for (j = 1; j <= p; j++)
                key = key SUBSEP stack[j]
            returnAST[key] = token
        }
    }
}

# JSON parser.
function parseJson(returnAST, tokens,
                   arrayStartTokens, arrayEndTokens,
                   objectStartTokens, objectEndTokens,
                   commas, colons,
                   ####
                   flag, i, j, key, name, p, stack, token) {
    # Default parameters
    if (!arrayStartTokens[0])  arrayStartTokens[0]  = "["
    if (!arrayEndTokens[0])    arrayEndTokens[0]    = "]"
    if (!objectStartTokens[0]) objectStartTokens[0] = "{"
    if (!objectEndTokens[0])   objectEndTokens[0]   = "}"
    if (!commas[0])            commas[0]            = ","
    if (!colons[0])            colons[0]            = ":"

    stack[p = 0] = 0
    flag = 0 # ready to read key
    for (i = 0; i < length(tokens); i++) {
        token = tokens[i]

        if (belongsTo(token, arrayStartTokens))
            stack[++p] = 0
        else if (belongsTo(token, objectStartTokens))
            stack[++p] = NULLSTR
        else if (belongsTo(token, objectEndTokens) ||
                 belongsTo(token, arrayEndTokens))
            --p
        else if (belongsTo(token, commas)) {
            if (isnum(stack[p])) # array
                stack[p]++ # increase index
        } else if (belongsTo(token, colons)) {
            flag = 1 # ready to read value
        } else if (isnum(stack[p]) || flag) {
            # Read a value
            key = stack[0]
            for (j = 1; j <= p; j++)
                key = key SUBSEP stack[j]
            returnAST[key] = token
            flag = 0 # ready to read key
        } else {
            # Read a key
            stack[p] = unparameterize(token)
        }
    }
}

# S-expr parser.
function parseList(returnAST, tokens,
                   leftBrackets,
                   rightBrackets,
                   separators,
                   ####
                   i, j, key, p, stack, token) {
    # Default parameters
    if (!leftBrackets[0]) {
        leftBrackets[0] = "(" # left parenthesis
        leftBrackets[1] = "[" # left bracket
        leftBrackets[2] = "{" # left brace
    }
    if (!rightBrackets[0]) {
        rightBrackets[0] = ")" # right parenthesis
        rightBrackets[1] = "]" # right bracket
        rightBrackets[2] = "}" # right brace
    }
    if (!separators[0]) {
        separators[0] = "," # comma
    }

    stack[p = 0] = 0
    for (i = 0; i < length(tokens); i++) {
        token = tokens[i]

        if (belongsTo(token, leftBrackets)) {
            stack[++p] = 0
        } else if (belongsTo(token, rightBrackets)) {
            stack[--p]++
        } else if (belongsTo(token, separators)) {
            # skip
        } else {
            key = NULLSTR
            if (p > 0) {
                for (j = 0; j < p - 1; j++)
                    key = key SUBSEP stack[j]
                returnAST[key][stack[p - 1]] = NULLSTR
                key = key SUBSEP stack[p - 1]
            }
            returnAST[key][stack[p]] = token
            stack[p]++
        }
    }
}

####################################################################
# Parser.awk                                                       #
####################################################################

# Tokenize a string and return a token list.
function tokenize(returnTokens, string,
                  delimiters,
                  newlines,
                  quotes,
                  escapeChars,
                  leftBlockComments,
                  rightBlockComments,
                  lineComments,
                  reservedOperators,
                  reservedPatterns,
                  ####
                  blockCommenting,
                  c,
                  currentToken,
                  escaping,
                  i,
                  lineCommenting,
                  p,
                  quoting,
                  r,
                  s,
                  tempGroup,
                  tempPattern,
                  tempString) {
    # Default parameters
    if (!delimiters[0]) {
        delimiters[0] = " "  # whitespace
        delimiters[1] = "\t" # horizontal tab
        delimiters[2] = "\v" # vertical tab
    }
    if (!newlines[0]) {
        newlines[0] = "\n" # line feed
        newlines[1] = "\r" # carriage return
    }
    if (!quotes[0]) {
        quotes[0] = "\"" # double quote
    }
    if (!escapeChars[0]) {
        escapeChars[0] = "\\" # backslash
    }
    if (!leftBlockComments[0]) {
        leftBlockComments[0] = "#|" # Lisp-style extended comment (open)
        leftBlockComments[1] = "/*" # C-style comment (open)
        leftBlockComments[2] = "(*" # ML-style comment (open)
    }
    if (!rightBlockComments[0]) {
        rightBlockComments[0] = "|#" # Lisp-style extended comment (close)
        rightBlockComments[1] = "*/" # C-style comment (close)
        rightBlockComments[2] = "*)" # ML-style comment (close)
    }
    if (!lineComments[0]) {
        lineComments[0] = ";"  # Lisp-style line comment
        lineComments[1] = "//" # C++-style line comment
        lineComments[2] = "#"  # hash comment
    }
    if (!reservedOperators[0]) {
        reservedOperators[0] = "(" #  left parenthesis
        reservedOperators[1] = ")" # right parenthesis
        reservedOperators[2] = "[" #  left bracket
        reservedOperators[3] = "]" # right bracket
        reservedOperators[4] = "{" #  left brace
        reservedOperators[5] = "}" # right brace
        reservedOperators[6] = "," # comma
    }
    if (!reservedPatterns[0]) {
        reservedPatterns[0] = "[+-]?((0|[1-9][0-9]*)|[.][0-9]*|(0|[1-9][0-9]*)[.][0-9]*)([Ee][+-]?[0-9]+)?" # numeric literal (scientific notation possible)
        reservedPatterns[1] = "[+-]?0[0-7]+([.][0-7]*)?" # numeric literal (octal)
        reservedPatterns[2] = "[+-]?0[Xx][0-9A-Fa-f]+([.][0-9A-Fa-f]*)?" # numeric literal (hexadecimal)
    }

    split(string, s, "")
    currentToken = ""
    quoting = escaping = blockCommenting = lineCommenting = 0
    p = 0
    i = 1
    while (i <= length(s)) {
        c = s[i]
        r = substr(string, i)

        if (blockCommenting) {
            if (tempString = startsWithAny(r, rightBlockComments))
                blockCommenting = 0 # block comment ends

            i++

        } else if (lineCommenting) {
            if (belongsTo(c, newlines))
                lineCommenting = 0 # line comment ends

            i++

        } else if (quoting) {
            currentToken = currentToken c

            if (escaping) {
                escaping = 0 # escape ends

            } else {
                if (belongsTo(c, quotes)) {
                    # Finish the current token
                    if (currentToken) {
                        returnTokens[p++] = currentToken
                        currentToken = ""
                    }

                    quoting = 0 # quotation ends

                } else if (belongsTo(c, escapeChars)) {
                    escaping = 1 # escape begins

                } else {
                    # Continue
                }
            }

            i++

        } else {
            if (belongsTo(c, delimiters) || belongsTo(c, newlines)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                    currentToken = ""
                }

                i++

            } else if (belongsTo(c, quotes)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                }

                currentToken = c

                quoting = 1 # quotation begins

                i++

            } else if (tempString = startsWithAny(r, leftBlockComments)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                    currentToken = ""
                }

                blockCommenting = 1 # block comment begins

                i += length(tempString)

            } else if (tempString = startsWithAny(r, lineComments)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                    currentToken = ""
                }

                lineCommenting = 1 # line comment begins

                i += length(tempString)

            } else if (tempString = startsWithAny(r, reservedOperators)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                    currentToken = ""
                }

                # Reserve token
                returnTokens[p++] = tempString

                i += length(tempString)

            } else if (tempPattern = matchesAny(r, reservedPatterns)) {
                # Finish the current token
                if (currentToken) {
                    returnTokens[p++] = currentToken
                    currentToken = ""
                }

                # Reserve token
                match(r, "^" tempPattern, tempGroup)
                returnTokens[p++] = tempGroup[0]

                i += length(tempGroup[0])

            } else {
                # Continue with the current token
                currentToken = currentToken c

                i++
            }
        }
    }

    # Finish the last token
    if (currentToken)
        returnTokens[p++] = currentToken

}

# Parse a token list of JSON array and return an AST.
function parseJsonArray(returnAST, tokens,
                        leftBrackets,
                        rightBrackets,
                        separators,
                        ####
                        i, j, key, p, stack, token) {
    # Default parameters
    if (!leftBrackets[0]) {
        leftBrackets[0] = "(" # left parenthesis
        leftBrackets[1] = "[" # left bracket
        leftBrackets[2] = "{" # left brace
    }
    if (!rightBrackets[0]) {
        rightBrackets[0] = ")" # right parenthesis
        rightBrackets[1] = "]" # right bracket
        rightBrackets[2] = "}" # right brace
    }
    if (!separators[0]) {
        separators[0] = "," # comma
    }

    stack[p = 0] = 0
    for (i = 0; i < length(tokens); i++) {
        token = tokens[i]

        if (belongsTo(token, leftBrackets))
            stack[++p] = 0
        else if (belongsTo(token, rightBrackets))
            --p
        else if (belongsTo(token, separators))
            stack[p]++
        else {
            key = stack[0]
            for (j = 1; j <= p; j++)
                key = key SUBSEP stack[j]
            returnAST[key] = token
        }
    }
}

#
function parseList(returnAST, tokens,
                   leftBrackets,
                   rightBrackets,
                   separators,
                   ####
                   i, j, key, p, stack, token) {
    # Default parameters
    if (!leftBrackets[0]) {
        leftBrackets[0] = "(" # left parenthesis
        leftBrackets[1] = "[" # left bracket
        leftBrackets[2] = "{" # left brace
    }
    if (!rightBrackets[0]) {
        rightBrackets[0] = ")" # right parenthesis
        rightBrackets[1] = "]" # right bracket
        rightBrackets[2] = "}" # right brace
    }
    if (!separators[0]) {
        separators[0] = "," # comma
    }

    stack[p = 0] = 0
    for (i = 0; i < length(tokens); i++) {
        token = tokens[i]

        if (belongsTo(token, leftBrackets)) {
            stack[++p] = 0
        } else if (belongsTo(token, rightBrackets)) {
            stack[--p]++
        } else if (belongsTo(token, separators)) {
            # skip
        } else {
            key = NULLSTR
            if (p > 0) {
                for (j = 0; j < p - 1; j++)
                    key = key SUBSEP stack[j]
                returnAST[key][stack[p - 1]] = NULLSTR
                key = key SUBSEP stack[p - 1]
            }
            returnAST[key][stack[p]] = token
            stack[p]++
        }
    }
}


Commons: add initUrlEncoding() and quote()

#!/usr/bin/gawk -f

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    temp = ""
    j = 0
    saveSortedIn = PROCINFO["sorted_in"]
    PROCINFO["sorted_in"] = sortedIn
    for (i in array)
        if (preserveNull || array[i] != "")
            temp = j++ ? temp separator array[i] : array[i]
    PROCINFO["sorted_in"] = saveSortedIn

    return temp
}

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

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

#!/usr/bin/gawk -f

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

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

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

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

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

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

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

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

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

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

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

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

    temp = ""
    j = 0
    saveSortedIn = PROCINFO["sorted_in"]
    PROCINFO["sorted_in"] = sortedIn
    for (i in array)
        if (preserveNull || array[i] != "")
            temp = j++ ? temp separator array[i] : array[i]
    PROCINFO["sorted_in"] = saveSortedIn

    return temp
}

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

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


In Competition

In Competition

#!/usr/bin/awk -f
# LoginDef

BEGIN {
	gsub(/PASS_MIN_DAYS\t[0-9]+/, "PASS_MIN_DAYS	10")
	print str
}

END {

}


INTEGRATION: CWS locales23 (1.4.10); FILE MERGED 2007/05/09 11:05:36 er 1.4.10.2: getAllFormats1 is optional 2007/04/27 17:11:15 er 1.4.10.1: #i74008# add optional second LC_FORMAT section (LC_FORMAT_1 element) to locale data to be able to distinguish inheritance

#!/usr/bin/gawk -f
# Usage: gawk -f linkermapfile-check.awk *.map *.xml
# Order of *.map *.xml is important, otherwise all symbols are reported to be
# missing.
# Checks if all symbols of all locale data are present in the symbol scoping
# linker mapfiles.  Any output indicates a missing symbol, ../localedata.cxx is
# grep'ed to indicate the library to which mapfile the symbol should be added.
# Author: Eike Rathke <er@openoffice.org>

BEGIN {
    bAnyMissing = 0
    file = ""
    nMap = 0
    nMaps = 0
    nPublics = 0
    sPublic[nPublics++] = "getAllCalendars_"
    sPublic[nPublics++] = "getAllCurrencies_"
    sPublic[nPublics++] = "getAllFormats0_"
    bOptional[nPublics] = 1     # getAllFormats1 most times not present
    sPublic[nPublics++] = "getAllFormats1_"
    sPublic[nPublics++] = "getBreakIteratorRules_"
    sPublic[nPublics++] = "getCollationOptions_"
    sPublic[nPublics++] = "getCollatorImplementation_"
    sPublic[nPublics++] = "getContinuousNumberingLevels_"
    sPublic[nPublics++] = "getForbiddenCharacters_"
    sPublic[nPublics++] = "getLCInfo_"
    sPublic[nPublics++] = "getLocaleItem_"
    sPublic[nPublics++] = "getOutlineNumberingLevels_"
    sPublic[nPublics++] = "getReservedWords_"
    sPublic[nPublics++] = "getSearchOptions_"
    sPublic[nPublics++] = "getTransliterations_"
    sPublic[nPublics++] = "getIndexAlgorithm_"
    sPublic[nPublics++] = "getUnicodeScripts_"
    sPublic[nPublics++] = "getFollowPageWords_"
}

file != FILENAME {
    file = FILENAME
    if ( file ~ /\.map$/ )
    {
        sMapFile[nMaps] = file
        nMap = nMaps
        ++nMaps
    }
    else if ( file ~ /\.xml$/ )
    {
        bOut = 0
        n = split( file, arr, /[:\\\/.]/ )
        locale = arr[n-1]
        for ( i=0; i<nPublics; ++i )
        {
            symbol = sPublic[i] locale ";"
            bFound = 0
            for ( j=0; j<nMaps && !bFound; ++j )
            {
                if ( sSymbol[j,symbol] )
                    bFound = 1
            }
            if ( !bFound && bOptional[i] )
            {
                print symbol " not present but optional"
                bFound = 1
            }
            if ( !bFound )
            {
                if ( !bOut )
                {
                    search = "\"" locale "\""
                    while ( !bOut && (getline <"../localedata.cxx") > 0 )
                    {
                        if ( $0 ~ search )
                        {
                            bOut = 1
                            print "../localedata.cxx says this should go into: " $0
                        }
                    }
                    close( "../localedata.cxx" )
                    if ( !bOut )
                        print "../localedata.cxx doesn't indicate to which lib this belongs to:"
                    bOut = 1
                }
                print symbol
            }
        }
        if ( bOut)
        {
            printf("\n")
            bAnyMissing = 1
        }
        nextfile
    }
    else
        nextfile
}

# only reached if .map file encountered, read in symbols
{
    if ( $1 ~ /;$/ )
        sSymbol[nMap,$1] = 1
}

END {
    if ( !bAnyMissing )
        print "All good." >>"/dev/stderr"
}

#!/usr/bin/gawk -f
# Usage: gawk -f linkermapfile-check.awk *.map *.xml
# Order of *.map *.xml is important, otherwise all symbols are reported to be
# missing.
# Checks if all symbols of all locale data are present in the symbol scoping
# linker mapfiles.  Any output indicates a missing symbol, ../localedata.cxx is
# grep'ed to indicate the library to which mapfile the symbol should be added.
# Author: Eike Rathke <er@openoffice.org>

BEGIN {
    bAnyMissing = 0
    file = ""
    nMap = 0
    nMaps = 0
    nPublics = 0
    sPublic[nPublics++] = "getAllCalendars_"
    sPublic[nPublics++] = "getAllCurrencies_"
    sPublic[nPublics++] = "getAllFormats_"
    sPublic[nPublics++] = "getBreakIteratorRules_"
    sPublic[nPublics++] = "getCollationOptions_"
    sPublic[nPublics++] = "getCollatorImplementation_"
    sPublic[nPublics++] = "getContinuousNumberingLevels_"
    sPublic[nPublics++] = "getForbiddenCharacters_"
    sPublic[nPublics++] = "getLCInfo_"
    sPublic[nPublics++] = "getLocaleItem_"
    sPublic[nPublics++] = "getOutlineNumberingLevels_"
    sPublic[nPublics++] = "getReservedWords_"
    sPublic[nPublics++] = "getSearchOptions_"
    sPublic[nPublics++] = "getTransliterations_"
    sPublic[nPublics++] = "getIndexAlgorithm_"
    sPublic[nPublics++] = "getUnicodeScripts_"
    sPublic[nPublics++] = "getFollowPageWords_"
}

file != FILENAME {
    file = FILENAME
    if ( file ~ /\.map$/ )
    {
        sMapFile[nMaps] = file
        nMap = nMaps
        ++nMaps
    }
    else if ( file ~ /\.xml$/ )
    {
        bOut = 0
        n = split( file, arr, /[:\\\/.]/ )
        locale = arr[n-1]
        for ( i=0; i<nPublics; ++i )
        {
            symbol = sPublic[i] locale ";"
            bFound = 0
            for ( j=0; j<nMaps && !bFound; ++j )
            {
                if ( sSymbol[j,symbol] )
                    bFound = 1
            }
            if ( !bFound )
            {
                if ( !bOut )
                {
                    search = "\"" locale "\""
                    while ( !bOut && (getline <"../localedata.cxx") > 0 )
                    {
                        if ( $0 ~ search )
                        {
                            bOut = 1
                            print "../localedata.cxx says this should go into: " $0
                        }
                    }
                    close( "../localedata.cxx" )
                    if ( !bOut )
                        print "../localedata.cxx doesn't indicate to which lib this belongs to:"
                    bOut = 1
                }
                print symbol
            }
        }
        if ( bOut)
        {
            printf("\n")
            bAnyMissing = 1
        }
        nextfile
    }
    else
        nextfile
}

# only reached if .map file encountered, read in symbols
{
    if ( $1 ~ /;$/ )
        sSymbol[nMap,$1] = 1
}

END {
    if ( !bAnyMissing )
        print "All good." >>"/dev/stderr"
}


account for abstract vertices

account for abstract vertices

# sequence numbering starts at 0
BEGIN{
	seqid=-1;
}
# new graph collection -> new sequence
# vertex and nucleotide numbering starts at 0
/^t/{
	seqid++;
	vertex_id=0;
}
# new entry on viewpoint vertice (omitting relational vertices)
/^v/ && !/\^/ && !/#/ {
	print seqid, vertex_id++, $3, $4-1;
}
# relational and abstract vertices increment vertex id and have no position
/^v/ && (/\^/ || /#/) {
	#print seqid, vertex_id++, $3, -1
	vertex_id++
}
# non-viewpoint vertices are silent
/^V/ && !/\^/ && !/#/ {
}

# sequence numbering starts at 0
BEGIN{
	seqid=-1;
}
# new graph collection -> new sequence
# vertex and nucleotide numbering starts at 0
/^t/{
	seqid++;
	vertex_id=0;
}
# new entry on viewpoint vertice (omitting relational vertices)
/^v/ && !/\^/ && !/#/ {
	print seqid, vertex_id++, $3, $4-1;
}
# non-viewpoint  vertices only increment nucleotide position
/^V/ && !/\^/ && !/#/ {
}