Remove extra spaces

Remove extra spaces

#!/usr/bin/awk -f
BEGIN {
    FS = "\t";

    URN           = "urn:swn:";

    LABEL         = "<http://www.w3.org/2000/01/rdf-schema#label>";
    TYPE          = "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>";

    CONCEPT       = "<http://www.w3.org/2004/02/skos/core#Concept>";
    LEXICALSENSE  = "<http://lemon-model.net/lemon#LexicalSense>";
    WORD          = "<http://lemon-model.net/lemon#Word>";
    FORM          = "<http://lemon-model.net/lemon#Form>";

    WRITTENREP    = "<http://lemon-model.net/lemon#writtenRep>";
    CANONICALFORM = "<http://lemon-model.net/lemon#canonicalForm>";
    BROADER       = "<http://lemon-model.net/lemon#broader>";
    NARROWER      = "<http://lemon-model.net/lemon#narrower>";
    SENSE         = "<http://lemon-model.net/lemon#sense>";
    ISSENSEOF     = "<http://lemon-model.net/lemon#isSenseOf>";
    REFERENCE     = "<http://lemon-model.net/lemon#reference>";
    ISREFERENCEOF = "<http://lemon-model.net/lemon#isReferenceOf>";
}
{
    nsenses = split($3, senses, ", ");
    nisas   = split($5, isas,   ", ");

    if (nsenses == 0 || nisas == 0) next;

    print "<" URN "c" $1 ">", TYPE,  CONCEPT,            ".";
    print "<" URN "c" $1 ">", LABEL, "\"synset" $1 "\"", ".";

    for (sense_id in senses) {
        sense = senses[sense_id];

        sub(":.*$", "", sense);

        if (!(sense in sindex)) {
            sindex[sense] = scount++;

            word = sense;
            gsub("_", " ",  word);
            sub("#.*$", "", word);

            if (!(word in windex)) {
                windex[word] = wcount++;

                print "<" URN "w" windex[word] ">", TYPE,          WORD,                         ".";
                print "<" URN "w" windex[word] ">", LABEL,         "\"" word "\"",               ".";
                print "<" URN "f" windex[word] ">", TYPE,          FORM,                         ".";
                print "<" URN "f" windex[word] ">", LABEL,         "\"" word "\"",               ".";
                print "<" URN "f" windex[word] ">", WRITTENREP,    "\"" word "\"",               ".";
                print "<" URN "w" windex[word] ">", CANONICALFORM, "<" URN "f" windex[word] ">", ".";
            }

            print "<" URN "s" sindex[sense] ">", TYPE,          LEXICALSENSE,                  ".";
            print "<" URN "s" sindex[sense] ">", LABEL,         "\"" sense "\"",               ".";
            print "<" URN "s" sindex[sense] ">", ISSENSEOF,     "<" URN "w" windex[word] ">",  ".";
            print "<" URN "w" windex[word]  ">", SENSE,         "<" URN "s" sindex[sense] ">", ".";
            print "<" URN "s" sindex[sense] ">", REFERENCE,     "<" URN "c" $1 ">",            ".";
            print "<" URN "c" $1 ">",            ISREFERENCEOF, "<" URN "s" sindex[sense] ">", ".";
        }

        for (isa_id in isas) {
            isa = isas[isa_id];

            sub(":.*$", "", isa);

            if (!(isa in sindex)) {
                sindex[isa] = scount++;

                word = isa;
                gsub("_", " ",  word);
                sub("#.*$", "", word);

                if (!(word in windex)) {
                    windex[word] = wcount++;

                    print "<" URN "w" windex[word] ">", TYPE,          WORD,                         ".";
                    print "<" URN "w" windex[word] ">", LABEL,         "\"" word "\"",               ".";
                    print "<" URN "f" windex[word] ">", TYPE,          FORM,                         ".";
                    print "<" URN "f" windex[word] ">", LABEL,         "\"" word "\"",               ".";
                    print "<" URN "f" windex[word] ">", WRITTENREP,    "\"" word "\"",               ".";
                    print "<" URN "w" windex[word] ">", CANONICALFORM, "<" URN "f" windex[word] ">", ".";
                }

                print "<" URN "s" sindex[isa] ">",  TYPE,      LEXICALSENSE,                 ".";
                print "<" URN "s" sindex[isa] ">",  LABEL,     "\"" isa "\"",                ".";
                print "<" URN "s" sindex[isa] ">",  ISSENSEOF, "<" URN "w" windex[word] ">", ".";
                print "<" URN "w" windex[word] ">", SENSE,     "<" URN "s" sindex[isa] ">",  ".";
            }

            print "<" URN "s" sindex[sense] ">", BROADER,  "<" URN "s" sindex[isa] ">",   ".";
            print "<" URN "s" sindex[isa] ">",   NARROWER, "<" URN "s" sindex[sense] ">", ".";
        }
    }
}


Better error formatting, capture warnings too

{
    print
    fflush(stdout)
}

/[0-9]+: (error|warning):/ {
    errors = errors $0 "\n"
}

/(TEST|BUILD) FAILED/ {
    if (length(errors) > 0) {
        print "\n*** All errors:\n" errors
    }

    fflush(stdout)

    # SYS_SOFTWARE
    exit 70
}

{
    print
    fflush(stdout)
}

/[0-9]+: error:/ {
    errors = errors $0 "\n"
}

/(TEST|BUILD) FAILED/ {
    print "\n" errors
    fflush(stdout)

    # SYS_SOFTWARE
    exit 70
}


properly treat /*dev-only-stop*/ marker

properly treat /*dev-only-stop*/ marker

# awk program to remove sections of a text file
# beginning  with   /*dev-only-start*/
# and ending with   /*dev-only-stop*/
# and further omitting single lines containing /*dev-only*/

/\/\*dev-only-start\*\// {
  print "// dev-only: " $0;
  getline;
  while (index($0, "/*dev-only-stop*/") == 0) {
      print "// dev-only: " $0;
      getline;
  }
  print "// dev-only: " $0;
  getline;
}

/\/\*dev-only\*\// {
  print "// dev-only: " $0;
  getline;
}

{ print }

# awk program to remove sections of a text file
# beginning  with   /*dev-only-start*/
# and ending with   /*dev-only-stop*/
# and further omitting single lines containing /*dev-only*/

/\/\*dev-only-start\*\// {
  print "// dev-only: " $0;
  getline;
  while (index($0, "/*dev-only-stop*/") == 0) {
      getline;
      print "// dev-only: " $0;
  }
}

/\/\*dev-only\*\// {
  print "// dev-only: " $0;
  getline;
}

{ print }


translate.awk: update disclaimer

translate.awk: update disclaimer

#!/usr/bin/gawk -f

# This is free and unencumbered software released into the public domain.
#
# This software is provided for the purpose of reasonable personal use of
# the Google Translate service, i.e., for those who prefer command line to
# web interface. For other purposes, please refer to the official Google
# Translate API <https://developers.google.com/translate/>.
#
# By using this software, you ("the user") are aware that:
#
# 1. Google Translate is a proprietary service provided and owned by
# Google Inc.
#
# 2. Translate Shell is NOT a Google product. Neither this software nor
# its author is affiliated with Google Inc.
#
# 3. The software is provided "AS IS", without warranty of any kind,
# express or implied, including but not limited to the warranties of
# merchantability, fitness for a particular purpose and noninfringement. In
# no event shall the authors be liable for any claim, damages or other
# liability, whether in an action of contract, tort or otherwise, arising
# from, out of or in connection with the software or the use or other
# dealings in the software.

@include "metainfo"

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

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

@include "include/Main"

#!/usr/bin/gawk -f

# This is free and unencumbered software released into the
# public domain.
#
# This software is provided for the purpose of personal, reasonable
# and convenient human use of the Google Translate Service, i.e.,
# only for those who feel that their terminal is more accessible
# than a web browser. For other purposes, please use the official
# Google Translate API <https://developers.google.com/translate/>.
#
# By using this software, you ("the user") agree that:
#
# 1. Neither this software nor its author is affiliated with
# Google Inc. ("Google").
#
# 2. By using this software, the user is de facto using web
# services provided by Google, therefore they are obliged to
# follow the Google Terms of Service.
#
# 3. This software is provided "as is". The user of this software
# shall be fully liable for any possible infringement of, including
# but not limited to, the Google Terms of Service; per contra,
# the user must be aware that their data might be collected by
# Google, therefore they shall be liable for their own privacy
# concern, including but not limited to, possible disclosure of
# personal information. See the (un)LICENSE file for more details.

@include "metainfo"

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

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

@include "include/Main"


Add placeholder for back field.

Add placeholder for back field.

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

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

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

{
  # add a loop to add line only if ending year is gt or eq to contract year
  current_year = 2014
  end_year = 0
  incontract = 0
  test_year = ""
  if ($7 == "") {
    test_year = $3
  } else {
    test_year = $7
  }
  if (length($4) > 3) {
    end_year = substr($4,length($4)-3,4)
  }
  #printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", $1,$2,$3,$4,$7,end_year,test_year
  if (end_year >= test_year) {
    if ((end_year < current_year) || ((end_year >= current_year) && (incl_cur == 1))) {
      incontract = 1
    }
  }

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

END {
  s[0] = "expected"
  s[1] = "exists"
  s[2] = "manifest"
  s[3] = "wanted"
  s[4] = "testing"
  s[5] = "notReady"
  s[6] = "ready"
  s[7] = "crawling"
  s[8] = "frozen"
  s[9] = "ingNotReady"
  s[10] = "finished"
  s[11] = "down"
  s[12] = "superseded"
  s[13] = "zapped"
  s[14] = "doNotProcess"
  sn = 15

  sc[0] = "expe"
  sc[1] = "exis"
  sc[2] = "mani"
  sc[3] = "want"
  sc[4] = "test"
  sc[5] = "notR"
  sc[6] = "read"
  sc[7] = "craw"
  sc[8] = "froz"
  sc[9] = "ingN"
  sc[10] = "fini"
  sc[11] = "down"
  sc[12] = "supe"
  sc[13] = "zapp"
  sc[14] = "doNP"
  scn = 15

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

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

  printf "\n"
}

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

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

{
  # add a loop to add line only if ending year is gt or eq to contract year
  current_year = 2014
  end_year = 0
  incontract = 0
  test_year = ""
  if ($7 == "") {
    test_year = $3
  } else {
    test_year = $7
  }
  if (length($4) > 3) {
    end_year = substr($4,length($4)-3,4)
  }
  #printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", $1,$2,$3,$4,$7,end_year,test_year
  if (end_year >= test_year) {
    if ((end_year < current_year) || ((end_year >= current_year) && (incl_cur == 1))) {
      incontract = 1
    }
  }

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

END {
  s[0] = "expected"
  s[1] = "exists"
  s[2] = "manifest"
  s[3] = "wanted"
  s[4] = "testing"
  s[5] = "notReady"
  s[6] = "ready"
  s[7] = "crawling"
  s[8] = "frozen"
  s[9] = "ingNotReady"
  s[10] = "finished"
  s[11] = "down"
  s[12] = "superseded"
  s[13] = "zapped"
  s[14] = "doNotProcess"
  sn = 15

  sc[0] = "expe"
  sc[1] = "exis"
  sc[2] = "mani"
  sc[3] = "want"
  sc[4] = "test"
  sc[5] = "notR"
  sc[6] = "read"
  sc[7] = "craw"
  sc[8] = "froz"
  sc[9] = "ingN"
  sc[10] = "fini"
  sc[11] = "down"
  sc[12] = "supe"
  sc[13] = "zapp"
  sc[14] = "doNP"
  scn = 15

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

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

  printf "\n"
}


Revise "Maigret" title to clarify timeframe

# Broduce a raw data spreadsheet of fields in BritBox Catalog --  apple_catalogue_feed.xml

# INVOCATION
#   awk -v ERROR_FILE=$ERROR_FILE -f getBBoxCatalogFrom-sitemap.awk $SITEMAP_FILE >$CATALOG_SPREADSHEET

# Field numbers
#     1 Sortkey       2 Title           3 Seasons          4 Episodes      5 Duration     6 Year
#     7 Rating        8 Description     9 Content Type    10 Content ID   11 Entity ID   12 Genre
#    13 Show Type    14 Date Type      15 Original Date   16 Show ID      16 Season ID   13 Sn #   14 Ep #

BEGIN {
    # Print header
    printf ("Sortkey\tTitle\tSeasons\tEpisodes\tDuration\tYear\tRating\tDescription\t")
    printf ("Content Type\tContent ID\tEntity ID\tGenre\tShow Type\tDate Type\tOriginal Date\t")
    printf ("Show ID\tSeason ID\tSn #\tEp #\n")
}

# Don't process credits
/<credit role=/,/<\/credit>/ {
    next
}

# Don't use Canadian ratings
/<rating systemCode="ca-tv">/ {
    next
}

# Don't use pubDate - it's too random to be useful
# <pubDate>2020-06-05T21:51:00Z</pubDate>
/<pubDate>/ {
    next
}

# Don't use "cover_artwork_horizontal"
# <artwork url="https://britbox-images-prod.s3-eu-west-1.amazonaws.com/3840x2160px/p05wv7gy.png" type="cover_artwork_horizontal" />
/<artwork url=.*type="cover_artwork_horizontal"/ {
    next
}

# Grab contentType & contentId
# <item contentType="tv_episode" contentId="p079sxm9">
/<item contentType="/ {
    split ($0,fld,"\"")
    contentType = fld[2]
    contentId = fld[4]
    # print "contentType = " contentType  > "/dev/stderr"
    # print "contentId = " contentId  > "/dev/stderr"
    # Make sure no fields will be carried over due to missing keys
    sortkey = ""
    title = ""
    EntityId = ""
    genre = ""
    rating = ""
    showType = ""
    duration = ""
    dateType = ""
    originalDate = ""
    showContentId = ""
    seasonContentId = ""
    seasonNumber = ""
    episodeNumber = ""
    description = ""
    # Generated fields
    year = ""
    # New fields that haven't been created yet
    numSeasons = 111
    numEpisodes = 222
}

# Grab title
# <title locale="en-US">Frequent Flyers</title>
/<title locale="en-US">/ {
    split ($0,fld,"[<>]")
    title = fld[3]
    # print "title = " title  > "/dev/stderr"
}

# Grab genre
# <genre>drama</genre>
/<genre>/ {
    split ($0,fld,"[<>]")
    genre = fld[3]
    # print "genre = " genre  > "/dev/stderr"
}

# Grab description
# <description>Set in the beautiful Yorkshire Dales, ...word.</description>
/<description>/ {
    split ($0,fld,"[<>]")
    description = fld[3]
    # print "description = " description  > "/dev/stderr"
}

# Grab rating
# <rating systemCode="us-tv">TV-PG</rating>
/<rating systemCode=/ {
    split ($0,fld,"[<>]")
    rating = fld[3]
    # print "rating = " rating  > "/dev/stderr"
}

# Grab type
# <type>series</type>
/<type>/ {
    split ($0,fld,"[<>]")
    showType = fld[3]
    # print "showType = " showType  > "/dev/stderr"
}

# Grab duration
# <duration>3000</duration>
/<duration>/ {
    split ($0,fld,"[<>]")
    duration = fld[3]
    # print "duration = " duration  > "/dev/stderr"
}

# Grab originalDate
# <originalAirDate>1978-03-25</originalAirDate>
# <originalPremiereDate>1978-01-08</originalPremiereDate>
# <originalReleaseDate>2017-12-25</originalReleaseDate>
/<original.*Date>/ {
    split ($0,fld,"[<>]")
    dateType = fld[2]
    sub (/original/,"",dateType)
    originalDate = fld[3]
    year = substr (originalDate,1,4)
    # print "dateType = " dateType  > "/dev/stderr"
    # print "originalDate = " originalDate  > "/dev/stderr"
    # print "year = " year  > "/dev/stderr"
}

# Grab showContentId
# <showContentId>b008yjd9</showContentId>
/<showContentId>/ {
    split ($0,fld,"[<>]")
    showContentId = fld[3]
    # print "showContentId = " showContentId  > "/dev/stderr"
}

# Grab seasonContentId
# <seasonContentId>p0318ps9</seasonContentId>
/<seasonContentId>/ {
    split ($0,fld,"[<>]")
    seasonContentId = fld[3]
    # print "seasonContentId = " seasonContentId  > "/dev/stderr"
}

# Grab seasonNumber
# <seasonNumber>1</seasonNumber>
/<seasonNumber>/ {
    split ($0,fld,"[<>]")
    seasonNumber = fld[3]
    # print "seasonNumber = " seasonNumber  > "/dev/stderr"
}

# Grab episodeNumber
# <episodeNumber>10</episodeNumber>
/<episodeNumber>/ {
    split ($0,fld,"[<>]")
    episodeNumber = fld[3]
    # print "episodeNumber = " episodeNumber  > "/dev/stderr"
}

# Grab EntityId from artwork
# <artwork url="https://us.britbox.com/isl/api/v1/dataservice/ResizeImage/$value?Format='jpg'&Quality=45&ImageId='176236'&EntityType='Item'&EntityId='16103'&Width=1920&Height=1080&ResizeAction='fit'" type="tile_artwork" />
/<artwork url=.*EntityId='/ {
    sub (/.*EntityId='/,"")
    sub (/&apos.*/,"")
    EntityId = "_" $0
    # print "EntityId = " EntityId  > "/dev/stderr"
    next
}

# Do any special end of item processing, then print raw data spreadsheet row
/<\/item>/ {
    # Add missing EntityId
    if (title == "Shallow Grave") {
        EntityId = "_23576"
        # print "==> EntityId = " EntityId  > "/dev/stderr"
    }

    # "Porridge" needs to be revised to avoid duplicate names
    if (title == "Porridge") {
        if (EntityId == "_9509") {
            revisedTitles += 1
            printf ("==> Changed title '%s' to 'Porridge (1974-1977)'\n", title) >> ERROR_FILE
            title = "Porridge (1974-1977)"
        } else if (EntityId == "_14747") {
            revisedTitles += 1
            printf ("==> Changed title '%s' to 'Porridge (2016-2017)'\n", title) >> ERROR_FILE
            title = "Porridge (2016-2017)"
        }
        # print "==> title = " title  > "/dev/stderr"
        # print "==> contentId = " contentId  > "/dev/stderr"
        # print "==> EntityId = " EntityId  > "/dev/stderr"
        # print "---"  > "/dev/stderr"
    }

    # "A Midsummer Night's Dream" needs to be revised to avoid duplicate names
    if (title == "A Midsummer Night's Dream") {
        if (EntityId == "_26179") {
            revisedTitles += 1
            printf ("==> Changed title '%s' to 'A Midsummer Night\'s Dream (1981)'\n", title) >> ERROR_FILE
            title = "A Midsummer Night's Dream (1981)"
        } else if (EntityId == "_15999") {
            revisedTitles += 1
            printf ("==> Changed title '%s' to 'A Midsummer Night\'s Dream (2016)'\n", title) >> ERROR_FILE
            title = "A Midsummer Night's Dream (2016)"
        }
        # print "==> title = " title  > "/dev/stderr"
        # print "==> EntityId = " EntityId  > "/dev/stderr"
    }

    # "Maigret" needs to be revised to clarify timeframe
    if (title ~ /^Maigret/ && contentType == "tv_show") {
        if (EntityId == "_15928") {
            revisedTitles += 1
            printf ("==> Changed title '%s' to 'Maigret (1992-1993)'\n", title) >> ERROR_FILE
            title = "Maigret (1992-1993)"
        } else if (EntityId == "_15974") {
            revisedTitles += 1
            printf ("==> Changed title '%s' to 'Maigret (2016–2017)'\n", title) >> ERROR_FILE
            title = "Maigret (2016–2017)"
        }
        # print "==> title = " title  > "/dev/stderr"
        # print "==> originalDate = " originalDate  > "/dev/stderr"
        # print "==> contentId = " contentId  > "/dev/stderr"
        # print "==> EntityId = " EntityId  > "/dev/stderr"
        # print "---"  > "/dev/stderr"
    }

    if (contentId == "p07gnw9f") {
        EntityId = "_23842"
        # print "==> EntityId = " EntityId  > "/dev/stderr"
    }

    if (contentType == "movie") {
        sortkey = sprintf ("%s (1) %s M%s", title, originalDate, EntityId)
    }

    if (contentType == "tv_show") {
        showTitle = title
        sortkey = sprintf ("%s (1) S%s", title, EntityId)
    }

    if (contentType == "tv_season") {
        sortkey = sprintf ("%s (2) S%02d", showTitle, seasonNumber)
    }

    if (contentType == "tv_episode") {
        sortkey = sprintf ("%s (2) S%02dE%03d %s", showTitle, seasonNumber, \
                episodeNumber, showContentId)
    }

    # Copied from printing header to make it easier to coordinate arranging fields
    # printf ("Sortkey\tTitle\tSeasons\tEpisodes\tDuration\tYear(s)\tRating\tDescription\t")
    # printf ("Content Type\tContent ID\tEntity ID\tGenre\tShow Type\tDate Type\tOriginal Date\t")
    # printf ("Show ID\tSeason ID\tSn #\tEp #\n")

    printf ("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", \
            sortkey, title, numSeasons, numEpisodes, duration, year, rating, description, \
            contentType, contentId, EntityId, genre, showType, dateType, originalDate, \
            showContentId, seasonContentId, seasonNumber, episodeNumber)
}

# <artwork url="https://us.britbox.com/isl/api/v1/dataservice/ResizeImage/$value?Format='jpg'&Quality=45&ImageId='176236'&EntityType='Item'&EntityId='16103'&Width=1920&Height=1080&ResizeAction='fit'" type="tile_artwork" />
# https://www.britbox.com/us/movie/300_Years_of_French_and_Saunders_16103
/<item contentType="movie"/,/<\/item>/ {
    # print
}

END {
    printf ("In getBBoxCatalogFrom-sitemap.awk\n") > "/dev/stderr"
    if (revisedTitles > 0 ) {
        revisedTitles == 1 ? field = "title" : field = "titles"
        printf ("    %2d %s revised in %s\n", revisedTitles, field, FILENAME) > "/dev/stderr"
    }
}

# Broduce a raw data spreadsheet of fields in BritBox Catalog --  apple_catalogue_feed.xml

# INVOCATION
#   awk -v ERROR_FILE=$ERROR_FILE -f getBBoxCatalogFrom-sitemap.awk $SITEMAP_FILE >$CATALOG_SPREADSHEET

# Field numbers
#     1 Sortkey       2 Title           3 Seasons          4 Episodes      5 Duration     6 Year
#     7 Rating        8 Description     9 Content Type    10 Content ID   11 Entity ID   12 Genre
#    13 Show Type    14 Date Type      15 Original Date   16 Show ID      16 Season ID   13 Sn #   14 Ep #

BEGIN {
    # Print header
    printf ("Sortkey\tTitle\tSeasons\tEpisodes\tDuration\tYear\tRating\tDescription\t")
    printf ("Content Type\tContent ID\tEntity ID\tGenre\tShow Type\tDate Type\tOriginal Date\t")
    printf ("Show ID\tSeason ID\tSn #\tEp #\n")
}

# Don't process credits
/<credit role=/,/<\/credit>/ {
    next
}

# Don't use Canadian ratings
/<rating systemCode="ca-tv">/ {
    next
}

# Don't use pubDate - it's too random to be useful
# <pubDate>2020-06-05T21:51:00Z</pubDate>
/<pubDate>/ {
    next
}

# Don't use "cover_artwork_horizontal"
# <artwork url="https://britbox-images-prod.s3-eu-west-1.amazonaws.com/3840x2160px/p05wv7gy.png" type="cover_artwork_horizontal" />
/<artwork url=.*type="cover_artwork_horizontal"/ {
    next
}

# Grab contentType & contentId
# <item contentType="tv_episode" contentId="p079sxm9">
/<item contentType="/ {
    split ($0,fld,"\"")
    contentType = fld[2]
    contentId = fld[4]
    # print "contentType = " contentType
    # print "contentId = " contentId
    # Make sure no fields will be carried over due to missing keys
    sortkey = ""
    title = ""
    EntityId = ""
    genre = ""
    rating = ""
    showType = ""
    duration = ""
    dateType = ""
    originalDate = ""
    showContentId = ""
    seasonContentId = ""
    seasonNumber = ""
    episodeNumber = ""
    description = ""
    # Generated fields
    year = ""
    # New fields that haven't been created yet
    numSeasons = 111
    numEpisodes = 222
}

# Grab title
# <title locale="en-US">Frequent Flyers</title>
/<title locale="en-US">/ {
    split ($0,fld,"[<>]")
    title = fld[3]
    # print "title = " title
}

# Grab genre
# <genre>drama</genre>
/<genre>/ {
    split ($0,fld,"[<>]")
    genre = fld[3]
    # print "genre = " genre
}

# Grab description
# <description>Set in the beautiful Yorkshire Dales, ...word.</description>
/<description>/ {
    split ($0,fld,"[<>]")
    description = fld[3]
    # print "description = " description
}

# Grab rating
# <rating systemCode="us-tv">TV-PG</rating>
/<rating systemCode=/ {
    split ($0,fld,"[<>]")
    rating = fld[3]
    # print "rating = " rating
}

# Grab type
# <type>series</type>
/<type>/ {
    split ($0,fld,"[<>]")
    showType = fld[3]
    # print "showType = " showType
}

# Grab duration
# <duration>3000</duration>
/<duration>/ {
    split ($0,fld,"[<>]")
    duration = fld[3]
    # print "duration = " duration
}

# Grab originalDate
# <originalAirDate>1978-03-25</originalAirDate>
# <originalPremiereDate>1978-01-08</originalPremiereDate>
# <originalReleaseDate>2017-12-25</originalReleaseDate>
/<original.*Date>/ {
    split ($0,fld,"[<>]")
    dateType = fld[2]
    sub (/original/,"",dateType)
    originalDate = fld[3]
    year = substr (originalDate,1,4)
    # print "dateType = " dateType
    # print "originalDate = " originalDate
    # print "year = " year
}

# Grab showContentId
# <showContentId>b008yjd9</showContentId>
/<showContentId>/ {
    split ($0,fld,"[<>]")
    showContentId = fld[3]
    # print "showContentId = " showContentId
}

# Grab seasonContentId
# <seasonContentId>p0318ps9</seasonContentId>
/<seasonContentId>/ {
    split ($0,fld,"[<>]")
    seasonContentId = fld[3]
    # print "seasonContentId = " seasonContentId
}

# Grab seasonNumber
# <seasonNumber>1</seasonNumber>
/<seasonNumber>/ {
    split ($0,fld,"[<>]")
    seasonNumber = fld[3]
    # print "seasonNumber = " seasonNumber
}

# Grab episodeNumber
# <episodeNumber>10</episodeNumber>
/<episodeNumber>/ {
    split ($0,fld,"[<>]")
    episodeNumber = fld[3]
    # print "episodeNumber = " episodeNumber
}

# Grab EntityId from artwork
# <artwork url="https://us.britbox.com/isl/api/v1/dataservice/ResizeImage/$value?Format='jpg'&Quality=45&ImageId='176236'&EntityType='Item'&EntityId='16103'&Width=1920&Height=1080&ResizeAction='fit'" type="tile_artwork" />
/<artwork url=.*EntityId='/ {
    sub (/.*EntityId='/,"")
    sub (/&apos.*/,"")
    EntityId = "_" $0
    # print "EntityId = " EntityId
    next
}

# Do any special end of item processing, then print raw data spreadsheet row
/<\/item>/ {
    if (title == "Shallow Grave") {
        EntityId = "_23576"
        # print "==> EntityId = " EntityId
    }

    if (title == "Porridge") {
        if (EntityId == "_9509") {
            revisedTitles += 1
            printf ("==> Changed title '%s' to 'Porridge (1974-1977)'\n", title) >> ERROR_FILE
            title = "Porridge (1974-1977)"
        } else if (EntityId == "_14747") {
            revisedTitles += 1
            printf ("==> Changed title '%s' to 'Porridge (2016-2017)'\n", title) >> ERROR_FILE
            title = "Porridge (2016-2017)"
        }
        # print "==> title = " title
        # print "==> EntityId = " EntityId
    }

    if (title == "A Midsummer Night's Dream") {
        if (EntityId == "_26179") {
            revisedTitles += 1
            printf ("==> Changed title '%s' to 'A Midsummer Night\'s Dream (1981)'\n", title) >> ERROR_FILE
            title = "A Midsummer Night's Dream (1981)"
        } else if (EntityId == "_15999") {
            revisedTitles += 1
            printf ("==> Changed title '%s' to 'A Midsummer Night\'s Dream (2016)'\n", title) >> ERROR_FILE
            title = "A Midsummer Night's Dream (2016)"
        }
        # print "==> title = " title
        # print "==> EntityId = " EntityId
    }

    if (contentId == "p07gnw9f") {
        EntityId = "_23842"
        # print "==> EntityId = " EntityId
    }

    if (contentType == "movie") {
        sortkey = sprintf ("%s (1) %s M%s", title, originalDate, EntityId)
    }

    if (contentType == "tv_show") {
        showTitle = title
        sortkey = sprintf ("%s (1) S%s", title, EntityId)
    }

    if (contentType == "tv_season") {
        sortkey = sprintf ("%s (2) S%02d", showTitle, seasonNumber)
    }

    if (contentType == "tv_episode") {
        sortkey = sprintf ("%s (2) S%02dE%03d %s", showTitle, seasonNumber, \
                episodeNumber, showContentId)
    }

    # Copied from printing header to make it easier to coordinate arranging fields
    # printf ("Sortkey\tTitle\tSeasons\tEpisodes\tDuration\tYear(s)\tRating\tDescription\t")
    # printf ("Content Type\tContent ID\tEntity ID\tGenre\tShow Type\tDate Type\tOriginal Date\t")
    # printf ("Show ID\tSeason ID\tSn #\tEp #\n")

    printf ("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", \
            sortkey, title, numSeasons, numEpisodes, duration, year, rating, description, \
            contentType, contentId, EntityId, genre, showType, dateType, originalDate, \
            showContentId, seasonContentId, seasonNumber, episodeNumber)
}

# <artwork url="https://us.britbox.com/isl/api/v1/dataservice/ResizeImage/$value?Format='jpg'&Quality=45&ImageId='176236'&EntityType='Item'&EntityId='16103'&Width=1920&Height=1080&ResizeAction='fit'" type="tile_artwork" />
# https://www.britbox.com/us/movie/300_Years_of_French_and_Saunders_16103
/<item contentType="movie"/,/<\/item>/ {
    # print
}

END {
    printf ("In getBBoxCatalogFrom-sitemap.awk\n") > "/dev/stderr"
    if (revisedTitles > 0 ) {
        revisedTitles == 1 ? field = "title" : field = "titles"
        printf ("    %2d %s revised in %s\n", revisedTitles, field, FILENAME) > "/dev/stderr"
    }
}


同じmodule/actionのルーティング名が複数ある場合に変換しない

同じmodule/actionのルーティング名が複数ある場合に変換しない

BEGIN {
  FS = "\t"
}

{
  module_and_action = $1
  route_name = $2

  table[module_and_action] = route_name
  count[module_and_action]++;
}

END {
  printf("/include_partial/b\n"); # skip (until the end of sed script) if "include_partial"
  for (module_and_action in table) {
    if (count[module_and_action] > 1) continue
    route_name = table[module_and_action]
    printf("s|'%s\\([\\?']\\)|'@%s\\1|g\n", module_and_action, route_name)
  }
}

BEGIN {
  FS = "\t"
}

{
  module_and_action = $1
  route_name = $2

  if (table[module_and_action]) next
  table[module_and_action] = route_name
}

END {
  printf("/include_partial/b\n"); # skip (until the end of sed script) if "include_partial"
  for (module_and_action in table) {
    route_name = table[module_and_action]
    printf("s|'%s\\([\\?']\\)|'@%s\\1|g\n", module_and_action, route_name)
  }
}


compile: make version_gen work on alpine

#
# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
#
# Copyright (C) 2006 Daniel M. Eischen.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#

#
# Make a list of all the library versions listed in the master file.
#
#   versions[] - array indexed by version name, contains number
#                of symbols (+ 1) found for each version.
#   successors[] - array index by version name, contains successor
#                  version name.
#   symbols[][] - array index by [version name, symbol index], contains
#                 names of symbols defined for each version.
#   names[] - array index is symbol name and value is its first version seen,
#	      used to check for duplicate symbols and warn about them.
#
BEGIN {
	brackets = 0;
	errors = warns = 0;
	version_count = 0;
	current_version = "";
	stderr = "/dev/stderr";
	while (getline < vfile) {
		# Strip comments.
		sub("#.*$", "", $0);

		# Strip leading and trailing whitespace.
		sub("^[ \t]+", "", $0);
		sub("[ \t]+$", "", $0);

		if (/^[a-zA-Z0-9._]+[ \t]*\{$/) {
			# Strip brace.
			sub("{", "", $1);
			brackets++;
			symver = $1;
			versions[symver] = 1;
			successors[symver] = "";
			generated[symver] = 0;
			version_count++;
		}
		else if (/^\}[ \t]*[a-zA-Z0-9._]+[ \t]*;$/) {
			v = $1 != "}" ? $1 : $2;
			# Strip brace.
			sub("}", "", v);
			# Strip semicolon.
			sub(";", "", v);
			if (symver == "") {
				printf("File %s: Unmatched bracket.\n",
				vfile) > stderr;
				errors++;
			}
			else if (versions[v] != 1) {
				printf("File %s: `%s' has unknown " \
				    "successor `%s'.\n",
				    vfile, symver, v) > stderr;
				errors++;
			}
			else
				successors[symver] = v;
			brackets--;
		}
		else if (/^\}[ \t]*;$/) {
			if (symver == "") {
				printf("File %s: Unmatched bracket.\n",
				    vfile) > stderr;
				errors++;
			}
			# No successor
			brackets--;
		}
		else if (/^\}$/) {
			printf("File %s: Missing final semicolon.\n",
			    vfile) > stderr;
			errors++;
		}
		else if (/^$/)
			;  # Ignore blank lines.
		else {
			printf("File %s: Unknown directive: `%s'.\n",
			    vfile, $0) > stderr;
			errors++;
		}
	}
	brackets = 0;
}

{
	# Set meaningful filename for diagnostics.
	filename = FILENAME != "" ? FILENAME : "<stdin>";

	# Delete comments, preceding and trailing whitespace, then
	# consume blank lines.
	sub("#.*$", "", $0);
	sub("^[ \t]+", "", $0);
	sub("[ \t]+$", "", $0);
	if ($0 == "")
		next;
}

/^[a-zA-Z0-9._]+[ \t]*\{$/ {
	# Strip bracket from version name.
	sub("{", "", $1);
	if (current_version != "") {
		printf("File %s, line %d: Illegal nesting detected.\n",
		    filename, FNR) > stderr;
		errors++;
	}
	else if (versions[$1] == 0) {
		printf("File %s, line %d: Undefined " \
		    "library version `%s'.\n", filename, FNR, $1) > stderr;
		errors++;
		# Remove this entry from the versions.
		delete versions[$1];
	}
	else
		current_version = $1;
	brackets++;
	next;
}

/^[a-zA-Z0-9._]+[ \t]*;$/ {
	# Strip semicolon.
	sub(";", "", $1);
	if (current_version != "") {
		count = versions[current_version];
		versions[current_version]++;
		symbols[current_version, count] = $1;
		if ($1 in names && names[$1] != current_version) {
			#
			# A graver case when a dup symbol appears under
			# different versions in the map.  That can result
			# in subtle problems with the library later.
			#
			printf("File %s, line %d: Duplicated symbol `%s' " \
			    "in version `%s', first seen in `%s'. " \
			    "Did you forget to move it to ObsoleteVersions?\n",
			    filename, FNR, $1,
			    current_version, names[$1]) > stderr;
			errors++;
		}
		else if (names[$1] == current_version) {
			#
			# A harmless case: a dup symbol with the same version.
			#
			printf("File %s, line %d: warning: " \
			    "Duplicated symbol `%s' in version `%s'.\n",
			    filename, FNR, $1, current_version) > stderr;
			warns++;
		}
		else
			names[$1] = current_version;
	}
	else {
		printf("File %s, line %d: Symbol `%s' outside version scope.\n",
		    filename, FNR, $1) > stderr;
		errors++;
	}
	next;
}

/^\}[ \t]*;$/ {
	brackets--;
	if (brackets < 0) {
		printf("File %s, line %d: Unmatched bracket.\n",
		    filename, FNR, $1) > stderr;
		errors++;
		brackets = 0;	# Reset
	}
	current_version = "";
	next;
}

{
	printf("File %s, line %d: Unknown directive: `%s'.\n",
	    filename, FNR, $0) > stderr;
	errors++;
}

function print_version(v)
{
	# This function is recursive, so return if this version
	# has already been printed.  Otherwise, if there is an
	# ancestral version, recursively print its symbols before
	# printing the symbols for this version.
	#
	if (generated[v] == 1)
		return;
	if (successors[v] != "")
		print_version(successors[v]);

	printf("%s {\n", v);

	# The version count is always one more that actual,
	# so the loop ranges from 1 to n-1.
	#
	for (i = 1; i < versions[v]; i++) {
		if (i == 1)
			printf("global:\n");
		printf("\t%s;\n", symbols[v, i]);
	}

	version_count--;
	if (version_count == 0) {
		printf("local:\n");
		printf("\t*;\n");
	}
	if (successors[v] == "")
		printf("};\n");
	else
		printf("} %s;\n", successors[v]);
	printf("\n");

	generated[v] = 1;
    }

END {
	if (errors) {
		printf("%d error(s) total.\n", errors) > stderr;
		exit(1);
	}
	# OK, no errors.
	for (v in versions) {
		print_version(v);
	}
}

#
# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
#
# Copyright (C) 2006 Daniel M. Eischen.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#

#
# Make a list of all the library versions listed in the master file.
#
#   versions[] - array indexed by version name, contains number
#                of symbols (+ 1) found for each version.
#   successors[] - array index by version name, contains successor
#                  version name.
#   symbols[][] - array index by [version name, symbol index], contains
#                 names of symbols defined for each version.
#   names[] - array index is symbol name and value is its first version seen,
#	      used to check for duplicate symbols and warn about them.
#
BEGIN {
	brackets = 0;
	errors = warns = 0;
	version_count = 0;
	current_version = "";
	stderr = "/dev/stderr";
	while (getline < vfile) {
		# Strip comments.
		sub("#.*$", "", $0);

		# Strip leading and trailing whitespace.
		sub("^[ \t]+", "", $0);
		sub("[ \t]+$", "", $0);

		if (/^[a-zA-Z0-9._]+[ \t]*{$/) {
			# Strip brace.
			sub("{", "", $1);
			brackets++;
			symver = $1;
			versions[symver] = 1;
			successors[symver] = "";
			generated[symver] = 0;
			version_count++;
		}
		else if (/^}[ \t]*[a-zA-Z0-9._]+[ \t]*;$/) {
			v = $1 != "}" ? $1 : $2;
			# Strip brace.
			sub("}", "", v);
			# Strip semicolon.
			sub(";", "", v);
			if (symver == "") {
				printf("File %s: Unmatched bracket.\n",
				vfile) > stderr;
				errors++;
			}
			else if (versions[v] != 1) {
				printf("File %s: `%s' has unknown " \
				    "successor `%s'.\n",
				    vfile, symver, v) > stderr;
				errors++;
			}
			else
				successors[symver] = v;
			brackets--;
		}
		else if (/^}[ \t]*;$/) {
			if (symver == "") {
				printf("File %s: Unmatched bracket.\n",
				    vfile) > stderr;
				errors++;
			}
			# No successor
			brackets--;
		}
		else if (/^}$/) {
			printf("File %s: Missing final semicolon.\n",
			    vfile) > stderr;
			errors++;
		}
		else if (/^$/)
			;  # Ignore blank lines.
		else {
			printf("File %s: Unknown directive: `%s'.\n",
			    vfile, $0) > stderr;
			errors++;
		}
	}
	brackets = 0;
}

{
	# Set meaningful filename for diagnostics.
	filename = FILENAME != "" ? FILENAME : "<stdin>";

	# Delete comments, preceding and trailing whitespace, then
	# consume blank lines.
	sub("#.*$", "", $0);
	sub("^[ \t]+", "", $0);
	sub("[ \t]+$", "", $0);
	if ($0 == "")
		next;
}

/^[a-zA-Z0-9._]+[ \t]*{$/ {
	# Strip bracket from version name.
	sub("{", "", $1);
	if (current_version != "") {
		printf("File %s, line %d: Illegal nesting detected.\n",
		    filename, FNR) > stderr;
		errors++;
	}
	else if (versions[$1] == 0) {
		printf("File %s, line %d: Undefined " \
		    "library version `%s'.\n", filename, FNR, $1) > stderr;
		errors++;
		# Remove this entry from the versions.
		delete versions[$1];
	}
	else
		current_version = $1;
	brackets++;
	next;
}

/^[a-zA-Z0-9._]+[ \t]*;$/ {
	# Strip semicolon.
	sub(";", "", $1);
	if (current_version != "") {
		count = versions[current_version];
		versions[current_version]++;
		symbols[current_version, count] = $1;
		if ($1 in names && names[$1] != current_version) {
			#
			# A graver case when a dup symbol appears under
			# different versions in the map.  That can result
			# in subtle problems with the library later.
			#
			printf("File %s, line %d: Duplicated symbol `%s' " \
			    "in version `%s', first seen in `%s'. " \
			    "Did you forget to move it to ObsoleteVersions?\n",
			    filename, FNR, $1,
			    current_version, names[$1]) > stderr;
			errors++;
		}
		else if (names[$1] == current_version) {
			#
			# A harmless case: a dup symbol with the same version.
			#
			printf("File %s, line %d: warning: " \
			    "Duplicated symbol `%s' in version `%s'.\n",
			    filename, FNR, $1, current_version) > stderr;
			warns++;
		}
		else
			names[$1] = current_version;
	}
	else {
		printf("File %s, line %d: Symbol `%s' outside version scope.\n",
		    filename, FNR, $1) > stderr;
		errors++;
	}
	next;
}

/^}[ \t]*;$/ {
	brackets--;
	if (brackets < 0) {
		printf("File %s, line %d: Unmatched bracket.\n",
		    filename, FNR, $1) > stderr;
		errors++;
		brackets = 0;	# Reset
	}
	current_version = "";
	next;
}

{
	printf("File %s, line %d: Unknown directive: `%s'.\n",
	    filename, FNR, $0) > stderr;
	errors++;
}

function print_version(v)
{
	# This function is recursive, so return if this version
	# has already been printed.  Otherwise, if there is an
	# ancestral version, recursively print its symbols before
	# printing the symbols for this version.
	#
	if (generated[v] == 1)
		return;
	if (successors[v] != "")
		print_version(successors[v]);

	printf("%s {\n", v);

	# The version count is always one more that actual,
	# so the loop ranges from 1 to n-1.
	#
	for (i = 1; i < versions[v]; i++) {
		if (i == 1)
			printf("global:\n");
		printf("\t%s;\n", symbols[v, i]);
	}

	version_count--;
	if (version_count == 0) {
		printf("local:\n");
		printf("\t*;\n");
	}
	if (successors[v] == "")
		printf("};\n");
	else
		printf("} %s;\n", successors[v]);
	printf("\n");

	generated[v] = 1;
    }

END {
	if (errors) {
		printf("%d error(s) total.\n", errors) > stderr;
		exit(1);
	}
	# OK, no errors.
	for (v in versions) {
		print_version(v);
	}
}