fix quoting a bit

fix quoting a bit

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

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

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

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

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

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

## NO CODING BELOW THIS POINT
coding { print "###code???####"; next; }

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

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

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

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

## quoting stops when item appears
## or not indented any more
quoting && (/^   *\*/ || !/^ /) {
  print "\\end{quotation}";
  print ""
  quoting = 0;
}

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

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

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

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

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

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

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

{ print }

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

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

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

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

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

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

## NO CODING BELOW THIS POINT
coding { print "###code???####"; next; }

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

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

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

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

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

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

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

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

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

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

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

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

{ print }


Script: do not upgrade myself

Script: do not upgrade myself

####################################################################
# Script.awk                                                       #
####################################################################

# Load options from the initialization script.
function loadOptions(script,    i, j, tokens, name, value) {
    tokenize(tokens, script)

    for (i in tokens) {
        if (tokens[i] ~ /^:/) {
            name = substr(tokens[i], 2)
            value = tokens[i + 1]

            if (value ~ /^[+-]?((0|[1-9][0-9]*)|[.][0-9]*|(0|[1-9][0-9]*)[.][0-9]*)([Ee][+-]?[0-9]+)?$/) {
                # Decimal number
                delete Option[name]
                Option[name] = value
            } else if (value == "false" || value == "true") {
                # Boolean
                delete Option[name]
                Option[name] = yn(value)
            } else if (value ~ /^".*"$/) {
                # String
                delete Option[name]
                Option[name] = literal(value)
            } else if (value == "[") {
                # List of strings
                delete Option[name]
                for (j = 1; tokens[i + j + 1] && tokens[i + j + 1] != "]"; j++) {
                    if (tokens[i + j + 1] ~ /^".*"$/)
                        Option[name][j] = literal(tokens[i + j + 1])
                    else {
                        e("[ERROR] Malformed configuration.")
                        return
                    }
                }
            } else {
                e("[ERROR] Malformed configuration.")
                return
            }
        }
    }
}

# Upgrade script.
function upgrade(    i, newVersion, registry, tokens) {
    RegistryIndex = "https://raw.githubusercontent.com/soimort/translate-shell/registry/index.trans"

    registry = curl(RegistryIndex)
    if (!registry) {
        e("[ERROR] Failed to check for upgrade.")
        ExitCode = 1
        return
    }

    tokenize(tokens, registry)
    for (i in tokens)
        if (tokens[i] == ":translate-shell")
            newVersion = literal(tokens[i + 1])
    if (newerVersion(newVersion, Version)) {
        w("Current version: \t" Version)
        w("New version available: \t" newVersion)
        w("Download from: \t" "http://www.soimort.org/translate-shell/trans")
    } else {
        w("Current version: \t" Version)
        w("Already up-to-date.")
    }
}

####################################################################
# Script.awk                                                       #
####################################################################

# Load options from the initialization script.
function loadOptions(script,    i, j, tokens, name, value) {
    tokenize(tokens, script)

    for (i in tokens) {
        if (tokens[i] ~ /^:/) {
            name = substr(tokens[i], 2)
            value = tokens[i + 1]

            if (value ~ /^[+-]?((0|[1-9][0-9]*)|[.][0-9]*|(0|[1-9][0-9]*)[.][0-9]*)([Ee][+-]?[0-9]+)?$/) {
                # Decimal number
                delete Option[name]
                Option[name] = value
            } else if (value == "false" || value == "true") {
                # Boolean
                delete Option[name]
                Option[name] = yn(value)
            } else if (value ~ /^".*"$/) {
                # String
                delete Option[name]
                Option[name] = literal(value)
            } else if (value == "[") {
                # List of strings
                delete Option[name]
                for (j = 1; tokens[i + j + 1] && tokens[i + j + 1] != "]"; j++) {
                    if (tokens[i + j + 1] ~ /^".*"$/)
                        Option[name][j] = literal(tokens[i + j + 1])
                    else {
                        e("[ERROR] Malformed configuration.")
                        return
                    }
                }
            } else {
                e("[ERROR] Malformed configuration.")
                return
            }
        }
    }
}

# Upgrade script.
function upgrade(    gitHead, i, newVersion, registry, tokens, trans) {
    if (!ENVIRON["TRANS_ABSPATH"]) {
        w("[ERROR] Not running from a single executable.")
        gitHead = getGitHead()
        if (gitHead)
            w("        Please try to upgrade via git commands.")
        else
            w("        Please download the latest release from here:" RS \
              "        https://github.com/soimort/translate-shell/releases")
        ExitCode = 1
        return
    }

    RegistryIndex = "https://raw.githubusercontent.com/soimort/translate-shell/registry/index.trans"
    TransExecutable = "http://www.soimort.org/translate-shell/trans"

    registry = curl(RegistryIndex)
    if (!registry) {
        e("[ERROR] Upgrading failed.")
        ExitCode = 1
        return
    }

    tokenize(tokens, registry)
    for (i in tokens)
        if (tokens[i] == ":translate-shell")
            newVersion = literal(tokens[i + 1])
    if (newerVersion(newVersion, Version)) {
        trans = curl(TransExecutable)
        if (trans) {
            print "Successfully upgraded to " newVersion "." > STDERR
            print trans > ENVIRON["TRANS_ABSPATH"]
            exit 0
        } else
            e("[ERROR] Upgrading failed due to network errors.")
    } else
        e("[ERROR] Already up-to-date.")
}


tests/uid.awk: rewrite in a more maintainable style

Since the test is virtually a FSM, rewrite it as a FSM.

BEGIN {
  r_uint = "(0|[1-9][0-9]*)"
  regexp = "^getuid" suffix "\\(\\)[[:space:]]+= " r_uint "$"
  expected = "getuid"
  fail = 0
}

regexp == "" {
  fail = 1
  next
}

{
  if (match($0, regexp, a)) {
    switch (expected) {
      case "getuid":
        uid = a[1]
        expected = "setuid"
        regexp = "^setuid" suffix "\\(" uid "\\)[[:space:]]+= 0$"
        next
      case "setuid":
        expected = "getresuid"
        regexp = "^getresuid" suffix "\\(\\[" uid "\\], \\[" uid "\\], \\[" uid "\\]\\)[[:space:]]+= 0$"
        next
      case "getresuid":
        expected = "setreuid"
        regexp = "^setreuid" suffix "\\(-1, -1\\)[[:space:]]+= 0$"
        next
      case "setreuid":
        expected = "setresuid"
        regexp = "^setresuid" suffix "\\(-1, " uid ", -1\\)[[:space:]]+= 0$"
        next
      case "setresuid":
        expected = "chown"
        regexp = "^chown" suffix "\\(\".\", -1, -1\\)[[:space:]]+= 0$"
        next
      case "chown":
        expected = "the last line"
        regexp = "^\\+\\+\\+ exited with 0 \\+\\+\\+$"
        next
      case "the last line":
        expected = "nothing"
        regexp = ""
        next
    }
  }
  next
}

END {
  if (fail) {
    print "Unexpected output after exit"
    exit 1
  }
  if (regexp == "")
    exit 0
  print "error: " expected " doesn't match"
  exit 1
}

BEGIN {
  ok = 0
  fail = 0
  r_uid = "(0|[1-9][0-9]*)"
  r_getuid = "^getuid" suffix "\\(\\)[[:space:]]+= " r_uid "$"
  r_setuid = "^/$"
  r_getresuid = "^/$"
  r_setreuid = "^/$"
  r_setresuid = "^/$"
  r_chown = "^/$"
  s_last = "/"
}

ok == 1 {
  fail = 1
  next
}

$0 == s_last {
  ok = 1
  next
}

{
  if (match($0, r_getuid, a)) {
    r_uid = a[1]
    r_setuid = "^setuid" suffix "\\(" r_uid "\\)[[:space:]]+= 0$"
    next
  }
  if (match($0, r_setuid)) {
    r_getresuid = "^getresuid" suffix "\\(\\[" r_uid "\\], \\[" r_uid "\\], \\[" r_uid "\\]\\)[[:space:]]+= 0$"
    next
  }
  if (match($0, r_getresuid)) {
    r_setreuid = "^setreuid" suffix "\\(-1, -1\\)[[:space:]]+= 0$"
    next
  }
  if (match($0, r_setreuid)) {
    r_setresuid = "^setresuid" suffix "\\(-1, " r_uid ", -1\\)[[:space:]]+= 0$"
    next
  }
  if (match($0, r_setresuid)) {
    r_chown = "^chown" suffix "\\(\".\", -1, -1\\)[[:space:]]+= 0$"
    next
  }
  if (match($0, r_chown)) {
    s_last = "+++ exited with 0 +++"
    next
  }
  next
}

END {
  if (fail) {
    print "Unexpected output after exit"
    exit 1
  }
  if (ok)
    exit 0
  if (r_setuid == "^/$") {
    print "getuid doesn't match"
    exit 1
  }
  if (r_getresuid == "^/$") {
    print "setuid doesn't match"
    exit 1
  }
  if (r_setreuid == "^/$") {
    print "getresuid doesn't match"
    exit 1
  }
  if (r_setresuid == "^/$") {
    print "setreuid doesn't match"
    exit 1
  }
  if (r_chown == "^/$") {
    print "setresuid doesn't match"
    exit 1
  }
  if (s_last == "/") {
    print "chown doesn't match"
    exit 1
  }
  print "The last line doesn't match"
  exit 1
}


Removing unneeded files in repo

Removing unneeded files in repo

##  Script for parsing arxiv metadata.  Call with a catalog file
##  that lists the bookids and file location (with _ for /) of the
##  abstracts:
##          awk -f parse_metadata.awk ../texts/catalog.txt
##
##  The code in the BEGIN statement sets up hashes for convenience.  "a"
##  is used to make the date into proper datetime SQL format.  "b" is to
##  translate the raw categories into ones that we will use in our database
BEGIN{
  a["Jan"] = "01";
  a["Feb"] = "02";
  a["Mar"] = "03";
  a["Apr"] = "04";
  a["May"] = "05";
  a["Jun"] = "06";
  a["Jul"] = "07";
  a["Aug"] = "08";
  a["Sep"] = "09";
  a["Oct"] = "10";
  a["Nov"] = "11";
  a["Dec"] = "12";
  OFS = "\t";
  where=0;

  b["acc-phys"]="physics"
  b["adap-org"]="nlin"
  b["alg-geom"]="math"
  b["ao-sci"]="physics"
  b["astro-ph"]="physics.astro-ph"
  b["astro-ph.CO"]="physics.astro-ph"
  b["astro-ph.EP"]="physics.astro-ph"
  b["astro-ph.GA"]="physics.astro-ph"
  b["astro-ph.HE"]="physics.astro-ph"
  b["astro-ph.IM"]="physics.astro-ph"
  b["astro-ph.SR"]="physics.astro-ph"
  b["atom-ph"]="physics"
  b["bayes-an"]="physics"
  b["chao-dyn"]="nlin"
  b["chem-ph"]="physics"
  b["cmp-lg"]="cs"
  b["comp-gas"]="nlin"
  b["cond-mat"]="physics.cond-mat"
  b["cond-mat.dis-nn"]="physics.cond-mat"
  b["cond-mat.mes-hall"]="physics.cond-mat"
  b["cond-mat.mtrl-sci"]="physics.cond-mat"
  b["cond-mat.other"]="physics.cond-mat"
  b["cond-mat.quant-gas"]="physics.cond-mat"
  b["cond-mat.soft"]="physics.cond-mat"
  b["cond-mat.stat-mech"]="physics.cond-mat"
  b["cond-mat.str-el"]="physics.cond-mat"
  b["cond-mat.supr-con"]="physics.cond-mat"
  b["cs.AI"]="cs"
  b["cs.AR"]="cs"
  b["cs.CC"]="cs"
  b["cs.CE"]="cs"
  b["cs.CG"]="cs"
  b["cs.CL"]="cs"
  b["cs.CR"]="cs"
  b["cs.CV"]="cs"
  b["cs.CY"]="cs"
  b["cs.DB"]="cs"
  b["cs.DC"]="cs"
  b["cs.DL"]="cs"
  b["cs.DM"]="cs"
  b["cs.DS"]="cs"
  b["cs.ET"]="cs"
  b["cs.FL"]="cs"
  b["cs.GL"]="cs"
  b["cs.GR"]="cs"
  b["cs.GT"]="cs"
  b["cs.HC"]="cs"
  b["cs.IR"]="cs"
  b["cs.IT"]="cs"
  b["cs.LG"]="cs"
  b["cs.LO"]="cs"
  b["cs.MA"]="cs"
  b["cs.MM"]="cs"
  b["cs.MS"]="cs"
  b["cs.NA"]="cs"
  b["cs.NE"]="cs"
  b["cs.NI"]="cs"
  b["cs.OH"]="cs"
  b["cs.OS"]="cs"
  b["cs.PF"]="cs"
  b["cs.PL"]="cs"
  b["cs.RO"]="cs"
  b["cs.SC"]="cs"
  b["cs.SD"]="cs"
  b["cs.SE"]="cs"
  b["cs.SI"]="cs"
  b["cs.SY"]="cs"
  b["dg-ga"]="math"
  b["funct-an"]="math"
  b["gr-qc"]="physics.gr-qc"
  b["hep-ex"]="physics.hep-ex"
  b["hep-lat"]="physics.hep-lat"
  b["hep-ph"]="physics.hep-ph"
  b["hep-th"]="physics.hep-th"
  b["math.AC"]="math"
  b["math.AG"]="math"
  b["math.AP"]="math"
  b["math.AT"]="math"
  b["math.CA"]="math"
  b["math.CO"]="math"
  b["math.CT"]="math"
  b["math.CV"]="math"
  b["math.DG"]="math"
  b["math.DS"]="math"
  b["math.FA"]="math"
  b["math.GM"]="math"
  b["math.GN"]="math"
  b["math.GR"]="math"
  b["math.GT"]="math"
  b["math.HO"]="math"
  b["math.IT"]="math"
  b["math.KT"]="math"
  b["math.LO"]="math"
  b["math.MG"]="math"
  b["math.MP"]="math"
  b["math.NA"]="math"
  b["math.NT"]="math"
  b["math.OA"]="math"
  b["math.OC"]="math"
  b["math-ph"]="math.math-ph"
  b["math.PR"]="math"
  b["math.QA"]="math"
  b["math.RA"]="math"
  b["math.RT"]="math"
  b["math.SG"]="math"
  b["math.SP"]="math"
  b["math.ST"]="math"
  b["mtrl-th"]="physics.cond-mat"
  b["nlin.AO"]="nlin"
  b["nlin.CD"]="nlin"
  b["nlin.CG"]="nlin"
  b["nlin.PS"]="nlin"
  b["nlin.SI"]="nlin"
  b["nucl-ex"]="physics.nucl-ex"
  b["nucl-th"]="physics.nucl-th"
  b["patt-sol"]="nlin"
  b["physics.acc-ph"]="physics"
  b["physics.ao-ph"]="physics"
  b["physics.atm-clus"]="physics"
  b["physics.atom-ph"]="physics"
  b["physics.bio-ph"]="physics"
  b["physics.chem-ph"]="physics"
  b["physics.class-ph"]="physics"
  b["physics.comp-ph"]="physics"
  b["physics.data-an"]="physics"
  b["physics.ed-ph"]="physics"
  b["physics.flu-dyn"]="physics"
  b["physics.gen-ph"]="physics"
  b["physics.geo-ph"]="physics"
  b["physics.hist-ph"]="physics"
  b["physics.ins-det"]="physics"
  b["physics.med-ph"]="physics"
  b["physics.optics"]="physics"
  b["physics.plasm-ph"]="physics"
  b["physics.pop-ph"]="physics"
  b["physics.soc-ph"]="physics"
  b["physics.space-ph"]="physics"
  b["plasm-ph"]="physics"
  b["q-alg"]="math"
  b["q-bio.BM"]="q-bio"
  b["q-bio.CB"]="q-bio"
  b["q-bio.GN"]="q-bio"
  b["q-bio.MN"]="q-bio"
  b["q-bio.NC"]="q-bio"
  b["q-bio.OT"]="q-bio"
  b["q-bio.PE"]="q-bio"
  b["q-bio.QM"]="q-bio"
  b["q-bio"]="q-bio"
  b["q-bio.SC"]="q-bio"
  b["q-bio.TO"]="q-bio"
  b["q-fin.CP"]="q-fin"
  b["q-fin.GN"]="q-fin"
  b["q-fin.PM"]="q-fin"
  b["q-fin.PR"]="q-fin"
  b["q-fin.RM"]="q-fin"
  b["q-fin.ST"]="q-fin"
  b["q-fin.TR"]="q-fin"
  b["quant-ph"]="physics.quant-ph"
  b["solv-int"]="nlin"
  b["stat.AP"]="stat"
  b["stat.CO"]="stat"
  b["stat.ME"]="stat"
  b["stat.ML"]="stat"
  b["stat.OT"]="stat"
  b["stat.TH"]="stat"
  b["supr-con"]="physics.cond-mat"
}
{
  # x is the book id
  x = $1;

  # fn is the filename
  fn = $2;
  gsub(/_/,"/", fn);
  fn = "../abs/"fn".abs"

  # where is used to deal with multiline author and title fields
  # t is title, au is author, c is the categories, fields is the line
  # we read in
  where = 0;
  t = "";
  au = "";
  delete c;
  delete fields;
  while ((getline line < fn) > 0) {
    len=split(line, fields);
    # arxiv id
    if (line ~ /^arXiv:/) {
      id=substr(line,7);
    }
    # email address
    if (line ~ /^From:/) {
      from=substr(line,7);
      # take only the email address, not user name
      st=index(from, "<");
      ed=index(from, ">");
      from2=substr(from,st+1,ed-st-1);
      # take only the domain from the email address
      at=index(from2, "@");
      from=substr(from2, at+1);
      num=split(from, s, "\\.");
      final=s[num];
      # write out the domain levels separated by tabs.
      # the first level is "edu", then "harvard.edu", then "seas.harvard.edu"
      for (i=num-1; i>=1; i--) {
        dl=sprintf("%s", s[i]);
        for (j=i+1; j<=num; j++) {
	  dl=sprintf("%s.%s", dl,s[j]);
        }
        final=sprintf("%s\t%s",final,dl);
      }
    }
    # date, convert to datetime format
    if (line ~ /^Date:/) {
      ds=sprintf("%s-%s-%02d %s",fields[5],a[fields[4]],fields[3],fields[6])
    }
    # where is for dealing with multiline title
    if (line ~ /^Title:/) {
      t=substr(line, index(line,fields[2]));
      where=1;
    }
    # where is for dealing with multiline author
    if (line ~ /^Authors:/) {
      au=substr(line, index(line,fields[2]));
      where=2;
    }
    # if line starts with an indentation, choose appropriate field to add to
    if (line ~ /^  /) {
      if (where==1)
	t=t""line;
      else if (where==2)
	au=au""line;
    }
    # reset where if we get to end of metadata
    if (line ~ /^\\/) {
      where=0;
    }
    # reset where if we get to Categories, which is always after title/author
    if (line ~ /^Categories:/) {
      where = 0;
      # loop over all categories
      for (i=2; i<=len; i++) {
	# check if we already saw it; want to preserve original order
        if (!(fields[i] in c)) {
	  # check if it's a funky one
	  if (fields[i] in b) {
	    # b-mapped category not seen yet, add
	    if (!(b[fields[i]] in c)) {
	      c[b[fields[i]]]=i;
	      print x,id,ds,t,au,b[fields[i]], final;
	    }
	  }
	  else {
	    # regular category not seen yet, add
	    c[fields[i]] = i;
	    print x,id,ds,t,au,fields[i], final;
	  }
	}
      }
    }
  }
  close (fn);
}


render code blocks at EOF - CTR

render code blocks at EOF - CTR

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

#
# @author Daniel Kuppitz (http://gremlin.guru)
#
function print_tabs(next_id, tabs, blocks) {

  num_tabs = length(tabs)
  x = next_id

  print "++++"
  print "
"

  for (i in tabs) {
    title = tabs[i]
    print "  <input id=\"tab-" id_part "-" x "\" type=\"radio\" name=\"radio-set-" id_part "-" next_id "\" class=\"tab-selector-" i "\"" (i == 1 ? " checked=\"checked\"" : "") " />"
    print "  " title ""
    x++
  }

  for (i in blocks) {
    print "
"
    print "
"
    print "++++\n"
    print blocks[i]
    print "++++"
    print "
"
    print "
"
  }

  print "
"
  print "++++\n"
}

function transform_callouts(code, c) {
  return gensub(/\s*((<[0-9]+>\s*)*<[0-9]+>)\s*\n/, " " c c " \\1\\2\n", "g", code)
}

BEGIN {
  id_part=systime()
  status = 0
  next_id = 1
  block[0] = 0 # initialize "blocks" as an array
  delete blocks[0]
}

/^\[gremlin-/ {
  status = 1
  lang = gensub(/^\[gremlin-([^,\]]+).*/, "\\1", "g", $0)
  code = ""
  evaluate = 1
}

/^\[source,(csharp|groovy|java|javascript|python),tab\]/ {
  status = 1
  lang = gensub(/^\[source,([^,\]]+).*/, "\\1", "g", $0)
  code = ""
  evaluate = 0
}

/^\[source,(csharp|groovy|java|javascript|python)\]/ {
  if (status == 3) {
    status = 1
    lang = gensub(/^\[source,([^\]]+).*/, "\\1", "g", $0)
    code = ""
  }
}

! /^\[source,(csharp|groovy|java|javascript|python)/ {
  if (status == 3 && $0 != "") {
    print_tabs(next_id, tabs, blocks)
    next_id = next_id + length(tabs)
    for (i in tabs) {
      delete tabs[i]
      delete blocks[i]
    }
    status = 0
  }
}

/^----$/ {
  if (status == 1) {
    status = 2
  } else if (status == 2) {
    status = 3
  }
}

{ if (status == 3) {
    if ($0 == "----") {
      i = length(blocks) + 1
      if (i == 1 && evaluate == 1) {
        tabs[i] = "console (" lang ")"
        blocks[i] = code_header code "\n" $0 "\n"
        i++
      }
      tabs[i] = lang
      switch (lang) {
        case "python":
          c = "#"
          break
        default:
          c = "//"
          break
      }
      blocks[i] = "[source," lang "]" transform_callouts(code, c) "\n" $0 "\n"
    }
  } else {
    if (status == 0) print
    else if (status == 1) code_header = gensub(/,tab/, "", "g", $0)
    else code = code "\n" $0
  }
}

END {
  # EOF
  if (status == 3) {
    print_tabs(next_id, tabs, blocks)
  }
}


second

second

#!/usr/local/bin/awk -E

# The MIT License (MIT)
#
# Copyright (c) 2016 by User:Green Cardamom (at en.wikipedia.org)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# 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 OR COPYRIGHT HOLDERS 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.

# "Auto" if you plan to update via AWB, manually or automatic
#   The assumption is you have already run and processed the data via ./project

# Demon to pass data back and forth between Windows host and Linux guest OS under VirtualBox
# See also demon-win.awk for the version running on the Windows host.
# Purposes is to run AWB on windows, and unix scripts on Linux.

@include "init.awk"
@include "library.awk"
@include "getopt.awk"

BEGIN {

  while ((C = getopt(ARGC, ARGV, "d:p:")) != -1) {
    if(C == "p")                                     # -p <project>      Project to run
      pid = verifypid(Optarg)
    if(C == "d")                                     # -d <number>       Delay seconds to use.
      delay = Optarg                                 #                     If -d0 (zero), no delay
  }
  setProject(pid)     # library.awk .. load Project[] paths via project.cfg
                      # if -p not given, use default noted in project.cfg

  if(delay == "" || ! isanumber(delay) ) {
    delay = 0
  }

  main()

}

function main(    name,tempid,article,command) {

  removefile(Ramdisk "article.txt")              # Clear out old files
  removefile(Ramdisk "abort.txt")

  prnt("\ndemon-lin.awk: Waiting for " Ramdisk "name.txt ...")

  while(1) {

    sleep(2)
    Z++
    if(Z > 500) {   # time-out. 2500 = about 90 minutes w/ 2sec sleep
      print "demon-lin.awk: Time out"
      exit
    }

    if( checkexists(Ramdisk "name.txt") ) {

      Z = 0                              # reset time-out
      name=article=tempid=choose=""      # reset variables

      name = strip( readfile(Ramdisk "name.txt") )
      prnt("demon-lin.awk: New job request: " name )
      removefile(Ramdisk "name.txt")
      removefile(Ramdisk "article.txt")

      if(length(name) > 0) {
          tempid = whatistempid(name, Project["index"] )
          if(tempid == "" || tempid == 0) {
            abort("demon-lin.awk: Error unknown tempid. " name)
          }
          else {
            if(checkexists(tempid "article.waybackmedic.txt"))  {  # Skip if no changes were made.

              print http2var("https://en.wikipedia.org/wiki/" gensub(/[ ]/, "_", "g", name) "?action=raw") > tempid "article.new.txt"
              close(tempid "article.new.txt")
              newarticle = readfile(tempid "article.new.txt")
              article = readfile(tempid "article.txt")
              if(length(newarticle) == 0 || length(article) == 0) {
                abort("demon-lin.awk: Error unable to retrieve wikisource or article.txt. " name)
              }
              else {
                if(length(article) != length(newarticle)) {
                  prnt("demon-lin.awk: Article lengths out of sync (old=" length(article) " new=" length(newarticle) "). Re-running Wayback Medic ...")
                  prnt("               old ID: " tempid)
                  command = Exe["medic"] " -n \"" name "\" -p \"" Project["id"] "\""
                  system(command)
                  tempid = whatistempid(name, Project["index"] )
                  prnt("               new ID: " tempid)
                  article = readfile(tempid "article.txt")
                  if(length(article) == 0)
                    abort("demon-lin.awk: Error unable to run Wayback Medic. " name)
                }
                if(checkexists(tempid "article.waybackmedic.txt") ) {
                  command = Exe["cp"] " " tempid "article.waybackmedic.txt " Ramdisk "article.txt"
                  prnt("demon-lin.awk: Status successful. Copying article.waybackmedic.txt to shared directory. " name)
                  sleep( delay )
                  sys2var(command)
                }
                else {
                  prnt("\ndemon-lin.awk: No changes to article.")
                }
              }
            }
            else {
              prnt("\ndemon-lin.awk: No changes to article.")
            }
          }
      }
      else {
        abort("demon-lin.awk: error retrieving name")
      }
      prnt("\ndemon-lin.awk: Waiting for " Ramdisk "name.txt ...")
    }
  }
}

#
# Return the path/tempid of a name (eg. /home/adminuser/wi-awb/temp/wi-awb-0202173111/)
#
function whatistempid(name, filepath,      s, a, re) {

  if(! checkexists(filepath) ) {
    abort("demon-lin.awk: Error unable to find " filepath ". " name )
    return 0
  }
  re = "^" regesc2(strip(name)) "$"
  while ((getline s < filepath ) > 0) {
    split(s, a, "|")
    if(strip(a[1]) ~ re) {
      close(filepath)
      return strip(a[2])
    }
  }
  close(filepath)
  return 0
}

#
# Return 1 if name is in file
#
#
# Abort
#
function abort(msg,  filen) {
  if( length(msg) > 0 )
    prnt(msg)
  printf "0" > Ramdisk "abort.txt"
  close(Ramdisk "abort.txt")
}

#
# Print and log messages
#
function prnt(msg) {
  if( length(msg) > 0 ) {
    print(msg)
    print(strftime("%Y%m%d %H:%M:%S") " " msg) >> Home "demon-lin.log"
    close(Home "demon-lin.log")
  }
}

function removefile(str) {
      if( checkexists(str) )
        sys2var( Exe["rm"] " -- " str)
      if( checkexists(str) ) {
        abort("demon-lin.awk: Error unable to delete " str ", aborting.")
        exit
      }
      system("") # Flush buffer
}

#!/usr/local/bin/awk -E

# The MIT License (MIT)
#
# Copyright (c) 2016 by User:Green Cardamom (at en.wikipedia.org)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# 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 OR COPYRIGHT HOLDERS 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.

# "Auto" if you plan to update via AWB, manually or automatic
#   The assumption is you have already run and processed the data via ./project

# Demon to pass data back and forth between Windows host and Linux guest OS under VirtualBox
# See also demon-win.awk for the version running on the Windows host.
# Purposes is to run AWB on windows, and unix scripts on Linux.

@include "init.awk"
@include "library.awk"
@include "getopt.awk"

BEGIN {

  while ((C = getopt(ARGC, ARGV, "d:p:")) != -1) {
    if(C == "p")                                     # -p <project>      Project to run
      pid = verifypid(Optarg)
    if(C == "d")                                     # -d <number>       Delay seconds to use (must be > 12). If set, no random delay.
      delay = Optarg                                 #                     If -d not set, a random delay period is used (15 + 1-50 seconds)
                                                     #                     If -d0 (zero), no delay
  }
  setProject(pid)     # library.awk .. load Project[] paths via project.cfg
                      # if -p not given, use default noted in project.cfg

  if( delay == "" || (delay < 12 && delay > 0) || ! isanumber(delay) ) {
    delay = 15
    delayrandom = 1
  }
  else if(delay == 0) {
    delay = 0
    delayrandom = 0
  }
  else {
    delay = 15
    delayrandom = 0
  }

  main()

}

function main(    name,tempid,article,command) {

  removefile(Ramdisk "article.txt")              # Clear out old files
  removefile(Ramdisk "abort.txt")

  prnt("\ndemon-lin.awk: Waiting for " Ramdisk "name.txt ...")

  while(1) {

    sleep(2)
    Z++
    if(Z > 500) {   # time-out. 2500 = about 90 minutes w/ 2sec sleep
      print "demon-lin.awk: Time out"
      exit
    }

    if( checkexists(Ramdisk "name.txt") ) {

      Z = 0                              # reset time-out
      name=article=tempid=choose=""      # reset variables

      name = strip( readfile(Ramdisk "name.txt") )
      prnt("demon-lin.awk: New job request: " name )
      removefile(Ramdisk "name.txt")
      removefile(Ramdisk "article.txt")

      if(length(name) > 0) {
          tempid = whatistempid(name, Project["index"] )
          if(tempid == "" || tempid == 0) {
            abort("demon-lin.awk: Error unknown tempid. " name)
          }
          else {
            if(checkexists(tempid "article.waybackmedic.txt"))  {  # Skip if no changes were made.

              print http2var("https://en.wikipedia.org/wiki/" gensub(/[ ]/, "_", "g", name) "?action=raw") > tempid "article.new.txt"
              close(tempid "article.new.txt")
              newarticle = readfile(tempid "article.new.txt")
              article = readfile(tempid "article.txt")
              if(length(newarticle) == 0 || length(article) == 0) {
                abort("demon-lin.awk: Error unable to retrieve wikisource or article.txt. " name)
              }
              else {
                if(length(article) != length(newarticle)) {
                  prnt("demon-lin.awk: Article lengths out of sync (old=" length(article) " new=" length(newarticle) "). Re-running Wayback Medic ...")
                  prnt("               old ID: " tempid)
                  command = Exe["medic"] " -n \"" name "\" -p \"" Project["id"] "\""
                  system(command)
                  tempid = whatistempid(name, Project["index"] )
                  prnt("               new ID: " tempid)
                  article = readfile(tempid "article.txt")
                  if(length(article) == 0)
                    abort("demon-lin.awk: Error unable to run Wayback Medic. " name)
                }
                if(checkexists(tempid "article.waybackmedic.txt") ) {
                  command = Exe["cp"] " " tempid "article.waybackmedic.txt " Ramdisk "article.txt"
                  prnt("demon-lin.awk: Status successful. Copying article.waybackmedic.txt to shared directory. " name)
                  if(delayrandom)
                    sleep( delay + randomnumber(40) ) # 180 will do ~300 in ~ 9 hours
                  else
                    sleep( delay )
                  sys2var(command)
                }
                else {
                  prnt("\ndemon-lin.awk: No changes to article.")
                }
              }
            }
            else {
              prnt("\ndemon-lin.awk: No changes to article.")
            }
          }
      }
      else {
        abort("demon-lin.awk: error retrieving name")
      }
      prnt("\ndemon-lin.awk: Waiting for " Ramdisk "name.txt ...")
    }
  }
}

#
# Return the path/tempid of a name (eg. /home/adminuser/wi-awb/temp/wi-awb-0202173111/)
#
function whatistempid(name, filepath,      s, a, re) {

  if(! checkexists(filepath) ) {
    abort("demon-lin.awk: Error unable to find " filepath ". " name )
    return 0
  }
  re = "^" regesc2(strip(name)) "$"
  while ((getline s < filepath ) > 0) {
    split(s, a, "|")
    if(strip(a[1]) ~ re) {
      close(filepath)
      return strip(a[2])
    }
  }
  close(filepath)
  return 0
}

#
# Return 1 if name is in file
#
#
# Abort
#
function abort(msg,  filen) {
  if( length(msg) > 0 )
    prnt(msg)
  printf "0" > Ramdisk "abort.txt"
  close(Ramdisk "abort.txt")
}

#
# Print and log messages
#
function prnt(msg) {
  if( length(msg) > 0 ) {
    print(msg)
    print(strftime("%Y%m%d %H:%M:%S") " " msg) >> Home "demon-lin.log"
    close(Home "demon-lin.log")
  }
}

function removefile(str) {
      if( checkexists(str) )
        sys2var( Exe["rm"] " -- " str)
      if( checkexists(str) ) {
        abort("demon-lin.awk: Error unable to delete " str ", aborting.")
        exit
      }
      system("") # Flush buffer
}


layerman: fix typo in text output

layerman: fix typo in text output

Signed-off-by: Koen Kooi <42e3d96910f922bdd7dd1805fe3f8aff634f391d@dominion.thruhere.net>

BEGIN {
	FS =",";
	print "Configured layers:\n";
 }

$1 != "# Name" { print "layer repository name: " $1 "\nlayer uri: " $2 "\nlayer branch/revision: " $3 "/" $4 ; system("${OE_BASE}/scripts/layerman " $1 " "  $2 " " $3 " " $4 " " command " " commandarg);}

BEGIN {
	FS =",";
	print "Configured layers:\n";
 }

$1 != "# Name" { print "layer repository nam/e: " $1 "\nlayer uri: " $2 "\nlayer branch/revision: " $3 "/" $4 ; system("${OE_BASE}/scripts/layerman " $1 " "  $2 " " $3 " " $4 " " command " " commandarg);}


MONDRIAN: Integrate from latest util/bin/checkFile.awk.

[git-p4: depot-paths = "//open/mondrian/": change = 14186]

#!/bin/gawk
# $Id: //open/util/bin/checkFile#13 $
# Checks that a file is valid.

function error(fname, linum, msg) {
    printf "%s: %d: %s\n", fname, linum, msg;
    if (0) print; # for debug
}
function _matchFile(fname) {
    return fname ~ "/mondrian/" \
       || fname ~ "/org/olap4j/" \
       || fname ~ "/aspen/" \
       || fname ~ "/farrago/" \
       || fname ~ "/fennel/" \
       || fname ~ "/extensions/" \
       || fname ~ "/com/sqlstream/" \
       || !lenient;
}
function _isCpp(fname) {
    return fname ~ /\.(cpp|h)$/;
}
function _isJava(fname) {
    return fname ~ /\.(java|jj)$/;
}
function push(val) {
    switchStack[switchStackLen++] = val;
}
function pop() {
    --switchStackLen
    val = switchStack[switchStackLen];
    delete switchStack[switchStackLen];
    return val;
}
function afterFile() {
    # Compute basename. If fname="/foo/bar/baz.txt" then basename="baz.txt".
    basename = fname;
    gsub(".*/", "", basename);
    gsub(lf, "", lastNonEmptyLine);
    terminator = "// End " basename;
    if (matchFile && (lastNonEmptyLine != terminator)) {
        error(fname, FNR, sprintf("Last line should be %c%s%c", 39, terminator, 39));
    }
}
# Returns whether there are unmatched open parentheses.
# unmatchedOpenParens("if ()") returns false.
# unmatchedOpenParens("if (") returns true.
# unmatchedOpenParens("if (foo) bar(") returns false
function unmatchedOpenParens(s) {
    i = index(s, "(");
    if (i == 0) {
    if (0)         print FNR, "unmatchedOpenParens=0";
        return 0;
    }
    openCount = 1;
    while (++i <= length(s)) {
        c = substr(s, i, 1);
        if (c == "(") {
            ++openCount;
        }
        if (c == ")") {
            if (--openCount == 0) {
    if (0)         print FNR, "unmatchedOpenParens=0 (b)";
                return 0;
            }
        }
    }
    if (0) print FNR, "unmatchedOpenParens=1";
    return 1;
}

BEGIN {
    # pre-compute regexp for quotes, linefeed
    apos = sprintf("%c", 39);
    quot = sprintf("%c", 34);
    lf = sprintf("%c", 13);
    pattern = apos "(\\" apos "|[^" apos "])" apos;
    if (0) printf "maxLineLength=%s lenient=%s\n", maxLineLength, lenient;
}
FNR == 1 {
    if (fname) {
        afterFile();
    }
    fname = FILENAME;
    matchFile = _matchFile(fname);
    isCpp = _isCpp(fname);
    isJava = _isJava(fname);
}
{
    if (previousLineEndedInCloseBrace > 0) {
        --previousLineEndedInCloseBrace;
    }
    if (previousLineEndedInOpenBrace > 0) {
        --previousLineEndedInOpenBrace;
    }
    if (previousLineWasEmpty > 0) {
        --previousLineWasEmpty;
    }
    s = $0;
    # remove DOS linefeeds
    gsub(lf, "", s);
    # replace strings
    gsub(/"(\\"|[^"\\]|\\[^"])*"/, "string", s);
    # replace single-quoted strings
    gsub(pattern, "string", s);
    # replace {: and :} in .cup files
    if (fname ~ /\.cup$/) {
        gsub(/{:/, "{", s);
        gsub(/:}/, "}", s);
        gsub(/:/, " : ", s);
    }
    if (inComment && $0 ~ /\*\//) {
        # end of multiline comment "*/"
        inComment = 0;
        gsub(/^.*\*\//, "/* comment */", s);
    } else if (inComment) {
        s = "/* comment */";
    } else if ($0 ~ /\/\*/ && $0 !~ /\/\*.*\*\//) {
        # beginning of multiline comment "/*"
        inComment = 1;
        gsub(/\/\*.*$/, "/* comment */", s);
    } else {
        # mask out /* */ comments
        gsub(/\/\*.*\*\//, "/* comment */", s);
    }
    if (s ~ /\/\/\$NON-NLS/) {
        error(fname, FNR, "NON-NLS not allowed");
    }
    # mask out // comments
    gsub(/\/\/.*$/, "// comment", s);
    # line starts with string or plus?
    if (s ~ /^ *string/ \
        && s !~ /)/)
    {
        stringCol = index(s, "string");
    } else if (s ~ /^ *[+] string/) {
        if (stringCol != 0 && index(s, "+") != stringCol) {
            error(fname, FNR, "String '+' must be aligned with string on line above");
        }
    } else if (s ~ /comment/) {
        # in comment; string target carries forward
    } else {
        stringCol = 0;
    }
}
/ $/ {
    error(fname, FNR, "Line ends in space");
}
/[\t]/ {
    if (matchFile) {
        error(fname, FNR, "Tab character");
    }
}
/[\r]/ {
    if (matchFile) {
        error(fname, FNR, "Carriage return character (file is in DOS format?)");
    }
}
/./ {
    lastNonEmptyLine = $0;
}
{
    # Rules beyond this point only apply to Java and C++.
    if (!isCpp && !isJava) {
        next;
    }
}

/^$/ {
    if (matchFile && previousLineEndedInOpenBrace) {
        error(fname, FNR, "Empty line following open brace");
    }
}
/^ +}( catch| finally| while|[;,)])/ ||
/^ +}$/ {
    if (matchFile && previousLineWasEmpty) {
        error(fname, FNR - 1, "Empty line before close brace");
    }
}
s ~ /\<if\>.*;$/ {
    if (!matchFile) {}
    else {
        error(fname, FNR, "if followed by statement on same line");
    }
}
s ~ /\<(if) *\(/ {
    if (!matchFile) {
    } else if (s !~ /\<(if) /) {
        error(fname, FNR, "if must be followed by space");
    } else if (s ~ / else if /) {
    } else if (s ~ /^#if /) {
    } else if (s !~ /^(    )*(if)/) {
        error(fname, FNR, "if must be correctly indented");
    }
}
s ~ /\<(while) *\(/ {
    if (!matchFile) {
    } else if (s !~ /\<(while) /) {
        error(fname, FNR, "while must be followed by space");
    } else if (s ~ /} while /) {
    } else if (s !~ /^(    )+(while)/) {
        error(fname, FNR, "while must be correctly indented");
    }
}
s ~ /\<(for|switch|synchronized|} catch) *\(/ {
    if (!matchFile) {}
    else if (s !~ /^(    )*(for|switch|synchronized|} catch)/) {
        error(fname, FNR, "for/switch/synchronized/catch must be correctly indented");
    } else if (s !~ /\<(for|switch|synchronized|} catch) /) {
        error(fname, FNR, "for/switch/synchronized/catch must be followed by space");
    }
}
s ~ /\<(if|while|for|switch|catch)\>/ {
    # Check single-line if statements, such as
    #   if (condition) return;
    # We recognize such statements because there are equal numbers of open and
    # close parentheses.
    opens = s;
    gsub(/[^(]/, "", opens);
    closes = s;
    gsub(/[^)]/, "", closes);
    if (!matchFile) {
    } else if (s ~ /{( *\/\/ comment)?$/) {
        # lines which end with { and optional comment are ok
    } else if (s ~ /{.*\\$/ && isCpp) {
        # lines which end with backslash are ok in c++ macros
    } else if (s ~ /} while/) {
        # lines like "} while (foo);" are ok
    } else if (s ~ /^#/) {
        # lines like "#if 0" are ok
    } else if (s ~ /if \(true|false\)/) {
        # allow "if (true)" and "if (false)" because they are
        # used for commenting
    } else if (!unmatchedOpenParens(s)  \
               && length($0) != 79      \
               && length($0) != 80)
    {
        error(fname, FNR, "single-line if/while/for/switch/catch must end in {");
    }
}
s ~ /[[:alnum:]]\(/ &&
s !~ /\<(if|while|for|switch|assert)\>/ {
    ss = s;
    while (match(ss, /[[:alnum:]]\(/)) {
        ss = substr(ss, RSTART + RLENGTH - 1);
        parens = ss;
        gsub(/[^()]/, "", parens);
        while (substr(parens, 1, 2) == "()") {
            parens = substr(parens, 3);
        }
        opens = parens;
        gsub(/[^(]/, "", opens);
        closes = parens;
        gsub(/[^)]/, "", closes);
        if (length(opens) > length(closes)) {
            if (ss ~ /,$/) {
                bras = ss;
                gsub(/[^<]/, "", bras);
                kets = ss;
                gsub(/->/, "", kets);
                gsub(/[^>]/, "", kets);
                if (length(bras) > length(kets)) {
                    # Ignore case like 'for (Map.Entry<Foo,{nl} Bar> entry : ...'
                } else if (s ~ / for /) {
                    # Ignore case like 'for (int i = 1,{nl} j = 2; i < j; ...'
                } else {
                    error(                                              \
                        fname, FNR,                                     \
                        "multi-line parameter list should start with newline");
                    break;
                }
            } else if (s ~ /[;(]( *\\)?$/) {
                # If open paren is at end of line (with optional backslash
                # for macros), we're fine.
            } else if (s ~ /@.*\({/) {
                # Ignore Java annotations.
            } else {
                error(                                                  \
                    fname, FNR,                                         \
                    "Open parenthesis should be at end of line (function call spans several lines)");
                break;
            }
        }
        ss = substr(ss, 2); # remove initial "("
    }
}
s ~ /\<switch\>/ {
    push(switchCol);
    switchCol = index($0, "switch");
}
s ~ /{/ {
    braceCol = index($0, "{");
    if (braceCol == switchCol) {
        push(switchCol);
    }
}
s ~ /}/ {
    braceCol = index($0, "}");
    if (braceCol == switchCol) {
        switchCol = pop();
    }
}
s ~ /\<(case|default)\>/ {
    caseDefaultCol = match($0, /case|default/);
    if (!matchFile) {}
    else if (caseDefaultCol != switchCol) {
        error(fname, FNR, "case/default must be aligned with switch");
    }
}
s ~ /\<assert\>/ {
    if (!matchFile) {}
    else if (isCpp) {} # rule only applies to java
    else if (s !~ /^(    )+(assert)/) {
        error(fname, FNR, "assert must be correctly indented");
    } else if (s !~ /\<assert /) {
        error(fname, FNR, "assert must be followed by space");
    }
}
s ~ /\<return\>/ {
    if (!matchFile) {}
    else if (isCpp && s ~ /^#/) {
        # ignore macros
    } else if (s !~ /^(    )+(return)/) {
        error(fname, FNR, "return must be correctly indented");
    } else if (s !~ /\<return[ ;]/ && s !~ /\<return$/) {
        error(fname, FNR, "return must be followed by space or ;");
    }
}
s ~ /\<throw\>/ {
    if (!matchFile) {}
    else if (isCpp) {
        # cannot yet handle C++ cases like 'void foo() throw(int)'
    } else if (s !~ /^(    )+(throw)/) {
        error(fname, FNR, "throw must be correctly indented");
    } else if (s !~ /\<throw / && s !~ /\<throw$/) {
        error(fname, FNR, "throw must be followed by space");
    }
}
s ~ /\<else\>/ {
    if (!matchFile) {}
    else if (isCpp && s ~ /^# *else$/) {} # ignore "#else"
    else if (s !~ /^(    )+} else (if |{$|{ *\/\/|{ *\/\*)/) {
        error(fname, FNR, "else must be preceded by } and followed by { or if and correctly indented");
    }
}
s ~ /\<do\>/ {
    if (!matchFile) {}
    else if (s !~ /^(    )*do {/) {
        error(fname, FNR, "do must be followed by space {, and correctly indented");
    }
}
s ~ /\<try\>/ {
    if (!matchFile) {}
    else if (s !~ /^(    )+try {/) {
        error(fname, FNR, "try must be followed by space {, and correctly indented");
    }
}
s ~ /\<catch\>/ {
    if (!matchFile) {}
    else if (s !~ /^(    )+} catch /) {
        error(fname, FNR, "catch must be preceded by }, followed by space, and correctly indented");
    }
}
s ~ /\<finally\>/ {
    if (!matchFile) {}
    else if (s !~ /^(    )+} finally {/) {
        error(fname, FNR, "finally must be preceded by }, followed by space {, and correctly indented");
    }
}
match(s, /([]A-Za-z0-9()])(+|-|\*|\^|\/|%|=|==|+=|-=|\*=|\/=|>=|<=|!=|&|&&|\||\|\||^|\?|:) *[A-Za-z0-9(]/, a) {
    # < and > are not handled here - they have special treatment below
    if (!matchFile) {}
#    else if (s ~ /<.*>/) {} # ignore templates
    else if (a[2] == "-" && s ~ /\(-/) {} # ignore case "foo(-1)"
    else if (a[2] == "-" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e-5
    else if (a[2] == "+" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e+5
    else if (a[2] == ":" && s ~ /(case.*|default):$/) {} # ignore e.g. "case 5:"
    else if (isCpp && s ~ /[^ ][*&]/) {} # ignore e.g. "Foo* p;" in c++ - debatable
    else if (isCpp && s ~ /\<operator.*\(/) {} # ignore e.g. "operator++()" in c++
    else if (isCpp && a[2] == "/" && s ~ /#include/) {} # ignore e.g. "#include <x/y.hpp>" in c++
    else {
        error(fname, FNR, "operator '" a[2] "' must be preceded by space");
    }
}
match(s, /([]A-Za-z0-9() ] *)(+|-|\*|\^|\/|%|=|==|+=|-=|\*=|\/=|>=|<=|!=|&|&&|\||\|\||^|\?|:|,)[A-Za-z0-9(]/, a) {
    if (!matchFile) {}
#    else if (s ~ /<.*>/) {} # ignore templates
    else if (a[2] == "-" && s ~ /(\(|return |case |= )-/) {} # ignore prefix -
    else if (a[2] == ":" && s ~ /(case.*|default):$/) {} # ignore e.g. "case 5:"
    else if (s ~ /, *-/) {} # ignore case "foo(x, -1)"
    else if (s ~ /-[^ ]/ && s ~ /[^A-Za-z0-9] -/) {} # ignore case "x + -1" but not "x -1" or "3 -1"
    else if (a[2] == "-" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e-5
    else if (a[2] == "+" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e+5
    else if (a[2] == "*" && isCpp && s ~ /\*[^ ]/) {} # ignore e.g. "Foo *p;" in c++
    else if (a[2] == "&" && isCpp && s ~ /&[^ ]/) {} # ignore case "foo(&x)" in c++
    else if (isCpp && s ~ /\<operator[^ ]+\(/) {} # ignore e.g. "operator++()" in c++
    else if (isCpp && a[2] == "/" && s ~ /#include/) {} # ignore e.g. "#include <x/y.hpp>" in c++
    else if (lenient && fname ~ /(fennel)/ && a[1] = ",") {} # not enabled yet
    else {
        error(fname, FNR, "operator '" a[2] "' must be followed by space");
    }
}
match(s, /( )(,)/, a) {
    # (, < and > are not handled here - they have special treatment below
    if (!matchFile) {}
    else {
        error(fname, FNR, "operator '" a[2] "' must not be preceded by space");
    }
}
match(s, / (+|-|\*|\/|==|>=|<=|!=|<<|<<<|>>|&|&&|\|\||\?|:)$/, a) || \
match(s, /(\.|->)$/, a) {
    if (lenient && fname ~ /(aspen)/ && a[1] != ":") {} # not enabled yet
    else if (lenient && fname ~ /(fennel|farrago|aspen)/ && a[1] = "+") {} # not enabled yet
    else if (a[1] == ":" && s ~ /(case.*|default):$/) {
        # ignore e.g. "case 5:"
    } else if ((a[1] == "*" || a[1] == "&") && isCpp && s ~ /^[[:alnum:]:_ ]* [*&]$/) {
        # ignore e.g. "const int *\nClass::Subclass2::method(int x)"
    } else {
        error(fname, FNR, "operator '" a[1] "' must not be at end of line");
    }
}
match(s, /^ *(=) /, a) {
    error(fname, FNR, "operator '" a[1] "' must not be at start of line");
}
match(s, /([[:alnum:]~]+)( )([(])/, a) {
    # (, < and > are not handled here - they have special treatment below
    if (!matchFile) {}
    else if (isJava && a[1] ~ /\<(if|while|for|catch|switch|case|return|throw|synchronized|assert)\>/) {}
    else if (isCpp && a[1] ~ /\<(if|while|for|catch|switch|case|return|throw|operator|void|PBuffer)\>/) {}
    else if (isCpp && s ~ /^#define /) {}
    else {
        error(fname, FNR, "there must be no space before '" a[3] "' in fun call or fun decl");
    }
}
s ~ /\<[[:digit:][:lower:]][[:alnum:]_]*</ {
    # E.g. "p<" but not "Map<"
    if (!matchFile) {}
    else if (isCpp) {} # in C++ 'xyz<5>' could be a template
    else {
        error(fname, FNR, "operator '<' must be preceded by space");
    }
}
s ~ /\<[[:digit:][:lower:]][[:alnum:]_]*>/ {
    # E.g. "g>" but not "String>" as in "List<String>"
    if (!matchFile) {}
    else if (isCpp) {} # in C++ 'xyz<int>' could be a template
    else {
        error(fname, FNR, "operator '>' must be preceded by space");
    }
}
match(s, /<([[:digit:][:lower:]][[:alnum:].]*)\>/, a) {
    if (!matchFile) {}
    else if (isCpp) {
        # in C++, template and include generate too many false positives
    } else if (isJava && a[1] ~ /(int|char|long|boolean|byte|double|float)/) {
        # Allow e.g. 'List<int[]>'
    } else if (isJava && a[1] ~ /^[[:lower:]]+\./) {
        # Allow e.g. 'List<java.lang.String>'
    } else {
        error(fname, FNR, "operator '<' must be followed by space");
    }
}
match(s, /^(.*[^-])>([[:digit:][:lower:]][[:alnum:]]*)\>/, a) {
    if (!matchFile) {}
    else if (isJava && a[1] ~ /.*\.<.*/) {
        # Ignore 'Collections.<Type>member'
    } else {
        error(fname, FNR, "operator '>' must be followed by space");
    }
}
s ~ /[[(] / {
    if (!matchFile) {}
    else if (s ~ /[[(] +\\$/) {} # ignore '#define foo(   \'
    else {
        error(fname, FNR, "( or [ must not be followed by space");
    }
}
s ~ / [])]/ {
    if (!matchFile) {}
    else if (s ~ /^ *\)/ && previousLineEndedInCloseBrace) {} # ignore "bar(new Foo() { } );"
    else {
        error(fname, FNR, ") or ] must not be followed by space");
    }
}
s ~ /}/ {
    if (!matchFile) {}
    else if (s !~ /}( |;|,|$|\))/) {
        error(fname, FNR, "} must be followed by space");
    } else if (s !~ /(    )*}/) {
        error(fname, FNR, "} must be at start of line and correctly indented");
    }
}
s ~ /{/ {
    if (!matchFile) {}
    else if (s ~ /(\]\)?|=) *{/) {} # ignore e.g. "(int[]) {1, 2}" or "int[] x = {1, 2}"
    else if (s ~ /\({/) {} # ignore e.g. @SuppressWarnings({"unchecked"})
    else if (s ~ /{ *(\/\/|\/\*)/) {} # ignore e.g. "do { // a comment"
    else if (s ~ / {}$/) {} # ignore e.g. "Constructor() {}"
    else if (s ~ / },$/) {} # ignore e.g. "{ yada },"
    else if (s ~ / };$/) {} # ignore e.g. "{ yada };"
    else if (s ~ / {};$/) {} # ignore e.g. "template <> class Foo<int> {};"
    else if (s ~ / },? *\/\/.*$/) {} # ignore e.g. "{ yada }, // comment"
    else if (s ~ /\\$/) {} # ignore multiline macros
    else if (s ~ /{}/) { # e.g. "Constructor(){}"
        error(fname, FNR, "{} must be preceded by space and at end of line");
    } else if (isCpp && s ~ /{ *\\$/) {
        # ignore - "{" can be followed by "\" in c macro
    } else if (s !~ /{$/) {
        error(fname, FNR, "{ must be at end of line");
    } else if (s !~ /(^| ){/) {
        error(fname, FNR, "{ must be preceded by space or at start of line");
    } else {
        opens = s;
        gsub(/[^(]/, "", opens);
        closes = s;
        gsub(/[^)]/, "", closes);
        if (0 && lenient && fname ~ /aspen/) {} # not enabled
        else if (length(closes) > length(opens)) {
            error(fname, FNR, "Open brace should be on new line (function call/decl spans several lines)");
        }
    }
}
s ~ /(^| )(class|interface|enum) / ||
s ~ /(^| )namespace / && isCpp {
    if (isCpp && s ~ /;$/) {} # ignore type declaration
    else {
        classDeclStartLine = FNR;
        t = s;
        gsub(/.*(class|interface|enum|namespace) /, "", t);
        gsub(/ .*$/, "", t);
        if (s ~ /template/) {
            # ignore case "template <class INSTCLASS> static void foo()"
            classDeclStartLine = 0;
        } else if (t ~ /[[:upper:]][[:upper:]][[:upper:]][[:upper:]]/     \
            && t !~ /LRU/ \
            && t !~ /WAL/ \
            && t !~ /classUUID/ \
            && t !~ /classSQLException/ \
            && t !~ /BBRC/ \
            && t !~ /_/ \
            && t !~ /EncodedSqlInterval/)
        {
            error(fname, FNR, "Class name " t " has consecutive uppercase letters");
        }
    }
}
s ~ / throws\>/ {
    if (s ~ /\(/) {
        funDeclStartLine = FNR;
    } else {
        funDeclStartLine = FNR - 1;
    }
}
length($0) > maxLineLength                      \
&& $0 !~ /@(throws|see|link)/                   \
&& $0 !~ /\$Id: /                               \
&& $0 !~ /^import /                             \
&& $0 !~ /http:/                                \
&& $0 !~ /\/\/ Expect "/                        \
&& s !~ /^ *(\+ |<< )?string\)?[;,]?$/ {
    error( \
        fname, \
        FNR, \
        "Line length (" length($0) ") exceeds " maxLineLength " chars");
}
/}$/ {
    previousLineEndedInCloseBrace = 2;
}
/;$/ {
    funDeclStartLine = 0;
}
/{$/ {
    # Ignore open brace if it is part of class or interface declaration.
    if (classDeclStartLine) {
        if (classDeclStartLine < FNR \
            && $0 !~ /^ *{$/)
        {
            error(fname, FNR, "Open brace should be on new line (class decl spans several lines)");
        }
        classDeclStartLine = 0;
    } else {
        previousLineEndedInOpenBrace = 2;
    }
    if (funDeclStartLine) {
        if (funDeclStartLine < FNR \
            && $0 !~ /^ *{$/)
        {
            if (lenient && fname ~ /aspen/) {} # not enabled
            else error(fname, FNR, "Open brace should be on new line (function decl spans several lines)");
        }
        funDeclStartLine = 0;
    }
}
/^$/ {
    previousLineWasEmpty = 2;
}
{
    next;
}
END {
    afterFile();
}

# End checkFile.awk

#!/bin/gawk
# $Id: //open/util/bin/checkFile#13 $
# Checks that a file is valid.

function error(fname, linum, msg) {
    printf "%s: %d: %s\n", fname, linum, msg;
    if (0) print; # for debug
}
function _matchFile(fname) {
    return fname ~ "/mondrian/" \
       || fname ~ "/org/olap4j/" \
       || fname ~ "/aspen/" \
       || fname ~ "/farrago/" \
       || fname ~ "/fennel/" \
       || fname ~ "/com/sqlstream/" \
       || !lenient;
}
function _isCpp(fname) {
    return fname ~ /\.(cpp|h)$/;
}
function _isJava(fname) {
    return fname ~ /\.(java|jj)$/;
}
function push(val) {
    switchStack[switchStackLen++] = val;
}
function pop() {
    --switchStackLen
    val = switchStack[switchStackLen];
    delete switchStack[switchStackLen];
    return val;
}
BEGIN {
    # pre-compute regexp for quotes, linefeed
    apos = sprintf("%c", 39);
    quot = sprintf("%c", 34);
    lf = sprintf("%c", 13);
    pattern = apos "(\\" apos "|[^" apos "])" apos;
    if (0) printf "maxLineLength=%s lenient=%s\n", maxLineLength, lenient;
}
FNR == 1 {
    fname = FILENAME;
    matchFile = _matchFile(fname);
    isCpp = _isCpp(fname);
    isJava = _isJava(fname);
}
{
    if (previousLineEndedInCloseBrace > 0) {
        --previousLineEndedInCloseBrace;
    }
    if (previousLineEndedInOpenBrace > 0) {
        --previousLineEndedInOpenBrace;
    }
    if (previousLineWasEmpty > 0) {
        --previousLineWasEmpty;
    }
    s = $0;
    # remove DOS linefeeds
    gsub(lf, "", s);
    # replace strings
    gsub(/"(\\"|[^"\\]|\\[^"])*"/, "string", s);
    # replace single-quoted strings
    gsub(pattern, "string", s);
    # replace {: and :} in .cup files
    if (fname ~ /\.cup$/) {
        gsub(/{:/, "{", s);
        gsub(/:}/, "}", s);
        gsub(/:/, " : ", s);
    }
    if (inComment && $0 ~ /\*\//) {
        # end of multiline comment "*/"
        inComment = 0;
        gsub(/^.*\*\//, "/* comment */", s);
    } else if (inComment) {
        s = "/* comment */";
    } else if ($0 ~ /\/\*/ && $0 !~ /\/\*.*\*\//) {
        # beginning of multiline comment "/*"
        inComment = 1;
        gsub(/\/\*.*$/, "/* comment */", s);
    } else {
        # mask out /* */ comments
        gsub(/\/\*.*\*\//, "/* comment */", s);
    }
    if (s ~ /\/\/\$NON-NLS/) {
        error(fname, FNR, "NON-NLS not allowed");
    }
    # mask out // comments
    gsub(/\/\/.*$/, "// comment", s);
    # line starts with string or plus?
    if (s ~ /^ *string/ \
        && s !~ /)/)
    {
        stringCol = index(s, "string");
    } else if (s ~ /^ *[+] string/) {
        if (stringCol != 0 && index(s, "+") != stringCol) {
            error(fname, FNR, "String '+' must be aligned with string on line above");
        }
    } else if (s ~ /comment/) {
        # in comment; string target carries forward
    } else {
        stringCol = 0;
    }
}
/ $/ {
    error(fname, FNR, "Line ends in space");
}
/[\t]/ {
    if (matchFile) {
        error(fname, FNR, "Tab character");
    }
}
/[\r]/ {
    if (matchFile) {
        error(fname, FNR, "Carriage return character (file is in DOS format?)");
    }
}
{
    # Rules beyond this point only apply to Java and C++.
    if (!isCpp && !isJava) {
        next;
    }
}

/^$/ {
    if (matchFile && previousLineEndedInOpenBrace) {
        error(fname, FNR, "Empty line following open brace");
    }
}
/^ +}( catch| finally| while|[;,)])/ ||
/^ +}$/ {
    if (matchFile && previousLineWasEmpty) {
        error(fname, FNR - 1, "Empty line before close brace");
    }
}
s ~ /\<if\>.*;$/ {
    if (!matchFile) {}
    else {
        error(fname, FNR, "if followed by statement on same line");
    }
}
s ~ /\<(if) *\(/ {
    if (!matchFile) {
    } else if (s !~ /\<(if) /) {
        error(fname, FNR, "if must be followed by space");
    } else if (s ~ / else if /) {
    } else if (s ~ /^#if /) {
    } else if (s !~ /^(    )*(if)/) {
        error(fname, FNR, "if must be correctly indented");
    }
}
s ~ /\<(while) *\(/ {
    if (!matchFile) {
    } else if (s !~ /\<(while) /) {
        error(fname, FNR, "while must be followed by space");
    } else if (s ~ /} while /) {
    } else if (s !~ /^(    )+(while)/) {
        error(fname, FNR, "while must be correctly indented");
    }
}
s ~ /\<(for|switch|synchronized|} catch) *\(/ {
    if (!matchFile) {}
    else if (s !~ /^(    )*(for|switch|synchronized|} catch)/) {
        error(fname, FNR, "for/switch/synchronized/catch must be correctly indented");
    } else if (s !~ /\<(for|switch|synchronized|} catch) /) {
        error(fname, FNR, "for/switch/synchronized/catch must be followed by space");
    }
}
s ~ /\<(if|while|for|switch)\>/ {
    # Check single-line if statements, such as
    #   if (condition) return;
    # We recognize such statements because there are equal numbers of open and
    # close parentheses.
    opens = s;
    gsub(/[^(]/, "", opens);
    closes = s;
    gsub(/[^)]/, "", closes);
    if (!matchFile) {
    } else if (s ~ /{( *\/\/ comment)?$/) {
        # lines which end with { and optional comment are ok
    } else if (s ~ /{.*\\$/ && isCpp) {
        # lines which end with backslash are ok in c++ macros
    } else if (s ~ /} while/) {
        # lines like "} while (foo);" are ok
    } else if (s ~ /^#/) {
        # lines like "#if 0" are ok
    } else if (s ~ /if \(true|false\)/) {
        # allow "if (true)" and "if (false)" because they are
        # used for commenting
    } else if (length(opens) == length(closes)  \
               && length($0) != 79              \
               && length($0) != 80)
    {
        error(fname, FNR, "single-line if/while/for/switch must end in {");
    }
}
s ~ /[[:alnum:]]\(/ &&
s !~ /\<(if|while|for|switch|assert)\>/ {
    ss = s;
    while (match(ss, /[[:alnum:]]\(/)) {
        ss = substr(ss, RSTART + RLENGTH - 1);
        parens = ss;
        gsub(/[^()]/, "", parens);
        while (substr(parens, 1, 2) == "()") {
            parens = substr(parens, 3);
        }
        opens = parens;
        gsub(/[^(]/, "", opens);
        closes = parens;
        gsub(/[^)]/, "", closes);
        if (length(opens) > length(closes)) {
            if (ss ~ /,$/) {
                bras = ss;
                gsub(/[^<]/, "", bras);
                kets = ss;
                gsub(/->/, "", kets);
                gsub(/[^>]/, "", kets);
                if (length(bras) > length(kets)) {
                    # Ignore case like 'for (Map.Entry<Foo,{nl} Bar> entry : ...'
                } else if (s ~ / for /) {
                    # Ignore case like 'for (int i = 1,{nl} j = 2; i < j; ...'
                } else {
                    error(                                              \
                        fname, FNR,                                     \
                        "multi-line parameter list should start with newline");
                    break;
                }
            } else if (s ~ /[;(]( *\\)?$/) {
                # If open paren is at end of line (with optional backslash
                # for macros), we're fine.
            } else if (s ~ /@.*\({/) {
                # Ignore Java annotations.
            } else {
                error(                                                  \
                    fname, FNR,                                         \
                    "Open parenthesis should be at end of line (function call spans several lines)");
                break;
            }
        }
        ss = substr(ss, 2); # remove initial "("
    }
}
s ~ /\<switch\>/ {
    push(switchCol);
    switchCol = index($0, "switch");
}
s ~ /{/ {
    braceCol = index($0, "{");
    if (braceCol == switchCol) {
        push(switchCol);
    }
}
s ~ /}/ {
    braceCol = index($0, "}");
    if (braceCol == switchCol) {
        switchCol = pop();
    }
}
s ~ /\<(case|default)\>/ {
    caseDefaultCol = match($0, /case|default/);
    if (!matchFile) {}
    else if (caseDefaultCol != switchCol) {
        error(fname, FNR, "case/default must be aligned with switch");
    }
}
s ~ /\<assert\>/ {
    if (!matchFile) {}
    else if (isCpp) {} # rule only applies to java
    else if (s !~ /^(    )+(assert)/) {
        error(fname, FNR, "assert must be correctly indented");
    } else if (s !~ /\<assert /) {
        error(fname, FNR, "assert must be followed by space");
    }
}
s ~ /\<return\>/ {
    if (!matchFile) {}
    else if (isCpp && s ~ /^#/) {
        # ignore macros
    } else if (s !~ /^(    )+(return)/) {
        error(fname, FNR, "return must be correctly indented");
    } else if (s !~ /\<return[ ;]/ && s !~ /\<return$/) {
        error(fname, FNR, "return must be followed by space or ;");
    }
}
s ~ /\<throw\>/ {
    if (!matchFile) {}
    else if (isCpp) {
        # cannot yet handle C++ cases like 'void foo() throw(int)'
    } else if (s !~ /^(    )+(throw)/) {
        error(fname, FNR, "throw must be correctly indented");
    } else if (s !~ /\<throw / && s !~ /\<throw$/) {
        error(fname, FNR, "throw must be followed by space");
    }
}
s ~ /\<else\>/ {
    if (!matchFile) {}
    else if (isCpp && s ~ /^# *else$/) {} # ignore "#else"
    else if (s !~ /^(    )+} else (if |{$|{ *\/\/|{ *\/\*)/) {
        error(fname, FNR, "else must be preceded by } and followed by { or if and correctly indented");
    }
}
s ~ /\<do\>/ {
    if (!matchFile) {}
    else if (s !~ /^(    )*do {/) {
        error(fname, FNR, "do must be followed by space {, and correctly indented");
    }
}
s ~ /\<try\>/ {
    if (!matchFile) {}
    else if (s !~ /^(    )+try {/) {
        error(fname, FNR, "try must be followed by space {, and correctly indented");
    }
}
s ~ /\<catch\>/ {
    if (!matchFile) {}
    else if (s !~ /^(    )+} catch /) {
        error(fname, FNR, "catch must be preceded by }, followed by space, and correctly indented");
    }
}
s ~ /\<finally\>/ {
    if (!matchFile) {}
    else if (s !~ /^(    )+} finally {/) {
        error(fname, FNR, "finally must be preceded by }, followed by space {, and correctly indented");
    }
}
match(s, /([]A-Za-z0-9()])(+|-|\*|\^|\/|%|=|==|+=|-=|\*=|\/=|>=|<=|!=|&|&&|\||\|\||^|\?|:) *[A-Za-z0-9(]/, a) {
    # < and > are not handled here - they have special treatment below
    if (!matchFile) {}
#    else if (s ~ /<.*>/) {} # ignore templates
    else if (a[2] == "-" && s ~ /\(-/) {} # ignore case "foo(-1)"
    else if (a[2] == "-" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e-5
    else if (a[2] == "+" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e+5
    else if (a[2] == ":" && s ~ /(case.*|default):$/) {} # ignore e.g. "case 5:"
    else if (isCpp && s ~ /[^ ][*&]/) {} # ignore e.g. "Foo* p;" in c++ - debatable
    else if (isCpp && s ~ /\<operator.*\(/) {} # ignore e.g. "operator++()" in c++
    else if (isCpp && a[2] == "/" && s ~ /#include/) {} # ignore e.g. "#include <x/y.hpp>" in c++
    else {
        error(fname, FNR, "operator '" a[2] "' must be preceded by space");
    }
}
match(s, /([]A-Za-z0-9() ] *)(+|-|\*|\^|\/|%|=|==|+=|-=|\*=|\/=|>=|<=|!=|&|&&|\||\|\||^|\?|:|,)[A-Za-z0-9(]/, a) {
    if (!matchFile) {}
#    else if (s ~ /<.*>/) {} # ignore templates
    else if (a[2] == "-" && s ~ /(\(|return |case |= )-/) {} # ignore prefix -
    else if (a[2] == ":" && s ~ /(case.*|default):$/) {} # ignore e.g. "case 5:"
    else if (s ~ /, *-/) {} # ignore case "foo(x, -1)"
    else if (s ~ /-[^ ]/ && s ~ /[^A-Za-z0-9] -/) {} # ignore case "x + -1" but not "x -1" or "3 -1"
    else if (a[2] == "-" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e-5
    else if (a[2] == "+" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e+5
    else if (a[2] == "*" && isCpp && s ~ /\*[^ ]/) {} # ignore e.g. "Foo *p;" in c++
    else if (a[2] == "&" && isCpp && s ~ /&[^ ]/) {} # ignore case "foo(&x)" in c++
    else if (isCpp && s ~ /\<operator[^ ]+\(/) {} # ignore e.g. "operator++()" in c++
    else if (isCpp && a[2] == "/" && s ~ /#include/) {} # ignore e.g. "#include <x/y.hpp>" in c++
    else if (lenient && fname ~ /(fennel)/ && a[1] = ",") {} # not enabled yet
    else {
        error(fname, FNR, "operator '" a[2] "' must be followed by space");
    }
}
match(s, /( )(,)/, a) {
    # (, < and > are not handled here - they have special treatment below
    if (!matchFile) {}
    else {
        error(fname, FNR, "operator '" a[2] "' must not be preceded by space");
    }
}
match(s, / (+|-|\*|\/|==|>=|<=|!=|<<|<<<|>>|&|&&|\|\||\?|:)$/, a) || \
match(s, /(\.|->)$/, a) {
    if (lenient && fname ~ /(aspen)/ && a[1] != ":") {} # not enabled yet
    else if (lenient && fname ~ /(fennel|farrago|aspen)/ && a[1] = "+") {} # not enabled yet
    else if (a[1] == ":" && s ~ /(case.*|default):$/) {
        # ignore e.g. "case 5:"
    } else if ((a[1] == "*" || a[1] == "&") && isCpp && s ~ /^[[:alnum:]:_ ]* [*&]$/) {
        # ignore e.g. "const int *\nClass::Subclass2::method(int x)"
    } else {
        error(fname, FNR, "operator '" a[1] "' must not be at end of line");
    }
}
match(s, /^ *(=) /, a) {
    error(fname, FNR, "operator '" a[1] "' must not be at start of line");
}
match(s, /([[:alnum:]~]+)( )([(])/, a) {
    # (, < and > are not handled here - they have special treatment below
    if (!matchFile) {}
    else if (isJava && a[1] ~ /\<(if|while|for|catch|switch|case|return|throw|synchronized|assert)\>/) {}
    else if (isCpp && a[1] ~ /\<(if|while|for|catch|switch|case|return|throw|operator|void|PBuffer)\>/) {}
    else if (isCpp && s ~ /^#define /) {}
    else {
        error(fname, FNR, "there must be no space before '" a[3] "' in fun call or fun decl");
    }
}
s ~ /\<[[:digit:][:lower:]][[:alnum:]_]*</ {
    # E.g. "p<" but not "Map<"
    if (!matchFile) {}
    else if (isCpp) {} # in C++ 'xyz<5>' could be a template
    else {
        error(fname, FNR, "operator '<' must be preceded by space");
    }
}
s ~ /\<[[:digit:][:lower:]][[:alnum:]_]*>/ {
    # E.g. "g>" but not "String>" as in "List<String>"
    if (!matchFile) {}
    else if (isCpp) {} # in C++ 'xyz<int>' could be a template
    else {
        error(fname, FNR, "operator '>' must be preceded by space");
    }
}
match(s, /<([[:digit:][:lower:]][[:alnum:].]*)\>/, a) {
    if (!matchFile) {}
    else if (isCpp) {
        # in C++, template and include generate too many false positives
    } else if (isJava && a[1] ~ /(int|char|long|boolean|byte|double|float)/) {
        # Allow e.g. 'List<int[]>'
    } else if (isJava && a[1] ~ /^[[:lower:]]+\./) {
        # Allow e.g. 'List<java.lang.String>'
    } else {
        error(fname, FNR, "operator '<' must be followed by space");
    }
}
match(s, /^(.*[^-])>([[:digit:][:lower:]][[:alnum:]]*)\>/, a) {
    if (!matchFile) {}
    else if (isJava && a[1] ~ /.*\.<.*/) {
        # Ignore 'Collections.<Type>member'
    } else {
        error(fname, FNR, "operator '>' must be followed by space");
    }
}
s ~ /[[(] / {
    if (!matchFile) {}
    else if (s ~ /[[(] +\\$/) {} # ignore '#define foo(   \'
    else {
        error(fname, FNR, "( or [ must not be followed by space");
    }
}
s ~ / [])]/ {
    if (!matchFile) {}
    else if (s ~ /^ *\)/ && previousLineEndedInCloseBrace) {} # ignore "bar(new Foo() { } );"
    else {
        error(fname, FNR, ") or ] must not be followed by space");
    }
}
s ~ /}/ {
    if (!matchFile) {}
    else if (s !~ /}( |;|,|$|\))/) {
        error(fname, FNR, "} must be followed by space");
    } else if (s !~ /(    )*}/) {
        error(fname, FNR, "} must be at start of line and correctly indented");
    }
}
s ~ /{/ {
    if (!matchFile) {}
    else if (s ~ /(\]\)?|=) *{/) {} # ignore e.g. "(int[]) {1, 2}" or "int[] x = {1, 2}"
    else if (s ~ /\({/) {} # ignore e.g. @SuppressWarnings({"unchecked"})
    else if (s ~ /{ *(\/\/|\/\*)/) {} # ignore e.g. "do { // a comment"
    else if (s ~ / {}$/) {} # ignore e.g. "Constructor() {}"
    else if (s ~ / },$/) {} # ignore e.g. "{ yada },"
    else if (s ~ / };$/) {} # ignore e.g. "{ yada };"
    else if (s ~ / {};$/) {} # ignore e.g. "template <> class Foo<int> {};"
    else if (s ~ / },? *\/\/.*$/) {} # ignore e.g. "{ yada }, // comment"
    else if (s ~ /\\$/) {} # ignore multiline macros
    else if (s ~ /{}/) { # e.g. "Constructor(){}"
        error(fname, FNR, "{} must be preceded by space and at end of line");
    } else if (isCpp && s ~ /{ *\\$/) {
        # ignore - "{" can be followed by "\" in c macro
    } else if (s !~ /{$/) {
        error(fname, FNR, "{ must be at end of line");
    } else if (s !~ /(^| ){/) {
        error(fname, FNR, "{ must be preceded by space or at start of line");
    } else {
        opens = s;
        gsub(/[^(]/, "", opens);
        closes = s;
        gsub(/[^)]/, "", closes);
        if (0 && lenient && fname ~ /aspen/) {} # not enabled
        else if (length(closes) > length(opens)) {
            error(fname, FNR, "Open brace should be on new line (function call/decl spans several lines)");
        }
    }
}
s ~ /(^| )(class|interface|enum) / ||
s ~ /(^| )namespace / && isCpp {
    if (isCpp && s ~ /;$/) {} # ignore type declaration
    else {
        classDeclStartLine = FNR;
        t = s;
        gsub(/.*(class|interface|enum|namespace) /, "", t);
        gsub(/ .*$/, "", t);
        if (s ~ /template/) {
            # ignore case "template <class INSTCLASS> static void foo()"
            classDeclStartLine = 0;
        } else if (t ~ /[[:upper:]][[:upper:]][[:upper:]][[:upper:]]/     \
            && t !~ /LRU/ \
            && t !~ /WAL/ \
            && t !~ /classUUID/ \
            && t !~ /classSQLException/ \
            && t !~ /BBRC/ \
            && t !~ /_/ \
            && t !~ /EncodedSqlInterval/)
        {
            error(fname, FNR, "Class name " t " has consecutive uppercase letters");
        }
    }
}
s ~ / throws\>/ {
    if (s ~ /\(/) {
        funDeclStartLine = FNR;
    } else {
        funDeclStartLine = FNR - 1;
    }
}
length($0) > maxLineLength                      \
&& $0 !~ /@(throws|see|link)/                   \
&& $0 !~ /\$Id: /                               \
&& $0 !~ /^import /                             \
&& $0 !~ /http:/                                \
&& $0 !~ /\/\/ Expect "/                        \
&& s !~ /^ *(\+ |<< )?string\)?[;,]?$/ {
    error( \
        fname, \
        FNR, \
        "Line length (" length($0) ") exceeds " maxLineLength " chars");
}
/./ {
    lastNonEmptyLine = $0;
}
/}$/ {
    previousLineEndedInCloseBrace = 2;
}
/;$/ {
    funDeclStartLine = 0;
}
/{$/ {
    # Ignore open brace if it is part of class or interface declaration.
    if (classDeclStartLine) {
        if (classDeclStartLine < FNR \
            && $0 !~ /^ *{$/)
        {
            error(fname, FNR, "Open brace should be on new line (class decl spans several lines)");
        }
        classDeclStartLine = 0;
    } else {
        previousLineEndedInOpenBrace = 2;
    }
    if (funDeclStartLine) {
        if (funDeclStartLine < FNR \
            && $0 !~ /^ *{$/)
        {
            if (lenient && fname ~ /aspen/) {} # not enabled
            else error(fname, FNR, "Open brace should be on new line (function decl spans several lines)");
        }
        funDeclStartLine = 0;
    }
}
/^$/ {
    previousLineWasEmpty = 2;
}
{
    next;
}
END {
    # Compute basename. If fname="/foo/bar/baz.txt" then basename="baz.txt".
    basename = fname;
    gsub(".*/", "", basename);
    gsub(lf, "", lastNonEmptyLine);
    terminator = "// End " basename;
    if (matchFile && (lastNonEmptyLine != terminator)) {
        error(fname, FNR, sprintf("Last line should be %c%s%c", 39, terminator, 39));
    }
}

# End checkFile.awk


First working version of parser

First working version of parser

BEGIN {
    FS = "\t"
    printf ("Title\tPerson\tType\tRole\tEpisodes\tYears\n")
}

{
    web_scraper_start_url = $1
    Title = $2
    Years = $3
    Cast = $4
    Directors = $5
    Writers = $6
    person = ""
    role = ""
    num_episodes = ""
    episode_years = ""

    if (Cast == "" && Directors == "" && Writers == "")
        next

    if (NR == 1)
        next

    if (Cast != "") {
        type = "Actor"
        gsub (/[[:blank:]]{3,99}\(uncredited\)/," (uncredited)",Cast)
        gsub (/[[:blank:]]{3,99}\/ \.\.\./," / ...",Cast)
        extra = sub (/\(extra\) ?/,"",Cast)
        if (extra != 0)
            type = type " (extra)"
        uncredited = sub (/\(uncredited\) ?/,"",Cast)
        if (uncredited != 0)
            type = type " (uncredited)"
        nflds1 = split (Cast,fld,/[[:blank:]]{3,99}/)
        person = fld[1]
        role = fld[3]
        if (role ~ /^'/)
            role = "'" role
        sub (/\302\240/,"",role)
        episodes = fld[4]
        if (episodes !~ /episodes?/) {
            person = person " " episodes
        } else {
            nflds2 = split (episodes,fld,/,/)
            num_episodes = fld[1]
            sub (/ episodes?/,"",num_episodes)
            episode_years = fld[2]
            sub (/ /,"",episode_years)
        }
    }

    if (Directors != "") {
        type = "Director"
        nflds1 = split (Directors,fld,/[[:blank:]]{3,99}/)
        person = fld[1]
        episodes = fld[3]
        uncredited = sub (/\(uncredited\) /,"",episodes)
        if (uncredited != 0)
            type = type " (uncredited)"
        gsub (/[()]/,"",episodes)
        nflds2 = split (episodes,fld,/,/)
        num_episodes = fld[1]
        sub (/ episodes?/,"",num_episodes)
        episode_years = fld[2]
        sub (/ /,"",episode_years)
    }

    if (Writers != "") {
        type = "Writer"
        nflds1 = split (Writers,fld,/[[:blank:]]{3,99}/)
        person = fld[1]
        parens = fld[3]
        nparens = split (parens,fld,/[()]/)
        for ( i = 2; i < nparens-1; i+=2 ) {
            if (fld[i] != " ") {
                type = type " (" fld[i] ")"
            }
        }
        episodes = fld[nparens-1]
        if (episodes !~ /episodes?/) {
            type = type " (" episodes ")"
        } else {
            nflds2 = split (episodes,fld,/,/)
            num_episodes = fld[1]
            sub (/ episodes?/,"",num_episodes)
            episode_years = fld[2]
            sub (/ /,"",episode_years)
        }
    }

    printf ("=HYPERLINK(\"%s\";\"%s %s\"\)\t%s\t%s\t%s\t%s\t%s\n",web_scraper_start_url,Title,Years,person,type,role,\
                num_episodes,episode_years)

}

BEGIN {
    FS = "\t"
}

{
    web_scraper_start_url = $1
    Title = $2
    Years = $3
    Cast = $4
    Directors = $5
    Writers = $6
    person = ""
    role = ""
    num_episodes = ""
    episode_years = ""

    if (Cast == "" && Directors == "" && Writers == "")
        next

    if (NR == 1)
        next

    if (Cast != "") {
        type = "Actor"
        gsub (/[[:blank:]]{3,99}\(uncredited\)/," (uncredited)",Cast)
        gsub (/[[:blank:]]{3,99}\/ \.\.\./," / ...",Cast)
        extra = sub (/\(extra\) ?/,"",Cast)
        if (extra != 0)
            type = type " (extra)"
        uncredited = sub (/\(uncredited\) ?/,"",Cast)
        if (uncredited != 0)
            type = type " (uncredited)"
        nflds1 = split (Cast,fld,/[[:blank:]]{3,99}/)
        person = fld[1]
        role = fld[3]
        sub (/\302\240/,"",role)
        episodes = fld[4]
        if (episodes !~ /episodes?/) {
            person = person " " episodes
        } else {
            nflds2 = split (episodes,fld,/,/)
            num_episodes = fld[1]
            sub (/ episodes?/,"",num_episodes)
            episode_years = fld[2]
            sub (/ /,"",episode_years)
        }
    }

    if (Directors != "") {
        type = "Director"
        nflds1 = split (Directors,fld,/[[:blank:]]{3,99}/)
        person = fld[1]
        episodes = fld[3]
        uncredited = sub (/\(uncredited\) /,"",episodes)
        if (uncredited != 0)
            type = type " (uncredited)"
        gsub (/[()]/,"",episodes)
        nflds2 = split (episodes,fld,/,/)
        num_episodes = fld[1]
        sub (/ episodes?/,"",num_episodes)
        episode_years = fld[2]
        sub (/ /,"",episode_years)
    }

    if (Writers != "") {
        type = "Writer"
        nflds1 = split (Writers,fld,/[[:blank:]]{3,99}/)
        person = fld[1]
        parens = fld[3]
        nparens = split (parens,fld,/[()]/)
        for ( i = 2; i < nparens-1; i+=2 ) {
            if (fld[i] != " ") {
                type = type " (" fld[i] ")"
            }
        }
        episodes = fld[nparens-1]
        if (episodes !~ /episodes?/) {
            type = type " (" episodes ")"
        } else {
            nflds2 = split (episodes,fld,/,/)
            num_episodes = fld[1]
            sub (/ episodes?/,"",num_episodes)
            episode_years = fld[2]
            sub (/ /,"",episode_years)
        }
    }

    printf ("%s %s\t%s\t%s\t%s\t%s\t%s\n",Title,Years,person,type,role,num_episodes,episode_years)

}