Translators/GoogleTranslate: replace preprocess with preprocessByDump which proactively encodes non-ASCII chars in UTF-8 (fix #310)

####################################################################
# GoogleTranslate.awk                                              #
####################################################################
#
# Last Updated: 25 Jul 2019
BEGIN { provides("google") }

# FIXME!
# See: <https://translate.google.com/translate/releases/twsfe_w_20151214_RC03/r/js/desktop_module_main.js>
function genRL(a, x,
               ####
               b, c, d, i, y) {
    tokenize(y, x)
    parseList(b, y)
    i = SUBSEP 0
    for (c = 0; c < length(b[i]) - 2; c += 3) {
        d = b[i][c + 2]
        d = d >= 97 ? d - 87 :
            d - 48 # convert to number
        d = b[i][c + 1] == 43 ? rshift(a, d) : lshift(a, d)
        a = b[i][c] == 43 ? and(a + d, 4294967295) : xor(a, d)
    }
    return a
}
function genTK(text,
               ####
               a, d, dLen, e, tkk, ub, vb) {
    if (TK[text]) return TK[text]

    tkk = systime() / 3600
    ub = "[43,45,51,94,43,98,43,45,102]"
    vb = "[43,45,97,94,43,54]"

    # FIXME: build a dump cache!
    dLen = dump(text, d) # convert to byte array
    a = tkk
    for (e = 1; e <= dLen; e++)
        a = genRL(a + d[e], vb)
    a = genRL(a, ub)
    0 > a && (a = and(a, 2147483647) + 2147483648)
    a %= 1e6
    TK[text] = a "." xor(a, tkk)

    l(text, "text")
    l(tkk, "tkk")
    l(TK[text], "tk")
    return TK[text]
}

function googleInit() {
    HttpProtocol = "http://"
    HttpHost = "translate.googleapis.com"
    HttpPort = 80
}

function googleRequestUrl(text, sl, tl, hl,    qc) {
    qc = Option["no-autocorrect"] ? "qc" : "qca";
    return HttpPathPrefix "/translate_a/single?client=gtx"              \
        "&ie=UTF-8&oe=UTF-8"                                            \
        "&dt=bd&dt=ex&dt=ld&dt=md&dt=rw&dt=rm&dt=ss&dt=t&dt=at&dt=gt"   \
        "&dt=" qc "&sl=" sl "&tl=" tl "&hl=" hl                         \
        "&q=" preprocessByDump(text)
}

function googleTTSUrl(text, tl) {
    return HttpProtocol HttpHost "/translate_tts?ie=UTF-8&client=gtx"	\
        "&tl=" tl "&q=" preprocessByDump(text)
}

function googleWebTranslateUrl(uri, sl, tl, hl) {
    return "https://translate.google.com/translate?"    \
        "hl=" hl "&sl=" sl "&tl=" tl "&u=" uri
}

# Get the translation of a string.
function googleTranslate(text, sl, tl, hl,
                         isVerbose, toSpeech, returnPlaylist, returnIl,
                         ####
                         r,
                         content, tokens, ast,
                         _sl, _tl, _hl, il, ils, isPhonetic,
                         article, example, explanation, ref, word,
                         translation, translations, phonetics,
                         wordClasses, words, segments, altTranslations,
                         original, oPhonetics, oWordClasses, oWords,
                         oRefs, oSynonymClasses, oSynonyms,
                         oExamples, oSeeAlso,
                         wShowOriginal, wShowOriginalPhonetics,
                         wShowTranslation, wShowTranslationPhonetics,
                         wShowPromptMessage, wShowLanguages,
                         wShowOriginalDictionary, wShowDictionary,
                         wShowAlternatives,
                         genderedTrans, hasWordClasses, hasAltTranslations,
                         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.")
    }

    # Convert codes or aliases to standard codes used by Google Translate
    # If the code or alias cannot be found, use as it is
    _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)
    if (Option["dump"])
        return content
    tokenize(tokens, content)
    parseJsonArray(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
    }

    saveSortedIn = PROCINFO["sorted_in"]
    PROCINFO["sorted_in"] = "compareByIndexFields"
    for (i in ast) {
        if (ast[i] == "null") continue

        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "0$")
            append(translations, literal(ast[i]))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "1$")
            append(original, literal(ast[i]))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "2$")
            append(phonetics, literal(ast[i]))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "3$")
            append(oPhonetics, literal(ast[i]))

        # 1 - word classes and explanations
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            wordClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "([[:digit:]]+)$", group))
            words[group[1]][group[2]][group[3]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)$", group))
            words[group[1]][group[2]]["1"][group[3]] = literal(ast[i])

        # 5 - alternative translations
        if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) {
            segments[group[1]] = literal(ast[i])
            altTranslations[group[1]][0] = ""
        }
        if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            altTranslations[group[1]][group[2]] = literal(ast[i])

        # 7 - autocorrection
        if (i ~ "^0" SUBSEP "7" SUBSEP "5$") {
            if (ast[i] == "true")
                w("Showing translation for:  (use -no-auto to disable autocorrect)")
            else
                w("Did you mean: "                                      \
                  ansi("bold", unparameterize(ast["0" SUBSEP "7" SUBSEP "1"])))
        }

        # 8 - identified source languages
        if (i ~ "^0" SUBSEP "8" SUBSEP "0" SUBSEP "[[:digit:]]+$" ||
            i ~ "^0" SUBSEP "2$")
            append(ils, literal(ast[i]))

        # 11 - (original) word classes and synonyms
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oSynonymClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group))
            if (ast[i]) {
                oRefs[literal(ast[i])][1] = group[1]
                oRefs[literal(ast[i])][2] = group[2]
            }
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0" SUBSEP "([[:digit:]]+)$", group))
            oSynonyms[group[1]][group[2]][group[3]] = literal(ast[i])

        # 12 - (original) word classes and explanations
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oWordClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oWords[group[1]][group[2]][0] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group))
            oWords[group[1]][group[2]][1] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2$", group))
            oWords[group[1]][group[2]][2] = literal(ast[i])

        # 13 - (original) examples
        if (match(i, "^0" SUBSEP "13" SUBSEP "0" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oExamples[group[1]] = literal(ast[i])

        # 14 - (original) see also
        if (match(i, "^0" SUBSEP "14" SUBSEP "0" SUBSEP "([[:digit:]]+)$", group))
            oSeeAlso[group[1]] = literal(ast[i])

        # 18 - gender-specific translations
        if (match(i, "^0" SUBSEP "18" SUBSEP "0" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group))
            genderedTrans[group[1]] = literal(ast[i])
    }
    PROCINFO["sorted_in"] = saveSortedIn

    translation = join(translations)

    returnIl[0] = il = !anything(ils) || belongsTo(sl, ils) ? sl : ils[0]
    if (Option["verbose"] < -1)
        return il
    else if (Option["verbose"] < 0)
        return getList(il)

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

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

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

    } else {
        # Verbose mode

        wShowOriginal = Option["show-original"]
        wShowOriginalPhonetics = Option["show-original-phonetics"]
        wShowTranslation = Option["show-translation"]
        wShowTranslationPhonetics = Option["show-translation-phonetics"]
        wShowPromptMessage = Option["show-prompt-message"]
        wShowLanguages = Option["show-languages"]
        wShowOriginalDictionary = Option["show-original-dictionary"]
        wShowDictionary = Option["show-dictionary"]
        wShowAlternatives = Option["show-alternatives"]

        if (!anything(oPhonetics)) wShowOriginalPhonetics = 0
        if (!anything(phonetics)) wShowTranslationPhonetics = 0
        if (getCode(il) == getCode(tl) &&                               \
            (isarray(oWordClasses) || isarray(oSynonymClasses) ||       \
             isarray(oExamples) || isarray(oSeeAlso))) {
            wShowOriginalDictionary = 1
            wShowTranslation = 0
        }
        hasWordClasses = exists(wordClasses)
        hasAltTranslations = exists(altTranslations[0])
        if (!hasWordClasses && !hasAltTranslations)
            wShowPromptMessage = wShowLanguages = 0
        if (!hasWordClasses) wShowDictionary = 0
        if (!hasAltTranslations) wShowAlternatives = 0

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

        if (wShowTranslation) {
            # Display: major translation & phonetics
            if (r) r = r RS RS
            r = r m("-- display major translation & phonetics")
            if (!exists(genderedTrans))
                r = r prettify("translation", s(translation, tl))
            else {
                r = r prettify("prompt-message", s("(♂) ", hl))
                r = r prettify("translation", s(genderedTrans[0], tl)) RS
                r = r prettify("prompt-message", s("(♀) ", hl))
                r = r prettify("translation", s(genderedTrans[1], tl))
            }
            if (wShowTranslationPhonetics)
                r = r RS prettify("translation-phonetics", showPhonetics(join(phonetics, " "), tl))
        }

        if (wShowPromptMessage || wShowLanguages)
            if (r) r = r RS
        if (wShowPromptMessage) {
            if (hasWordClasses) {
                # Display: prompt message (Definitions of ...)
                if (r) r = r RS
                r = r m("-- display prompt message (Definitions of ...)")
                if (isRTL(hl)) # home language is R-to-L
                    r = r prettify("prompt-message", s(showDefinitionsOf(hl, join(original, " "))))
                else { # home language is L-to-R
                    split(showDefinitionsOf(hl, "\0%s\0"), group, "\0")
                    for (i = 1; i <= length(group); i++) {
                        if (group[i] == "%s")
                            r = r prettify("prompt-message-original", show(join(original, " "), il))
                        else
                            r = r prettify("prompt-message", group[i])
                    }
                }
            } else if (hasAltTranslations) {
                # Display: prompt message (Translations of ...)
                if (r) r = r RS
                r = r m("-- display prompt message (Translations of ...)")
                if (isRTL(hl)) # home language is R-to-L
                    r = r prettify("prompt-message", s(showTranslationsOf(hl, join(original, " "))))
                else { # home language is L-to-R
                    split(showTranslationsOf(hl, "\0%s\0"), group, "\0")
                    for (i = 1; i <= length(group); i++) {
                        if (group[i] == "%s")
                            r = r prettify("prompt-message-original", show(join(original, " "), il))
                        else
                            r = r prettify("prompt-message", group[i])
                    }
                }
            }
        }
        if (wShowLanguages) {
            # Display: source language -> target language
            if (r) r = r 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 (wShowOriginalDictionary) {
            # Display: original dictionary
            if (exists(oWordClasses)) {
                # Detailed explanations
                if (r) r = r RS
                r = r m("-- display original dictionary (detailed explanations)")
                for (i = 0; i < length(oWordClasses); i++) {
                    r = (i > 0 ? r RS : r) RS prettify("original-dictionary-detailed-word-class", s(oWordClasses[i], hl))
                    for (j = 0; j < length(oWords[i]); j++) {
                        explanation = oWords[i][j][0]
                        ref = oWords[i][j][1]
                        example = oWords[i][j][2]

                        r = (j > 0 ? r RS : r) RS prettify("original-dictionary-detailed-explanation", ins(1, explanation, il))
                        if (example)
                            r = r RS prettify("original-dictionary-detailed-example", ins(2, "- \"" example "\"", il))
                        if (ref && isarray(oRefs[ref])) {
                            temp = prettify("original-dictionary-detailed-synonyms", ins(1, show(showSynonyms(hl), hl) ": "))
                            temp = temp prettify("original-dictionary-detailed-synonyms-item", show(oSynonyms[oRefs[ref][1]][oRefs[ref][2]][0], il))
                            for (k = 1; k < length(oSynonyms[oRefs[ref][1]][oRefs[ref][2]]); k++)
                                temp = temp prettify("original-dictionary-detailed-synonyms", ", ") \
                                    prettify("original-dictionary-detailed-synonyms-item", show(oSynonyms[oRefs[ref][1]][oRefs[ref][2]][k], il))
                            r = r RS temp
                        }
                    }
                }
            }
            if (exists(oSynonymClasses)) {
                # Synonyms
                r = r RS RS
                r = r m("-- display original dictionary (synonyms)")
                r = r prettify("original-dictionary-synonyms", s(showSynonyms(hl), hl))
                for (i = 0; i < length(oSynonymClasses); i++) {
                    r = (i > 0 ? r RS : r) RS prettify("original-dictionary-synonyms-word-class", ins(1, oSynonymClasses[i], hl))
                    for (j = 0; j < length(oSynonyms[i]); j++) {
                        temp = prettify("original-dictionary-synonyms-synonyms", ins(2, "- "))
                        temp = temp prettify("original-dictionary-synonyms-synonyms-item", show(oSynonyms[i][j][0], il))
                        for (k = 1; k < length(oSynonyms[i][j]); k++)
                            temp = temp prettify("original-dictionary-synonyms-synonyms", ", ") \
                                prettify("original-dictionary-synonyms-synonyms-item", show(oSynonyms[i][j][k], il))
                        r = r RS temp
                    }
                }
            }
            if (exists(oExamples)) {
                # Examples
                r = r RS RS
                r = r m("-- display original dictionary (examples)")
                r = r prettify("original-dictionary-examples", s(showExamples(hl), hl))
                for (i = 0; i < length(oExamples); i++) {
                    example = oExamples[i]

                    temp = prettify("original-dictionary-examples-example", ins(1, "- "))
                    split(example, group, /(<b>|<\/b>)/)
                    if (group[3] ~ / [[:punct:].]/)
                        group[3] = substr(group[3], 2)
                    if (isRTL(il)) # target language is R-to-L
                        temp = temp show(group[1] group[2] group[3], il)
                    else # target language is L-to-R
                        temp = temp prettify("original-dictionary-examples-example", group[1]) \
                            prettify("original-dictionary-examples-original", group[2]) \
                            prettify("original-dictionary-examples-example", group[3])
                    r = (i > 0 ? r RS : r) RS temp
                }
            }
            if (exists(oSeeAlso)) {
                # See also
                r = r RS RS
                r = r m("-- display original dictionary (see also)")
                r = r prettify("original-dictionary-see-also", s(showSeeAlso(hl), hl))
                temp = ins(1, prettify("original-dictionary-see-also-phrases-item", show(oSeeAlso[0], il)))
                for (k = 1; k < length(oSeeAlso); k++)
                    temp = temp prettify("original-dictionary-see-also-phrases", ", ") \
                        prettify("original-dictionary-see-also-phrases-item", show(oSeeAlso[k], il))
                r = r RS temp
            }
        }

        if (wShowDictionary) {
            # Display: dictionary entries
            if (r) r = r RS
            r = r m("-- display dictionary entries")
            for (i = 0; i < length(wordClasses); i++) {
                r = (i > 0 ? r RS : r) RS prettify("dictionary-word-class", s(wordClasses[i], hl))
                for (j = 0; j < length(words[i]); j++) {
                    word = words[i][j][0]
                    article = words[i][j][4]
                    if (isRTL(il))
                        explanation = join(words[i][j][1], ", ")
                    else {
                        explanation = prettify("dictionary-explanation-item", words[i][j][1][0])
                        for (k = 1; k < length(words[i][j][1]); k++)
                            explanation = explanation prettify("dictionary-explanation", ", ") \
                                prettify("dictionary-explanation-item", words[i][j][1][k])
                    }

                    r = r RS prettify("dictionary-word", ins(1, (article ? "(" article ") " : "") word, tl))
                    if (isRTL(il))
                        r = r RS prettify("dictionary-explanation-item", ins(2, explanation, il))
                    else
                        r = r RS ins(2, explanation)
                }
            }
        }

        if (wShowAlternatives) {
            # Display: alternative translations
            if (r) r = r RS RS
            r = r m("-- display alternative translations")
            for (i = 0; i < length(altTranslations); i++) {
                r = (i > 0 ? r RS : r) prettify("alternatives-original", show(segments[i], il))
                if (isRTL(tl)) {
                    temp = join(altTranslations[i], ", ")
                    r = r RS prettify("alternatives-translations-item", ins(1, temp, tl))
                } else {
                    temp = prettify("alternatives-translations-item", altTranslations[i][0])
                    for (j = 1; j < length(altTranslations[i]); j++)
                        temp = temp prettify("alternatives-translations", ", ") \
                            prettify("alternatives-translations-item", altTranslations[i][j])
                    r = r RS ins(1, temp)
                }
            }
        }

        if (toSpeech) {
            if (index(showTranslationsOf(hl, "%s"), "%s") > 2) {
                returnPlaylist[0]["text"] = showTranslationsOf(hl)
                returnPlaylist[0]["tl"] = _hl
                returnPlaylist[1]["text"] = join(original)
                returnPlaylist[1]["tl"] = il
            } else {
                returnPlaylist[0]["text"] = join(original)
                returnPlaylist[0]["tl"] = il
                returnPlaylist[1]["text"] = showTranslationsOf(hl)
                returnPlaylist[1]["tl"] = _hl
            }
            returnPlaylist[2]["text"] = translation
            returnPlaylist[2]["tl"] = _tl
        }
    }

    return r
}

####################################################################
# GoogleTranslate.awk                                              #
####################################################################
#
# Last Updated: 18 Dec 2015
# https://translate.google.com/translate/releases/twsfe_w_20151214_RC03/r/js/desktop_module_main.js
BEGIN { provides("google") }

function genRL(a, x,
               ####
               b, c, d, i, y) {
    tokenize(y, x)
    parseList(b, y)
    i = SUBSEP 0
    for (c = 0; c < length(b[i]) - 2; c += 3) {
        d = b[i][c + 2]
        d = d >= 97 ? d - 87 :
            d - 48 # convert to number
        d = b[i][c + 1] == 43 ? rshift(a, d) : lshift(a, d)
        a = b[i][c] == 43 ? and(a + d, 4294967295) : xor(a, d)
    }
    return a
}

function genTK(text,
               ####
               a, d, dLen, e, tkk, ub, vb) {
    if (TK[text]) return TK[text]

    tkk = systime() / 3600
    ub = "[43,45,51,94,43,98,43,45,102]"
    vb = "[43,45,97,94,43,54]"

    # FIXME: build a dump cache!
    dLen = dump(text, d) # convert to byte array
    a = tkk
    for (e = 1; e <= dLen; e++)
        a = genRL(a + d[e], vb)
    a = genRL(a, ub)
    0 > a && (a = and(a, 2147483647) + 2147483648)
    a %= 1e6
    TK[text] = a "." xor(a, tkk)

    l(text, "text")
    l(tkk, "tkk")
    l(TK[text], "tk")
    return TK[text]
}

function googleInit() {
    HttpProtocol = "http://"
    HttpHost = "translate.googleapis.com"
    HttpPort = 80
}

function googleRequestUrl(text, sl, tl, hl,    qc) {
    qc = Option["no-autocorrect"] ? "qc" : "qca";
    return HttpPathPrefix "/translate_a/single?client=gtx"              \
        "&ie=UTF-8&oe=UTF-8"                                            \
        "&dt=bd&dt=ex&dt=ld&dt=md&dt=rw&dt=rm&dt=ss&dt=t&dt=at&dt=gt"   \
        "&dt=" qc "&sl=" sl "&tl=" tl "&hl=" hl                         \
        "&q=" preprocess(text)
}

function googleTTSUrl(text, tl) {
    return HttpProtocol HttpHost "/translate_tts?ie=UTF-8&client=gtx"	\
        "&tl=" tl "&q=" preprocess(text)
}

function googleWebTranslateUrl(uri, sl, tl, hl) {
    return "https://translate.google.com/translate?"    \
        "hl=" hl "&sl=" sl "&tl=" tl "&u=" uri
}

# Get the translation of a string.
function googleTranslate(text, sl, tl, hl,
                         isVerbose, toSpeech, returnPlaylist, returnIl,
                         ####
                         r,
                         content, tokens, ast,
                         _sl, _tl, _hl, il, ils, isPhonetic,
                         article, example, explanation, ref, word,
                         translation, translations, phonetics,
                         wordClasses, words, segments, altTranslations,
                         original, oPhonetics, oWordClasses, oWords,
                         oRefs, oSynonymClasses, oSynonyms,
                         oExamples, oSeeAlso,
                         wShowOriginal, wShowOriginalPhonetics,
                         wShowTranslation, wShowTranslationPhonetics,
                         wShowPromptMessage, wShowLanguages,
                         wShowOriginalDictionary, wShowDictionary,
                         wShowAlternatives,
                         genderedTrans, hasWordClasses, hasAltTranslations,
                         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.")
    }

    # Convert codes or aliases to standard codes used by Google Translate
    # If the code or alias cannot be found, use as it is
    _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)
    if (Option["dump"])
        return content
    tokenize(tokens, content)
    parseJsonArray(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
    }

    saveSortedIn = PROCINFO["sorted_in"]
    PROCINFO["sorted_in"] = "compareByIndexFields"
    for (i in ast) {
        if (ast[i] == "null") continue

        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "0$")
            append(translations, literal(ast[i]))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "1$")
            append(original, literal(ast[i]))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "2$")
            append(phonetics, literal(ast[i]))
        if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "3$")
            append(oPhonetics, literal(ast[i]))

        # 1 - word classes and explanations
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            wordClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "([[:digit:]]+)$", group))
            words[group[1]][group[2]][group[3]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)$", group))
            words[group[1]][group[2]]["1"][group[3]] = literal(ast[i])

        # 5 - alternative translations
        if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group)) {
            segments[group[1]] = literal(ast[i])
            altTranslations[group[1]][0] = ""
        }
        if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            altTranslations[group[1]][group[2]] = literal(ast[i])

        # 7 - autocorrection
        if (i ~ "^0" SUBSEP "7" SUBSEP "5$") {
            if (ast[i] == "true")
                w("Showing translation for:  (use -no-auto to disable autocorrect)")
            else
                w("Did you mean: "                                      \
                  ansi("bold", unparameterize(ast["0" SUBSEP "7" SUBSEP "1"])))
        }

        # 8 - identified source languages
        if (i ~ "^0" SUBSEP "8" SUBSEP "0" SUBSEP "[[:digit:]]+$" ||
            i ~ "^0" SUBSEP "2$")
            append(ils, literal(ast[i]))

        # 11 - (original) word classes and synonyms
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oSynonymClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group))
            if (ast[i]) {
                oRefs[literal(ast[i])][1] = group[1]
                oRefs[literal(ast[i])][2] = group[2]
            }
        if (match(i, "^0" SUBSEP "11" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0" SUBSEP "([[:digit:]]+)$", group))
            oSynonyms[group[1]][group[2]][group[3]] = literal(ast[i])

        # 12 - (original) word classes and explanations
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oWordClasses[group[1]] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oWords[group[1]][group[2]][0] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group))
            oWords[group[1]][group[2]][1] = literal(ast[i])
        if (match(i, "^0" SUBSEP "12" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2$", group))
            oWords[group[1]][group[2]][2] = literal(ast[i])

        # 13 - (original) examples
        if (match(i, "^0" SUBSEP "13" SUBSEP "0" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
            oExamples[group[1]] = literal(ast[i])

        # 14 - (original) see also
        if (match(i, "^0" SUBSEP "14" SUBSEP "0" SUBSEP "([[:digit:]]+)$", group))
            oSeeAlso[group[1]] = literal(ast[i])

        # 18 - gender-specific translations
        if (match(i, "^0" SUBSEP "18" SUBSEP "0" SUBSEP "([[:digit:]]+)" SUBSEP "1$", group))
            genderedTrans[group[1]] = literal(ast[i])
    }
    PROCINFO["sorted_in"] = saveSortedIn

    translation = join(translations)

    returnIl[0] = il = !anything(ils) || belongsTo(sl, ils) ? sl : ils[0]
    if (Option["verbose"] < -1)
        return il
    else if (Option["verbose"] < 0)
        return getList(il)

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

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

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

    } else {
        # Verbose mode

        wShowOriginal = Option["show-original"]
        wShowOriginalPhonetics = Option["show-original-phonetics"]
        wShowTranslation = Option["show-translation"]
        wShowTranslationPhonetics = Option["show-translation-phonetics"]
        wShowPromptMessage = Option["show-prompt-message"]
        wShowLanguages = Option["show-languages"]
        wShowOriginalDictionary = Option["show-original-dictionary"]
        wShowDictionary = Option["show-dictionary"]
        wShowAlternatives = Option["show-alternatives"]

        if (!anything(oPhonetics)) wShowOriginalPhonetics = 0
        if (!anything(phonetics)) wShowTranslationPhonetics = 0
        if (getCode(il) == getCode(tl) &&                               \
            (isarray(oWordClasses) || isarray(oSynonymClasses) ||       \
             isarray(oExamples) || isarray(oSeeAlso))) {
            wShowOriginalDictionary = 1
            wShowTranslation = 0
        }
        hasWordClasses = exists(wordClasses)
        hasAltTranslations = exists(altTranslations[0])
        if (!hasWordClasses && !hasAltTranslations)
            wShowPromptMessage = wShowLanguages = 0
        if (!hasWordClasses) wShowDictionary = 0
        if (!hasAltTranslations) wShowAlternatives = 0

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

        if (wShowTranslation) {
            # Display: major translation & phonetics
            if (r) r = r RS RS
            r = r m("-- display major translation & phonetics")
            if (!exists(genderedTrans))
                r = r prettify("translation", s(translation, tl))
            else {
                r = r prettify("prompt-message", s("(♂) ", hl))
                r = r prettify("translation", s(genderedTrans[0], tl)) RS
                r = r prettify("prompt-message", s("(♀) ", hl))
                r = r prettify("translation", s(genderedTrans[1], tl))
            }
            if (wShowTranslationPhonetics)
                r = r RS prettify("translation-phonetics", showPhonetics(join(phonetics, " "), tl))
        }

        if (wShowPromptMessage || wShowLanguages)
            if (r) r = r RS
        if (wShowPromptMessage) {
            if (hasWordClasses) {
                # Display: prompt message (Definitions of ...)
                if (r) r = r RS
                r = r m("-- display prompt message (Definitions of ...)")
                if (isRTL(hl)) # home language is R-to-L
                    r = r prettify("prompt-message", s(showDefinitionsOf(hl, join(original, " "))))
                else { # home language is L-to-R
                    split(showDefinitionsOf(hl, "\0%s\0"), group, "\0")
                    for (i = 1; i <= length(group); i++) {
                        if (group[i] == "%s")
                            r = r prettify("prompt-message-original", show(join(original, " "), il))
                        else
                            r = r prettify("prompt-message", group[i])
                    }
                }
            } else if (hasAltTranslations) {
                # Display: prompt message (Translations of ...)
                if (r) r = r RS
                r = r m("-- display prompt message (Translations of ...)")
                if (isRTL(hl)) # home language is R-to-L
                    r = r prettify("prompt-message", s(showTranslationsOf(hl, join(original, " "))))
                else { # home language is L-to-R
                    split(showTranslationsOf(hl, "\0%s\0"), group, "\0")
                    for (i = 1; i <= length(group); i++) {
                        if (group[i] == "%s")
                            r = r prettify("prompt-message-original", show(join(original, " "), il))
                        else
                            r = r prettify("prompt-message", group[i])
                    }
                }
            }
        }
        if (wShowLanguages) {
            # Display: source language -> target language
            if (r) r = r 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 (wShowOriginalDictionary) {
            # Display: original dictionary
            if (exists(oWordClasses)) {
                # Detailed explanations
                if (r) r = r RS
                r = r m("-- display original dictionary (detailed explanations)")
                for (i = 0; i < length(oWordClasses); i++) {
                    r = (i > 0 ? r RS : r) RS prettify("original-dictionary-detailed-word-class", s(oWordClasses[i], hl))
                    for (j = 0; j < length(oWords[i]); j++) {
                        explanation = oWords[i][j][0]
                        ref = oWords[i][j][1]
                        example = oWords[i][j][2]

                        r = (j > 0 ? r RS : r) RS prettify("original-dictionary-detailed-explanation", ins(1, explanation, il))
                        if (example)
                            r = r RS prettify("original-dictionary-detailed-example", ins(2, "- \"" example "\"", il))
                        if (ref && isarray(oRefs[ref])) {
                            temp = prettify("original-dictionary-detailed-synonyms", ins(1, show(showSynonyms(hl), hl) ": "))
                            temp = temp prettify("original-dictionary-detailed-synonyms-item", show(oSynonyms[oRefs[ref][1]][oRefs[ref][2]][0], il))
                            for (k = 1; k < length(oSynonyms[oRefs[ref][1]][oRefs[ref][2]]); k++)
                                temp = temp prettify("original-dictionary-detailed-synonyms", ", ") \
                                    prettify("original-dictionary-detailed-synonyms-item", show(oSynonyms[oRefs[ref][1]][oRefs[ref][2]][k], il))
                            r = r RS temp
                        }
                    }
                }
            }
            if (exists(oSynonymClasses)) {
                # Synonyms
                r = r RS RS
                r = r m("-- display original dictionary (synonyms)")
                r = r prettify("original-dictionary-synonyms", s(showSynonyms(hl), hl))
                for (i = 0; i < length(oSynonymClasses); i++) {
                    r = (i > 0 ? r RS : r) RS prettify("original-dictionary-synonyms-word-class", ins(1, oSynonymClasses[i], hl))
                    for (j = 0; j < length(oSynonyms[i]); j++) {
                        temp = prettify("original-dictionary-synonyms-synonyms", ins(2, "- "))
                        temp = temp prettify("original-dictionary-synonyms-synonyms-item", show(oSynonyms[i][j][0], il))
                        for (k = 1; k < length(oSynonyms[i][j]); k++)
                            temp = temp prettify("original-dictionary-synonyms-synonyms", ", ") \
                                prettify("original-dictionary-synonyms-synonyms-item", show(oSynonyms[i][j][k], il))
                        r = r RS temp
                    }
                }
            }
            if (exists(oExamples)) {
                # Examples
                r = r RS RS
                r = r m("-- display original dictionary (examples)")
                r = r prettify("original-dictionary-examples", s(showExamples(hl), hl))
                for (i = 0; i < length(oExamples); i++) {
                    example = oExamples[i]

                    temp = prettify("original-dictionary-examples-example", ins(1, "- "))
                    split(example, group, /(<b>|<\/b>)/)
                    if (group[3] ~ / [[:punct:].]/)
                        group[3] = substr(group[3], 2)
                    if (isRTL(il)) # target language is R-to-L
                        temp = temp show(group[1] group[2] group[3], il)
                    else # target language is L-to-R
                        temp = temp prettify("original-dictionary-examples-example", group[1]) \
                            prettify("original-dictionary-examples-original", group[2]) \
                            prettify("original-dictionary-examples-example", group[3])
                    r = (i > 0 ? r RS : r) RS temp
                }
            }
            if (exists(oSeeAlso)) {
                # See also
                r = r RS RS
                r = r m("-- display original dictionary (see also)")
                r = r prettify("original-dictionary-see-also", s(showSeeAlso(hl), hl))
                temp = ins(1, prettify("original-dictionary-see-also-phrases-item", show(oSeeAlso[0], il)))
                for (k = 1; k < length(oSeeAlso); k++)
                    temp = temp prettify("original-dictionary-see-also-phrases", ", ") \
                        prettify("original-dictionary-see-also-phrases-item", show(oSeeAlso[k], il))
                r = r RS temp
            }
        }

        if (wShowDictionary) {
            # Display: dictionary entries
            if (r) r = r RS
            r = r m("-- display dictionary entries")
            for (i = 0; i < length(wordClasses); i++) {
                r = (i > 0 ? r RS : r) RS prettify("dictionary-word-class", s(wordClasses[i], hl))
                for (j = 0; j < length(words[i]); j++) {
                    word = words[i][j][0]
                    article = words[i][j][4]
                    if (isRTL(il))
                        explanation = join(words[i][j][1], ", ")
                    else {
                        explanation = prettify("dictionary-explanation-item", words[i][j][1][0])
                        for (k = 1; k < length(words[i][j][1]); k++)
                            explanation = explanation prettify("dictionary-explanation", ", ") \
                                prettify("dictionary-explanation-item", words[i][j][1][k])
                    }

                    r = r RS prettify("dictionary-word", ins(1, (article ? "(" article ") " : "") word, tl))
                    if (isRTL(il))
                        r = r RS prettify("dictionary-explanation-item", ins(2, explanation, il))
                    else
                        r = r RS ins(2, explanation)
                }
            }
        }

        if (wShowAlternatives) {
            # Display: alternative translations
            if (r) r = r RS RS
            r = r m("-- display alternative translations")
            for (i = 0; i < length(altTranslations); i++) {
                r = (i > 0 ? r RS : r) prettify("alternatives-original", show(segments[i], il))
                if (isRTL(tl)) {
                    temp = join(altTranslations[i], ", ")
                    r = r RS prettify("alternatives-translations-item", ins(1, temp, tl))
                } else {
                    temp = prettify("alternatives-translations-item", altTranslations[i][0])
                    for (j = 1; j < length(altTranslations[i]); j++)
                        temp = temp prettify("alternatives-translations", ", ") \
                            prettify("alternatives-translations-item", altTranslations[i][j])
                    r = r RS ins(1, temp)
                }
            }
        }

        if (toSpeech) {
            if (index(showTranslationsOf(hl, "%s"), "%s") > 2) {
                returnPlaylist[0]["text"] = showTranslationsOf(hl)
                returnPlaylist[0]["tl"] = _hl
                returnPlaylist[1]["text"] = join(original)
                returnPlaylist[1]["tl"] = il
            } else {
                returnPlaylist[0]["text"] = join(original)
                returnPlaylist[0]["tl"] = il
                returnPlaylist[1]["text"] = showTranslationsOf(hl)
                returnPlaylist[1]["tl"] = _hl
            }
            returnPlaylist[2]["text"] = translation
            returnPlaylist[2]["tl"] = _tl
        }
    }

    return r
}


In Competition

In Competition

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

BEGIN {
   str = $0
   print "String before replacement = " str

   gsub("World", "Jerry", str)
   print "String after replacement = " str
}

END {

}

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

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

END {

}


Fixed non-POSIX errors

Fixed non-POSIX errors

function writeStatic(device, fields, orders) {

    # Create the order as original
    for (o = 0; o in orders; o++) {
	field = orders[o];
	value = fields[field];
	delete fields[field];
	if (length(value)) {
	    printf("    %s %s\n", field, value);
	}
    }

    # additional items have no order
    for (f in fields) {
	value = fields[f];
	if (length(value)) {
	    printf("    %s %s\n", f, value);
	}
    }
    print "";
}

function usage() {
        print "awk -f changeInterfaces.awk <interfaces file> dev=<eth device> \n" \
            "       [mode=dhcp|static|manual] [action=add|remove] \n" \
            "       [address=<ip addr> networkmask=<ipaddress> <name=value> ]\n" \
	    "       [arg=debug]\n"
}

BEGIN { start = 0;

    order = 0

    if (ARGC < 3 || ARGC > 10) {
        usage();
        exit 1;
    }

    for (i = 2; i < ARGC; i++) {
        num = split(ARGV[i], pair, "=");
        if (pair[1] == "arg" && pair[2] == "debug") {
            debug = 1;
	} else if (pair[1] == "mode") {
	    mode = pair[2];
	} else if (pair[1] == "action" && pair[2] == "remove")
            remove = 1;
        else if (pair[1] == "action" && pair[2] == "add")
            add = 1;
	else if (pair[1] == "device" || pair[1] == "dev") {
	    device = pair[2];
	} else if (num == 2) {
	    if (pair[1] == "dns") {
		pair[1] = "dns-nameservers";
	    }
	    settings[pair[1]] = pair[2];
	} else {
	    usage();
	    exit 1;
	}
    }

    # Sort out the logic of argument
    if (mode == "dhcp" && (length(network) || length(gateway) || length(address) || length(netmask))) {
        print "Both DHCP and static properties are defined";
        usage();
        exit 1;
    } else if (!mode && !remove) {
	print "Missing mode input";
	usage();
	exit 1;
    }

    if (debug) {
	for (f in settings) {
	    print f, ": ", settings[f];
	}
    }
}

{
    # auto <device> line
    if ($1 == "auto") {
	if ($2 != device) {
	    # We come to different device
	    # Good place to write all the settings
	    if (targetDev) {
		targetDev = 0;
		if (!add && !remove) {
		    if (mode == "static" || mode == "manual") {
			writeStatic(device, settings, fieldOrders);
		    }
		}
	    }
	    print $0;
	    next;
	} else if (!remove) {
	    print $0;
	    add = 0;
	    next;
	}
	# Remove - don't print
	next;
    }
    # iface <device> .. line
    else if ($1 == "iface") {

	if ($2 != device) {
	    # We come to different device
	    # Good place to write all the settings
	    if (targetDev) {
		targetDev = 0;
		if (!add && !remove) {
		    if (mode == "static" || mode == "manual") {
			writeStatic(device, settings, fieldOrders);
		    }
		}
	    }
	    print $0;
	    next;
	} else {

	    # If already specified 'add' and found an existing entry
	    # cancel it
	    add = 0;

	    # Go to different condition in next loop
	    targetDev = 1;

	    if (!remove) {
		printf("iface %s inet %s\n", device, mode);
	    }
	    next;
	}
    }

    # Matched device found - working through each line
    # until found a 'auto' line or end of file
    else if (targetDev) {

	# Comment line - leave it
	if (substr($1, 0, 1) == "#") {
	    print $0;
	    next;
	}

	field = $1;
	if (field in settings) {
	    # It means we specify the argument in command line
	    # as preference over the file content
	} else {
	    # field not in the command line
	    # copy it over
	    settings[field] = substr($0, index($0, $2))
	}
	fieldOrders[order] = field
	order++;
	next;

    # Other type of lines e.g. comment
    } else {
	print $0;
	next;
    }
}

END {

    # Come to the last line and we may not print out the
    # matched device settings
    if (!remove) {
	if (add || targetDev) {
	    if (add) {
		printf("auto %s\n", device);
		printf("iface %s inet %s\n", device, mode);
	    }
	    if (mode != "dhcp") {
		writeStatic(device, settings, fieldOrders);
	    }
	}
    }
}

function writeStatic(device, fields, orders) {

    # Create the order as original
    for (o = 0; o < length(orders); o++) {
	field = orders[o];
	value = fields[field];
	delete fields[field];
	if (length(value)) {
	    printf("    %s %s\n", field, value);
	}
    }

    # additional items have no order
    for (f in fields) {
	value = fields[f];
	if (length(value)) {
	    printf("    %s %s\n", f, value);
	}
    }
    print "";
}

function usage() {
        print "awk -f changeInterfaces.awk <interfaces file> dev=<eth device> \n" \
            "       [mode=dhcp|static|manual] [action=add|remove] \n" \
            "       [address=<ip addr> networkmask=<ipaddress> <name=value> ]\n" \
	    "       [arg=debug]\n"
}

BEGIN { start = 0;

    order = 0

    if (ARGC < 3 || ARGC > 10) {
        usage();
        exit 1;
    }

    for (i = 2; i < ARGC; i++) {
        split(ARGV[i], pair, "=");
        if (pair[1] == "arg" && pair[2] == "debug") {
            debug = 1;
	} else if (pair[1] == "mode") {
	    mode = pair[2];
	} else if (pair[1] == "action" && pair[2] == "remove")
            remove = 1;
        else if (pair[1] == "action" && pair[2] == "add")
            add = 1;
	else if (pair[1] == "device" || pair[1] == "dev") {
	    device = pair[2];
	} else if (length(pair) == 2) {
	    if (pair[1] == "dns") {
		pair[1] = "dns-nameservers";
	    }
	    settings[pair[1]] = pair[2];
	} else {
	    usage();
	    exit 1;
	}
    }

    # Sort out the logic of argument
    if (mode == "dhcp" && (length(network) || length(gateway) || length(address) || length(netmask))) {
        print "Both DHCP and static properties are defined";
        usage();
        exit 1;
    } else if (!mode && !remove) {
	print "Missing mode input";
	usage();
	exit 1;
    }

    if (debug) {
	for (f in settings) {
	    print f, ": ", settings[f];
	}
    }
}

{
    # auto <device> line
    if ($1 == "auto") {
	if ($2 != device) {
	    # We come to different device
	    # Good place to write all the settings
	    if (targetDev) {
		targetDev = 0;
		if (!add && !remove) {
		    if (mode == "static" || mode == "manual") {
			writeStatic(device, settings, fieldOrders);
		    }
		}
	    }
	    print $0;
	    next;
	} else if (!remove) {
	    print $0;
	    add = 0;
	    next;
	}
	# Remove - don't print
	next;
    }
    # iface <device> .. line
    else if ($1 == "iface") {

	if ($2 != device) {
	    # We come to different device
	    # Good place to write all the settings
	    if (targetDev) {
		targetDev = 0;
		if (!add && !remove) {
		    if (mode == "static" || mode == "manual") {
			writeStatic(device, settings, fieldOrders);
		    }
		}
	    }
	    print $0;
	    next;
	} else {

	    # If already specified 'add' and found an existing entry
	    # cancel it
	    add = 0;

	    # Go to different condition in next loop
	    targetDev = 1;

	    if (!remove) {
		printf("iface %s inet %s\n", device, mode);
	    }
	    next;
	}
    }

    # Matched device found - working through each line
    # until found a 'auto' line or end of file
    else if (targetDev) {

	# Comment line - leave it
	if (substr($1, 0, 1) == "#") {
	    print $0;
	    next;
	}

	field = $1;
	if (field in settings) {
	    # It means we specify the argument in command line
	    # as preference over the file content
	} else {
	    # field not in the command line
	    # copy it over
	    settings[field] = substr($0, index($0, $2))
	}
	fieldOrders[order] = field
	order++;
	next;

    # Other type of lines e.g. comment
    } else {
	print $0;
	next;
    }
}

END {

    # Come to the last line and we may not print out the
    # matched device settings
    if (!remove) {
	if (add || targetDev) {
	    if (add) {
		printf("auto %s\n", device);
		printf("iface %s inet %s\n", device, mode);
	    }
	    if (mode != "dhcp") {
		writeStatic(device, settings, fieldOrders);
	    }
	}
    }
}


change compare and title heads

change compare and title heads

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

#!/usr/bin/awk -f
# input: publisher\tplugin\tcontract_year\tyear\ttester\tstatus

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

{
# add a loop to add line only if ending year is gt or eq to contract year
end = 0
if ((length($4) == 9) {
  end = substr($4,6,4)
} else if ((length($4) == 4 {
  end = substr($4,1,4)
}
if (end >= $3) incontract = 1
else incontract = 0

if (incontract == 1) {
    nn = split($2,na,/\./)
    lp2 = na[nn]
  if (!(($1,lp2,$3,$4) in b)) {
    p[pn] = $1
    n[pn] = lp2
#    n[pn] = $2
    t[pn] = $3
    d[pn] = $4
    r[pn] = $5
    pn++
  }
  b[$1,lp2,$3,$4]++
  c[$1,lp2,$3,$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] = "X"
  sc[1] = "E"
  sc[2] = "M"
  sc[3] = "W"
  sc[4] = "C"
  sc[5] = "T"
  sc[6] = "N"
  sc[7] = "R"
  sc[8] = "D"
  sc[9] = "S"
  sc[10] = "Z"
  scn = 11

  #print out header
  printf "Publisher\tPlugin\tContr\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, year, total aus
  for (i = 0 ; i < pn ; i++) {
    printf "%s\t%s\t%s\t%s\t%s\t%d", p[i], n[i], t[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],d[i],s[j]] == 0) {
      printf "\t.."
    } else {
        printf "\t%d", c[p[i],n[i],t[i],d[i],s[j]]
      }
    }
    }
    printf "\n"
  }
    #print out bottom line sums
    printf "Publisher\tPlugin\tContr\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
# input: publisher\tplugin\tcontract_year\tyear\ttester\tstatus

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

{
# add a loop to add line only if first 4 char or last 4 char of year are gt or eq to contract
if ((substr($4,1,4) >= $3) || ((length($4) == 9) && (substr($4,6,4) >= $3))) {
    nn = split($2,na,/\./)
    lp2 = na[nn]
  if (!(($1,lp2,$3,$4) in b)) {
    p[pn] = $1
    n[pn] = lp2
#    n[pn] = $2
    t[pn] = $3
    d[pn] = $4
    r[pn] = $5
    pn++
  }
  b[$1,lp2,$3,$4]++
  c[$1,lp2,$3,$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\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, year, total aus
  for (i = 0 ; i < pn ; i++) {
    printf "%s\t%s\t%s\t%s\t%s\t%d", p[i], n[i], t[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],d[i],s[j]] == 0) {
      printf "\t.."
    } else {
        printf "\t%d", c[p[i],n[i],t[i],d[i],s[j]]
      }
    }
    }
    printf "\n"
  }
    #print out bottom line sums
    printf "Publisher\tPlugin\tContr\tYear\tT\t%d", tt
    for (j = 0 ; j < sn ; j++) {
    	if (x[s[j]] > 0) {
    		printf "\t%d", x[s[j]]
      }
    }

  printf "\n"
}


Drop unused arguments.

Drop unused arguments.

function printUrlQueryString(queryString, j)
{
    split(queryString, pairs, "&")
    len = length(pairs)
    for (j = 1; j < len; ++j) {
        split(pairs[j], keyValue, "=")
        k = keyValue[1]
        v = keyValue[2]
        printf "\t\t\"%s\": \"%s\",\n", k, urlDecode(urlDecode(v))
    }
}

function base64Decode(thing)
{
  "echo "$thing" | base64 --decode" | getline x
  return x
}

function urlDecode(url, i) {
    for (i = 0x20; i < 0x40; ++i) {
        repl = sprintf("%c", i);
        if ((repl == "&") || (repl == "\\")) {
            repl = "\\" repl;
        }
        url = gensub(sprintf("%%%02X", i), repl, "g", url);
        url = gensub(sprintf("%%%02x", i), repl, "g", url);
    }
    return url;
}

BEGIN {
    logLineSeen = 0
    print "{";
}

END {
    print "}"
}

/^#Version: / {
    printf "\t\"version\": \"%s\",\n", substr($0, length("#Version: ") + 1)
}

/^#Fields: / {
    rest = substr($0, length("#Fields: ") + 1)
    split(rest, fields, " ")
    numFields = length(fields)
}

/^#/ {
    # ignore anything else starting with "#"
}

! /^#/ {
    if (logLineSeen == 1) {
        printf ",\n"
    }
    split($0, fieldsThisLine, " ")
    urlIndex = 0
    if (NF == numFields) {
        print "\t{"
        for(i = 1; i < NF; i++)
        {
            fieldName = fields[i]
            if (fieldName == "cs-uri-query") {
                urlIndex = i;
                continue;
            }
            fieldValue = fieldsThisLine[i]
            maybeDecoded = (fieldName == "cs-uri-query" ? urlDecode(fieldValue) : fieldValue)
            printf "\t\t\"%s\": \"%s\"", fieldName, fieldValue
            if (i + 1 < NF && urlIndex > 0) {
                printf ","
            }
            printf "\n"
        }
        if (urlIndex > 0) {
            printf "\t\t\"cs-url-query\": {\n"
            printUrlQueryString(fieldsThisLine[urlIndex])
            printf "}\n"
        }
        printf "\t}"
    }
    logLineSeen = 1;
}

function printUrlQueryString(queryString, j)
{
    split(queryString, pairs, "&", seps)
    len = length(pairs)
    for (j = 1; j < len; ++j) {
        split(pairs[j], keyValue, "=", seps2)
        k = keyValue[1]
        v = keyValue[2]
        printf "\t\t\"%s\": \"%s\",\n", k, urlDecode(urlDecode(v))
    }
}

function base64Decode(thing)
{
  "echo "$thing" | base64 --decode" | getline x
  return x
}

function urlDecode(url, i) {
    for (i = 0x20; i < 0x40; ++i) {
        repl = sprintf("%c", i);
        if ((repl == "&") || (repl == "\\")) {
            repl = "\\" repl;
        }
        url = gensub(sprintf("%%%02X", i), repl, "g", url);
        url = gensub(sprintf("%%%02x", i), repl, "g", url);
    }
    return url;
}

BEGIN {
    logLineSeen = 0
    print "{";
}

END {
    print "}"
}

/^#Version: / {
    printf "\t\"version\": \"%s\",\n", substr($0, length("#Version: ") + 1)
}

/^#Fields: / {
    rest = substr($0, length("#Fields: ") + 1)
    split(rest, fields, " ")
    numFields = length(fields)
}

/^#/ {
    # ignore anything else starting with "#"
}

! /^#/ {
    if (logLineSeen == 1) {
        printf ",\n"
    }
    split($0, fieldsThisLine, " ")
    urlIndex = 0
    if (NF == numFields) {
        print "\t{"
        for(i = 1; i < NF; i++)
        {
            fieldName = fields[i]
            if (fieldName == "cs-uri-query") {
                urlIndex = i;
                continue;
            }
            fieldValue = fieldsThisLine[i]
            maybeDecoded = (fieldName == "cs-uri-query" ? urlDecode(fieldValue) : fieldValue)
            printf "\t\t\"%s\": \"%s\"", fieldName, fieldValue
            if (i + 1 < NF && urlIndex > 0) {
                printf ","
            }
            printf "\n"
        }
        if (urlIndex > 0) {
            printf "\t\t\"cs-url-query\": {\n"
            printUrlQueryString(fieldsThisLine[urlIndex])
            printf "}\n"
        }
        printf "\t}"
    }
    logLineSeen = 1;
}


TestUtils: case to fail newerVersion()

TestUtils: case to fail newerVersion()

@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"))
    }

    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()", 4)
    {
        assertTrue(newerVersion("0.9", "0.8"))
        assertTrue(newerVersion("1.0", "0.9.9999"))
        assertTrue(newerVersion("1.9.9999", "1.9.10"))
        assertTrue(newerVersion("2", "1.9.9999"))
    }

    END_TEST()
}


REPL: support setting sl and tl by :set (fix #451)

####################################################################
# REPL.awk                                                         #
####################################################################

# Welcome message.
function welcome() {
    if (Option["fmt-welcome-message"])
        print prettify("welcome-message", Option["fmt-welcome-message"]) > STDERR
    if (Option["fmt-welcome-submessage"])
        print prettify("welcome-submessage", Option["fmt-welcome-submessage"]) > STDERR
}

# Prompt for interactive session.
function prompt(    i, p, temp) {
    p = Option["fmt-prompt"]

    # Format specifiers supported by strftime().
    # Roughly following ISO 8601:1988, with the notable exception of "%S", "%t" and "%T".
    # GNU libc extensions like "%l", "%s" and "%_*" are not supported.
    # See: <https://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html>
    #      <http://pubs.opengroup.org/onlinepubs/007908799/xsh/strftime.html>
    if (p ~ /%a/) gsub(/%a/, strftime("%a"), p)
    if (p ~ /%A/) gsub(/%A/, strftime("%A"), p)
    if (p ~ /%b/) gsub(/%b/, strftime("%b"), p)
    if (p ~ /%B/) gsub(/%B/, strftime("%B"), p)
    if (p ~ /%c/) gsub(/%c/, strftime("%c"), p)
    if (p ~ /%C/) gsub(/%C/, strftime("%C"), p)
    if (p ~ /%d/) gsub(/%d/, strftime("%d"), p)
    if (p ~ /%D/) gsub(/%D/, strftime("%D"), p)
    if (p ~ /%e/) gsub(/%e/, strftime("%e"), p)
    if (p ~ /%F/) gsub(/%F/, strftime("%F"), p)
    if (p ~ /%g/) gsub(/%g/, strftime("%g"), p)
    if (p ~ /%G/) gsub(/%G/, strftime("%G"), p)
    if (p ~ /%h/) gsub(/%h/, strftime("%h"), p)
    if (p ~ /%H/) gsub(/%H/, strftime("%H"), p)
    if (p ~ /%I/) gsub(/%I/, strftime("%I"), p)
    if (p ~ /%j/) gsub(/%j/, strftime("%j"), p)
    if (p ~ /%m/) gsub(/%m/, strftime("%m"), p)
    if (p ~ /%M/) gsub(/%M/, strftime("%M"), p)
    if (p ~ /%n/) gsub(/%n/, strftime("%n"), p)
    if (p ~ /%p/) gsub(/%p/, strftime("%p"), p)
    if (p ~ /%r/) gsub(/%r/, strftime("%r"), p)
    if (p ~ /%R/) gsub(/%R/, strftime("%R"), p)
    if (p ~ /%u/) gsub(/%u/, strftime("%u"), p)
    if (p ~ /%U/) gsub(/%U/, strftime("%U"), p)
    if (p ~ /%V/) gsub(/%V/, strftime("%V"), p)
    if (p ~ /%w/) gsub(/%w/, strftime("%w"), p)
    if (p ~ /%W/) gsub(/%W/, strftime("%W"), p)
    if (p ~ /%x/) gsub(/%x/, strftime("%x"), p)
    if (p ~ /%X/) gsub(/%X/, strftime("%X"), p)
    if (p ~ /%y/) gsub(/%y/, strftime("%y"), p)
    if (p ~ /%Y/) gsub(/%Y/, strftime("%Y"), p)
    if (p ~ /%z/) gsub(/%z/, strftime("%z"), p)
    if (p ~ /%Z/) gsub(/%Z/, strftime("%Z"), p)

    # %_ : prompt message
    if (p ~ /%_/)
        gsub(/%_/, showTranslationsOf(Option["hl"]), p)

    # %l : host language
    if (p ~ /%l/)
        gsub(/%l/, getDisplay(Option["hl"]), p)

    # %L : host language (English name)
    if (p ~ /%L/)
        gsub(/%L/, getName(Option["hl"]), p)

    # %s : source languages, separated by "+"
    # 's' is the format-control character for string

    # %S : source languages (English names), separated by "+"
    if (p ~ /%S/) {
        temp = getName(Option["sls"][1])
        for (i = 2; i <= length(Option["sls"]); i++)
            temp = temp "+" getName(Option["sls"][i])
        gsub(/%S/, temp, p)
    }

    # TODO: source languages separated by "," and "/"

    # %t : target languages, separated by "+"
    if (p ~ /%t/) {
        temp = getDisplay(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "+" getDisplay(Option["tl"][i])
        gsub(/%t/, temp, p)
    }

    # %T : target languages (English names), separated by "+"
    if (p ~ /%T/) {
        temp = getName(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "+" getName(Option["tl"][i])
        gsub(/%T/, temp, p)
    }

    # %, : target languages, separated by ","
    if (p ~ /%,/) {
        temp = getDisplay(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "," getDisplay(Option["tl"][i])
        gsub(/%,/, temp, p)
    }

    # %< : target languages (English names), separated by ","
    if (p ~ /%</) {
        temp = getName(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "," getName(Option["tl"][i])
        gsub(/%</, temp, p)
    }

    # %/ : target languages, separated by "/"
    if (p ~ /%\//) {
        temp = getDisplay(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "/" getDisplay(Option["tl"][i])
        gsub(/%\//, temp, p)
    }

    # %? : target languages (English names), separated by "/"
    if (p ~ /%\?/) {
        temp = getName(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "/" getName(Option["tl"][i])
        gsub(/%\?/, temp, p)
    }

    # %s : source languages, separated by "+"
    temp = getDisplay(Option["sls"][1])
    for (i = 2; i <= length(Option["sls"]); i++)
        temp = temp "+" getDisplay(Option["sls"][i])
    printf(prettify("prompt", p), temp) > STDERR
}

# REPL.
function repl(line,    command, group, name, i, value, words) {
    split(line, words, " ")
    command = words[1]

    if (command ~ /^:(q|quit)$/) {
        exit
    } else if (command ~ /^:set$/) {
        name = words[2]
        value = words[3]
        Option[name] = value
        # :set sl and :set tl should work as intended
        # TODO: support multiple language codes
        if (name == "sl") {
            delete Option["sls"]
            Option["sls"][1] = Option["sl"]
        } else if (name == "tl") {
            delete Option["tl"]
            Option["tl"][1] = value
        }
    } else if (command ~ /^:show$/) {
        name = words[2]
        print prettify("welcome-submessage", toString(Option[name], 1, 0, 1))
    } else if (command ~ /^:swap$/) {
        tl = Option["tl"][1]
        Option["tl"][1] = Option["sls"][1]
        Option["sls"][1] = tl
    } else if (command ~ /^:engine$/) {
        value = words[2]
        Option["engine"] = value
        initHttpService()
    } else if (command ~ /^:reset$/) {
        # TODO: reset source and target languages, etc.
    } else {
        match(command, /^[{(\[]?((@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?\+)*(@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?)?)?(:|=)((@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?\+)*(@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?)?)[})\]]?$/, group)
        if (RSTART) {
            if (group[1]) {
                split(group[1], Option["sls"], "+")
                Option["sl"] = Option["sls"][1]
            }
            if (group[7]) split(group[7], Option["tl"], "+")
            line = words[2]
            for (i = 3; i <= length(words); i++)
                line = line " " words[i]
        }
        if (line) {
            translates(line)

            # Interactive verbose mode: newline after each translation
            if (Option["verbose"]) printf RS
        }
    }

    prompt()
}

####################################################################
# REPL.awk                                                         #
####################################################################

# Welcome message.
function welcome() {
    if (Option["fmt-welcome-message"])
        print prettify("welcome-message", Option["fmt-welcome-message"]) > STDERR
    if (Option["fmt-welcome-submessage"])
        print prettify("welcome-submessage", Option["fmt-welcome-submessage"]) > STDERR
}

# Prompt for interactive session.
function prompt(    i, p, temp) {
    p = Option["fmt-prompt"]

    # Format specifiers supported by strftime().
    # Roughly following ISO 8601:1988, with the notable exception of "%S", "%t" and "%T".
    # GNU libc extensions like "%l", "%s" and "%_*" are not supported.
    # See: <https://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html>
    #      <http://pubs.opengroup.org/onlinepubs/007908799/xsh/strftime.html>
    if (p ~ /%a/) gsub(/%a/, strftime("%a"), p)
    if (p ~ /%A/) gsub(/%A/, strftime("%A"), p)
    if (p ~ /%b/) gsub(/%b/, strftime("%b"), p)
    if (p ~ /%B/) gsub(/%B/, strftime("%B"), p)
    if (p ~ /%c/) gsub(/%c/, strftime("%c"), p)
    if (p ~ /%C/) gsub(/%C/, strftime("%C"), p)
    if (p ~ /%d/) gsub(/%d/, strftime("%d"), p)
    if (p ~ /%D/) gsub(/%D/, strftime("%D"), p)
    if (p ~ /%e/) gsub(/%e/, strftime("%e"), p)
    if (p ~ /%F/) gsub(/%F/, strftime("%F"), p)
    if (p ~ /%g/) gsub(/%g/, strftime("%g"), p)
    if (p ~ /%G/) gsub(/%G/, strftime("%G"), p)
    if (p ~ /%h/) gsub(/%h/, strftime("%h"), p)
    if (p ~ /%H/) gsub(/%H/, strftime("%H"), p)
    if (p ~ /%I/) gsub(/%I/, strftime("%I"), p)
    if (p ~ /%j/) gsub(/%j/, strftime("%j"), p)
    if (p ~ /%m/) gsub(/%m/, strftime("%m"), p)
    if (p ~ /%M/) gsub(/%M/, strftime("%M"), p)
    if (p ~ /%n/) gsub(/%n/, strftime("%n"), p)
    if (p ~ /%p/) gsub(/%p/, strftime("%p"), p)
    if (p ~ /%r/) gsub(/%r/, strftime("%r"), p)
    if (p ~ /%R/) gsub(/%R/, strftime("%R"), p)
    if (p ~ /%u/) gsub(/%u/, strftime("%u"), p)
    if (p ~ /%U/) gsub(/%U/, strftime("%U"), p)
    if (p ~ /%V/) gsub(/%V/, strftime("%V"), p)
    if (p ~ /%w/) gsub(/%w/, strftime("%w"), p)
    if (p ~ /%W/) gsub(/%W/, strftime("%W"), p)
    if (p ~ /%x/) gsub(/%x/, strftime("%x"), p)
    if (p ~ /%X/) gsub(/%X/, strftime("%X"), p)
    if (p ~ /%y/) gsub(/%y/, strftime("%y"), p)
    if (p ~ /%Y/) gsub(/%Y/, strftime("%Y"), p)
    if (p ~ /%z/) gsub(/%z/, strftime("%z"), p)
    if (p ~ /%Z/) gsub(/%Z/, strftime("%Z"), p)

    # %_ : prompt message
    if (p ~ /%_/)
        gsub(/%_/, showTranslationsOf(Option["hl"]), p)

    # %l : host language
    if (p ~ /%l/)
        gsub(/%l/, getDisplay(Option["hl"]), p)

    # %L : host language (English name)
    if (p ~ /%L/)
        gsub(/%L/, getName(Option["hl"]), p)

    # %s : source languages, separated by "+"
    # 's' is the format-control character for string

    # %S : source languages (English names), seperated by "+"
    if (p ~ /%S/) {
        temp = getName(Option["sls"][1])
        for (i = 2; i <= length(Option["sls"]); i++)
            temp = temp "+" getName(Option["sls"][i])
        gsub(/%S/, temp, p)
    }

    # TODO: source languages separated by "," and "/"

    # %t : target languages, separated by "+"
    if (p ~ /%t/) {
        temp = getDisplay(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "+" getDisplay(Option["tl"][i])
        gsub(/%t/, temp, p)
    }

    # %T : target languages (English names), separated by "+"
    if (p ~ /%T/) {
        temp = getName(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "+" getName(Option["tl"][i])
        gsub(/%T/, temp, p)
    }

    # %, : target languages, separated by ","
    if (p ~ /%,/) {
        temp = getDisplay(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "," getDisplay(Option["tl"][i])
        gsub(/%,/, temp, p)
    }

    # %< : target languages (English names), separated by ","
    if (p ~ /%</) {
        temp = getName(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "," getName(Option["tl"][i])
        gsub(/%</, temp, p)
    }

    # %/ : target languages, separated by "/"
    if (p ~ /%\//) {
        temp = getDisplay(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "/" getDisplay(Option["tl"][i])
        gsub(/%\//, temp, p)
    }

    # %? : target languages (English names), separated by "/"
    if (p ~ /%\?/) {
        temp = getName(Option["tl"][1])
        for (i = 2; i <= length(Option["tl"]); i++)
            temp = temp "/" getName(Option["tl"][i])
        gsub(/%\?/, temp, p)
    }

    # %s : source languages, separated by "+"
    temp = getDisplay(Option["sls"][1])
    for (i = 2; i <= length(Option["sls"]); i++)
        temp = temp "+" getDisplay(Option["sls"][i])
    printf(prettify("prompt", p), temp) > STDERR
}

# REPL.
function repl(line,    command, group, name, i, value, words) {
    split(line, words, " ")
    command = words[1]

    if (command ~ /^:(q|quit)$/) {
        exit
    } else if (command ~ /^:set$/) {
        name = words[2]
        value = words[3]
        Option[name] = value
    } else if (command ~ /^:show$/) {
        name = words[2]
        print prettify("welcome-submessage", toString(Option[name], 1, 0, 1))
    } else if (command ~ /^:swap$/) {
        tl = Option["tl"][1]
        Option["tl"][1] = Option["sls"][1]
        Option["sls"][1] = tl
    } else if (command ~ /^:engine$/) {
        value = words[2]
        Option["engine"] = value
        initHttpService()
    } else {
        match(command, /^[{(\[]?((@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?\+)*(@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?)?)?(:|=)((@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?\+)*(@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]][[:alpha:]]?[[:alpha:]]?)?)?)[})\]]?$/, group)
        if (RSTART) {
            if (group[1]) {
                split(group[1], Option["sls"], "+")
                Option["sl"] = Option["sls"][1]
            }
            if (group[7]) split(group[7], Option["tl"], "+")
            line = words[2]
            for (i = 3; i <= length(words); i++)
                line = line " " words[i]
        }
        if (line) {
            translates(line)

            # Interactive verbose mode: newline after each translation
            if (Option["verbose"]) printf RS
        }
    }

    prompt()
}


Added additional comments

Added additional comments

#
# generate_all
#
# Read three input data files and output LED segment patterns in code form that
#  is included in the source stream for compliation
#
# file1 format is "hexnum chars" where hexnum = hex entry index, char = "on" led segmemts
# file2 consists a index and a text string
# file3 is a template file for the output of the text strings
#
# file1 converts raw led segment letters to a translated hex number
# which is stored in an array with the characters hex number being the index
#
# file1:
#   0x30    abcdef
#   0x31    bc
#   0x32    abdeg
#   ... repeats for 127 chars total
#
# file2:
#
#    <41>  SEt,_
#    <42>  bEE,P
#
# Where <41> is the pattern used for matching in the output template file.
#  See the comments in the file "text_strings.txt" for explaination of the
#   special codes used to generate different character attributes
#
# file3:
#
#  #if DIGIT_3_FLIP
#      <4F1>
#      <4F2>
#
# The template file has <4F1> replaced with the hex code for string <41> with the character rotated
# (flipped) 180 degrees. In other locations, you will see the index markers:
#
#  #else
#      <4N1>
#      <4N2>
#
# Where the "N" character in the marker means do not flip or rotate the character pattern
# This is only needed in the third digit position due to lazy hardware engineers.
#
# The output from this GAW program thus becomes:
#
#  #if DIGIT_3_FLIP
#      0x92,0x86,0xB8,0xFF,       // SEt_
#      0x83,0x86,0xB0,0x8C,       // bEEP
#
# and lower in the listing:
#
#  #else
#      0x92,0x86,0x87,0xFF,       // SEt
#      0x83,0x86,0x86,0x8C,       // bEEP
#
# Note the difference in the value of the third hex number, this is
# the "flipped" LED segment pattern
#
BEGIN {

	while (getline <"segTable/segment_list.txt" > 0){

    if (match($0,/^#/)) # skip comment line
      continue

    if ( $2 == ";" ) {
      ledValueNorm[ hexToString($1 "") ] = "0xFF"
      ledValueFlip[ hexToString($1 "") ] = "0xFF"
    }
    if ( $2 ~ /[a-g]+/ ) {
      val  = 0;
      for ( i = 1; i <= length($2); i++) {
          c = substr($2,i,1)
          if ( c == "a" ) val += 1
          if ( c == "b" ) val += 2
          if ( c == "c" ) val += 4
          if ( c == "d" ) val += 8
          if ( c == "e" ) val += 16
          if ( c == "f" ) val += 32
          if ( c == "g" ) val += 64
          if ( c == "h" ) val += 128
      }
      s = ""
      if ( val >= 128 ){ s = s "1"; val -= 128 } else { s = s "0"}
      if ( val >=  64 ){ s = s "1"; val -=  64 } else { s = s "0"}
      if ( val >=  32 ){ s = s "1"; val -=  32 } else { s = s "0"}
      if ( val >=  16 ){ s = s "1"; val -=  16 } else { s = s "0"}
      if ( val >=   8 ){ s = s "1"; val -=   8 } else { s = s "0"}
      if ( val >=   4 ){ s = s "1"; val -=   4 } else { s = s "0"}
      if ( val >=   2 ){ s = s "1"; val -=   2 } else { s = s "0"}
      if ( val >=   1 ){ s = s "1"; val -=   1 } else { s = s "0"}

    	b01 = substr(s,8,1)         # get each bit in order
    	b02 = substr(s,7,1)
    	b04 = substr(s,6,1)
    	b08 = substr(s,5,1)
    	b10 = substr(s,4,1)
    	b20 = substr(s,3,1)
    	b40 = substr(s,2,1)
    	b80 = substr(s,1,1)
    	#
    	# the bit reorder is here:
      #
      # inverted logic here!
      #
      val = 0
      if ( b80 == "0" ){ val += 128 }
      if ( b40 == "0" ){ val +=  64 }
      if ( b20 == "0" ){ val +=  32 }
      if ( b10 == "0" ){ val +=  16 }
      if ( b08 == "0" ){ val +=   8 }
      if ( b04 == "0" ){ val +=   4 }
      if ( b02 == "0" ){ val +=   2 }
      if ( b01 == "0" ){ val +=   1 }
      ledValueNorm[ hexToString($1 "") ] = sprintf("0x%02X",val)
      #
      # inverted logic here!
      #
      val = 0
      if ( b80 == "0" ){ val += 128 }
      if ( b40 == "0" ){ val +=  64 }
      if ( b04 == "0" ){ val +=  32 }
      if ( b02 == "0" ){ val +=  16 }
      if ( b01 == "0" ){ val +=   8 }
      if ( b20 == "0" ){ val +=   4 }
      if ( b10 == "0" ){ val +=   2 }
      if ( b08 == "0" ){ val +=   1 }
      ledValueFlip[ hexToString($1 "") ] = sprintf("0x%02X",val)
      }
  } # end of file 1

	while (getline < "segTable/text_strings.txt" > 0) {

    if (match($0,/^#/)) # skip comment line
      continue

      if (NF == 2) {
        if ( match($1,/[0-9]+/) )
          text_string[substr($1,RSTART,RLENGTH)] = $2
    }
  } # end file text_strings.txt

  printf("// ----------------------------------------------------------------\n")
  printf("// ----------------------------------------------------------------\n")
  printf("// ------    This file was generated by the make process     ------\n")
  printf("// ------ Do not edit this file as your changes will be lost ------\n")
  printf("// ------     with the next invocation of \"make led\"         ------\n")
  printf("// ----------------------------------------------------------------\n")
  printf("// ----------------------------------------------------------------\n")

	while (getline < "segTable/codeTemplate.txt" > 0) {

    if (match($1,/<[234][NF][0-9]+>/)) {
      sIndex = $1
      gsub(/[<>]/,"",sIndex)
      gsub(/[NF]/,"",sIndex)
      orientation = substr($1,3,1)
      gen_string = text_string[sIndex]

      # handle decimal point in text string
      decimal_loc = index(gen_string,".")
      if ( decimal_loc ){
        # remove actual decimal from text
        decimal_loc--
        gsub(/\./,"",gen_string)
      }

      # handle flip character escaped code
      flip_loc = index(gen_string,",")
      if ( flip_loc ){
        # remove escape code from text
        flip_loc--
        gsub(/,/,"",gen_string)
      }

      rc = "" # start with empty string
      # now generate each character
      for (i =1; i <= length(gen_string); i++) {
        ci = substr(gen_string,i,1)

        if ( orientation == "F" && i == flip_loc )
          tc = ledValueFlip[ci]
         else
          tc = ledValueNorm[ci]

        # handle decimal point if at that character
        if (i == decimal_loc){
          tc = add_decimal(tc)
        }

      # now concatenate everything into one string each pass through
      rc = rc tc ","
      } #end for of each character

      # now replace placeholder with text
      gsub(/<[0-9][NF][0-9]+>/,rc)
      } # end if $1 matches pattern <2 3 or 4>

    if (match($1,/<[1][NF][0-9]+>/)) {
      # here when we have single "0-9" substitution
      sIndex = substr($1,4,1)
      orientation = substr($1,3,1)
      gen_string = text_string[sIndex]
      if ( orientation == "N" )
        rc = ledValueNorm[sIndex] ","
      else
        rc = ledValueFlip[sIndex] ","
      gsub(/<[0-9][NF][0-9]+>/,rc)
    }

    printf($0 "\n") # the the source, possibly modified
  } # end file text_strings.txt

} # end of pgm

#
# -------------------------------------------------------------------
#
function add_decimal(hexchars)
{
    # hexchars = "0x4F"
    msb = substr(hexchars,3,1)
    lsb = substr(hexchars,4,1)
    val = 0
    if ( msb == "F" ){ val += 240 }
    if ( msb == "E" ){ val += 224 }
    if ( msb == "D" ){ val += 208 }
    if ( msb == "C" ){ val += 192 }
    if ( msb == "B" ){ val += 176 }
    if ( msb == "A" ){ val += 160 }
    if ( msb == "9" ){ val += 144 }
    if ( msb == "8" ){ val += 128 }
    if ( msb == "7" ){ val += 112 }
    if ( msb == "6" ){ val +=  96 }
    if ( msb == "5" ){ val +=  80 }
    if ( msb == "4" ){ val +=  64 }
    if ( msb == "3" ){ val +=  48 }
    if ( msb == "2" ){ val +=  32 }
    if ( msb == "1" ){ val +=  16 }
    if ( lsb == "F" ){ val +=  15 }
    if ( lsb == "E" ){ val +=  14 }
    if ( lsb == "D" ){ val +=  13 }
    if ( lsb == "C" ){ val +=  12 }
    if ( lsb == "B" ){ val +=  11 }
    if ( lsb == "A" ){ val +=  10 }
    if ( lsb == "9" ){ val +=   9 }
    if ( lsb == "8" ){ val +=   8 }
    if ( lsb == "7" ){ val +=   7 }
    if ( lsb == "6" ){ val +=   6 }
    if ( lsb == "5" ){ val +=   5 }
    if ( lsb == "4" ){ val +=   4 }
    if ( lsb == "3" ){ val +=   3 }
    if ( lsb == "2" ){ val +=   2 }
    if ( lsb == "1" ){ val +=   1 }
    if (val >= 128) val -= 128
    return sprintf("0x%02X",val)
}
#
# -------------------------------------------------------------------
#
function hexToString(hexchars)
{
    # hexchars = "0x4F"
    msb = substr(hexchars,3,1)
    lsb = substr(hexchars,4,1)
    val = 0
    if ( msb == "F" ){ val += 240 }
    if ( msb == "E" ){ val += 224 }
    if ( msb == "D" ){ val += 208 }
    if ( msb == "C" ){ val += 192 }
    if ( msb == "B" ){ val += 176 }
    if ( msb == "A" ){ val += 160 }
    if ( msb == "9" ){ val += 144 }
    if ( msb == "8" ){ val += 128 }
    if ( msb == "7" ){ val += 112 }
    if ( msb == "6" ){ val +=  96 }
    if ( msb == "5" ){ val +=  80 }
    if ( msb == "4" ){ val +=  64 }
    if ( msb == "3" ){ val +=  48 }
    if ( msb == "2" ){ val +=  32 }
    if ( msb == "1" ){ val +=  16 }
    if ( lsb == "F" ){ val +=  15 }
    if ( lsb == "E" ){ val +=  14 }
    if ( lsb == "D" ){ val +=  13 }
    if ( lsb == "C" ){ val +=  12 }
    if ( lsb == "B" ){ val +=  11 }
    if ( lsb == "A" ){ val +=  10 }
    if ( lsb == "9" ){ val +=   9 }
    if ( lsb == "8" ){ val +=   8 }
    if ( lsb == "7" ){ val +=   7 }
    if ( lsb == "6" ){ val +=   6 }
    if ( lsb == "5" ){ val +=   5 }
    if ( lsb == "4" ){ val +=   4 }
    if ( lsb == "3" ){ val +=   3 }
    if ( lsb == "2" ){ val +=   2 }
    if ( lsb == "1" ){ val +=   1 }
    return sprintf("%c",val)
}

#
# generate_all
#
# - input two seperate data files and output transliterated characters
#
# file1 format is "hexnum chars" where hexnum = hex entry index, char = "on" led segmemts
# file2 consists a index and a text string
# file3 is a template file for the output of the text strings after translation
#  into an LED segment pattern.
#  This output is then included in the source stream for complilation
#
# file1 converts raw led segment letters to a translated hex number
# which is stored in an array with the characters hex number being the index
#
# file1:
#   0x30    abcdef
#   0x31    bc
#   0x32    abdeg
#   ... repeats for 127 chars total
#
# file2:
#
#    <41>  SEt,_
#    <42>  bEE,P
#
# Where <41> is the pattern used for matching in the output template file.
#
# file3:
#
#  #if DIGIT_3_FLIP
#      <4F1>
#      <4F2>
#
# This template has <4F1> replaced with the hex code for string <41> with the character rotated
# (flipped) 180 degrees. In other locations, you will see the index markers:
#
#  #else
#      <4N1>
#      <4N2>
#
# Where the "N" character in the marker means do not flip or rotate the character pattern
# This is only needed in the third digit position due to lazy hardware engineers.
#
# The output from this GAW program thus becomes:
#
#  #if DIGIT_3_FLIP
#      0x92,0x86,0xB8,0xFF,       // SEt_
#      0x83,0x86,0xB0,0x8C,       // bEEP
#
# and lower in the listing:
#
#  #else
#      0x92,0x86,0x87,0xFF,       // SEt
#      0x83,0x86,0x86,0x8C,       // bEEP
#
# Note the difference in the value of the third hex number, this is
# the "flipped" LED segment pattern
#
BEGIN {

	while (getline <"segTable/segment_list.txt" > 0){

    if (match($0,/^#/)) # skip comment line
      continue

    if ( $2 == ";" ) {
      ledValueNorm[ hexToString($1 "") ] = "0xFF"
      ledValueFlip[ hexToString($1 "") ] = "0xFF"
    }
    if ( $2 ~ /[a-g]+/ ) {
      val  = 0;
      for ( i = 1; i <= length($2); i++) {
          c = substr($2,i,1)
          if ( c == "a" ) val += 1
          if ( c == "b" ) val += 2
          if ( c == "c" ) val += 4
          if ( c == "d" ) val += 8
          if ( c == "e" ) val += 16
          if ( c == "f" ) val += 32
          if ( c == "g" ) val += 64
          if ( c == "h" ) val += 128
      }
      s = ""
      if ( val >= 128 ){ s = s "1"; val -= 128 } else { s = s "0"}
      if ( val >=  64 ){ s = s "1"; val -=  64 } else { s = s "0"}
      if ( val >=  32 ){ s = s "1"; val -=  32 } else { s = s "0"}
      if ( val >=  16 ){ s = s "1"; val -=  16 } else { s = s "0"}
      if ( val >=   8 ){ s = s "1"; val -=   8 } else { s = s "0"}
      if ( val >=   4 ){ s = s "1"; val -=   4 } else { s = s "0"}
      if ( val >=   2 ){ s = s "1"; val -=   2 } else { s = s "0"}
      if ( val >=   1 ){ s = s "1"; val -=   1 } else { s = s "0"}

    	b01 = substr(s,8,1)         # get each bit in order
    	b02 = substr(s,7,1)
    	b04 = substr(s,6,1)
    	b08 = substr(s,5,1)
    	b10 = substr(s,4,1)
    	b20 = substr(s,3,1)
    	b40 = substr(s,2,1)
    	b80 = substr(s,1,1)
    	#
    	# the bit reorder is here:
      #
      # inverted logic here!
      #
      val = 0
      if ( b80 == "0" ){ val += 128 }
      if ( b40 == "0" ){ val +=  64 }
      if ( b20 == "0" ){ val +=  32 }
      if ( b10 == "0" ){ val +=  16 }
      if ( b08 == "0" ){ val +=   8 }
      if ( b04 == "0" ){ val +=   4 }
      if ( b02 == "0" ){ val +=   2 }
      if ( b01 == "0" ){ val +=   1 }
      ledValueNorm[ hexToString($1 "") ] = sprintf("0x%02X",val)
      #
      # inverted logic here!
      #
      val = 0
      if ( b80 == "0" ){ val += 128 }
      if ( b40 == "0" ){ val +=  64 }
      if ( b04 == "0" ){ val +=  32 }
      if ( b02 == "0" ){ val +=  16 }
      if ( b01 == "0" ){ val +=   8 }
      if ( b20 == "0" ){ val +=   4 }
      if ( b10 == "0" ){ val +=   2 }
      if ( b08 == "0" ){ val +=   1 }
      ledValueFlip[ hexToString($1 "") ] = sprintf("0x%02X",val)
      }
  } # end of file 1

	while (getline < "segTable/text_strings.txt" > 0) {

    if (match($0,/^#/)) # skip comment line
      continue

      if (NF == 2) {
        if ( match($1,/[0-9]+/) )
          text_string[substr($1,RSTART,RLENGTH)] = $2
    }
  } # end file text_strings.txt

  printf("// ----------------------------------------------------------------\n")
  printf("// ----------------------------------------------------------------\n")
  printf("// ------    This file was generated by the make process     ------\n")
  printf("// ------ Do not edit this file as your changes will be lost ------\n")
  printf("// ------     with the next invocation of \"make led\"         ------\n")
  printf("// ----------------------------------------------------------------\n")
  printf("// ----------------------------------------------------------------\n")

	while (getline < "segTable/codeTemplate.txt" > 0) {

    if (match($1,/<[234][NF][0-9]+>/)) {
      sIndex = $1
      gsub(/[<>]/,"",sIndex)
      gsub(/[NF]/,"",sIndex)
      orientation = substr($1,3,1)
      gen_string = text_string[sIndex]

      # handle decimal point in text string
      decimal_loc = index(gen_string,".")
      if ( decimal_loc ){
        # remove actual decimal from text
        decimal_loc--
        gsub(/\./,"",gen_string)
      }

      # handle flip character escaped code
      flip_loc = index(gen_string,",")
      if ( flip_loc ){
        # remove escape code from text
        flip_loc--
        gsub(/,/,"",gen_string)
      }

      rc = "" # start with empty string
      # now generate each character
      for (i =1; i <= length(gen_string); i++) {
        ci = substr(gen_string,i,1)

        if ( orientation == "F" && i == flip_loc )
          tc = ledValueFlip[ci]
         else
          tc = ledValueNorm[ci]

        # handle decimal point if at that character
        if (i == decimal_loc){
          tc = add_decimal(tc)
        }

      # now concatenate everything into one string each pass through
      rc = rc tc ","
      } #end for of each character

      # now replace placeholder with text
      gsub(/<[0-9][NF][0-9]+>/,rc)
      } # end if $1 matches pattern <2 3 or 4>

    if (match($1,/<[1][NF][0-9]+>/)) {
      # here when we have single "0-9" substitution
      sIndex = substr($1,4,1)
      orientation = substr($1,3,1)
      gen_string = text_string[sIndex]
      if ( orientation == "N" )
        rc = ledValueNorm[sIndex] ","
      else
        rc = ledValueFlip[sIndex] ","
      gsub(/<[0-9][NF][0-9]+>/,rc)
    }

    printf($0 "\n") # the the source, possibly modified
  } # end file text_strings.txt

} # end of pgm

#
# -------------------------------------------------------------------
#
function add_decimal(hexchars)
{
    # hexchars = "0x4F"
    msb = substr(hexchars,3,1)
    lsb = substr(hexchars,4,1)
    val = 0
    if ( msb == "F" ){ val += 240 }
    if ( msb == "E" ){ val += 224 }
    if ( msb == "D" ){ val += 208 }
    if ( msb == "C" ){ val += 192 }
    if ( msb == "B" ){ val += 176 }
    if ( msb == "A" ){ val += 160 }
    if ( msb == "9" ){ val += 144 }
    if ( msb == "8" ){ val += 128 }
    if ( msb == "7" ){ val += 112 }
    if ( msb == "6" ){ val +=  96 }
    if ( msb == "5" ){ val +=  80 }
    if ( msb == "4" ){ val +=  64 }
    if ( msb == "3" ){ val +=  48 }
    if ( msb == "2" ){ val +=  32 }
    if ( msb == "1" ){ val +=  16 }
    if ( lsb == "F" ){ val +=  15 }
    if ( lsb == "E" ){ val +=  14 }
    if ( lsb == "D" ){ val +=  13 }
    if ( lsb == "C" ){ val +=  12 }
    if ( lsb == "B" ){ val +=  11 }
    if ( lsb == "A" ){ val +=  10 }
    if ( lsb == "9" ){ val +=   9 }
    if ( lsb == "8" ){ val +=   8 }
    if ( lsb == "7" ){ val +=   7 }
    if ( lsb == "6" ){ val +=   6 }
    if ( lsb == "5" ){ val +=   5 }
    if ( lsb == "4" ){ val +=   4 }
    if ( lsb == "3" ){ val +=   3 }
    if ( lsb == "2" ){ val +=   2 }
    if ( lsb == "1" ){ val +=   1 }
    if (val >= 128) val -= 128
    return sprintf("0x%02X",val)
}
#
# -------------------------------------------------------------------
#
function hexToString(hexchars)
{
    # hexchars = "0x4F"
    msb = substr(hexchars,3,1)
    lsb = substr(hexchars,4,1)
    val = 0
    if ( msb == "F" ){ val += 240 }
    if ( msb == "E" ){ val += 224 }
    if ( msb == "D" ){ val += 208 }
    if ( msb == "C" ){ val += 192 }
    if ( msb == "B" ){ val += 176 }
    if ( msb == "A" ){ val += 160 }
    if ( msb == "9" ){ val += 144 }
    if ( msb == "8" ){ val += 128 }
    if ( msb == "7" ){ val += 112 }
    if ( msb == "6" ){ val +=  96 }
    if ( msb == "5" ){ val +=  80 }
    if ( msb == "4" ){ val +=  64 }
    if ( msb == "3" ){ val +=  48 }
    if ( msb == "2" ){ val +=  32 }
    if ( msb == "1" ){ val +=  16 }
    if ( lsb == "F" ){ val +=  15 }
    if ( lsb == "E" ){ val +=  14 }
    if ( lsb == "D" ){ val +=  13 }
    if ( lsb == "C" ){ val +=  12 }
    if ( lsb == "B" ){ val +=  11 }
    if ( lsb == "A" ){ val +=  10 }
    if ( lsb == "9" ){ val +=   9 }
    if ( lsb == "8" ){ val +=   8 }
    if ( lsb == "7" ){ val +=   7 }
    if ( lsb == "6" ){ val +=   6 }
    if ( lsb == "5" ){ val +=   5 }
    if ( lsb == "4" ){ val +=   4 }
    if ( lsb == "3" ){ val +=   3 }
    if ( lsb == "2" ){ val +=   2 }
    if ( lsb == "1" ){ val +=   1 }
    return sprintf("%c",val)
}