Building without perl

Peter Stuge stuge-openssh-unix-dev at cdy.org
Mon Dec 9 07:16:42 EST 2002


On Sat, Dec 07, 2002 at 09:47:21AM -0600, Ben Lindstrom wrote:
> Ermm.... I'm not sure I want to trust awk over multiple platforms.  It is
> bad enough that some vendors don't ship a tolerable awk to start with.
> 
> Of course I'll reserve judgement until I see it work on every platform
> without adding 3rd party software.

Ok, here we go.  Attached is an awk version of mdoc2man.pl.  Please test it
everywhere you can.  Runs fine here, using GNU awk with or without --posix.

While making this I also discovered two bugs in mdoc2man.pl: one typo and
one data loss.  I've gotten the account in Bugzilla activated, I'll file
them there separately.

The typo is an extra comma with multiple reference authors: "x, and y"

Data loss is in the Ic handler, it silently discarded the rest of the line,
ignoring any words following a comma or period.  The data loss bug only
manifests itself in sftp.1 in the text describing -b:
"..if any of the following commands fail: get, rm, and lmkdir."  as opposed
to "..fail: get, put, rename, ln, rm, mkdir, chdir, lchdir and lmkdir."

Please note that I didn't have any earlier knowledge of the input and the
output formats used and I don't think I have gained too much either.
I've made some observations on logic and syntax of the mdoc (nroff?) format
but that's it.  There may very well be errors in the script due to that.
(But they were probably present in the perl version too, in that case.)

However, the awk script produces the same output as mdoc2man.pl with the
exception of the two bugs mentioned, for all openssh .[1-9] files, using
much of the same logic as the perl version.

On a side note, I'm not very impressed by awk.  Sure, it takes a lot of work
out of text mangling with sh+sed, but if it isn't too portable anyway I'm
not sure how useful it really is..  I was also a bit annoyed that it doesn't
support nested actions, I wanted to use that at first, but had to switch to
a loop going over all words in the input line.  Oh well, I'm sure it's handy
for making reports.  :)

I just realized that the data loss bug might be a bug in the manpage as
well, where is that file format documented?


//Peter
-------------- next part --------------
#!/usr/bin/awk

BEGIN {
  optlist=0
  oldoptlist=0
  nospace=0
  synopsis=0
  reference=0
  block=0
  ext=0
  extopt=0
  literal=0
  line=""
}

function wtail() {
  retval=""
  while(w<nwords) {
    if(length(retval))
      retval=retval OFS
    retval=retval words[++w]
  }
  return retval
}

! /^\./ {
  print
  if(literal)
    print ".br"
  next
}

/^\.\\"/ { next }

{
  option=0
  parens=0
  sub("^\.","")
  nwords=split($0,words)
  for(w=1;w<=nwords;w++) {
    skip=0
    if(match(words[w],"^Li|Pf$")) {
      skip=1
    } else if(match(words[w],"^Xo$")) {
      skip=1
      ext=1
      if(length(line)&&!match(line,"[\n ]$"))
        line=line OFS
    } else if(match(words[w],"^Xc$")) {
      skip=1
      ext=0
      if(!extopt)
        line=line "\n"
      w=nwords
    } else if(match(words[w],"^Bd$")) {
      skip=1
      if(match(words[w+1],"-literal")) {
        literal=1
        line=line "\n"
        w=nwords
      }
    } else if(match(words[w],"^Ed$")) {
      skip=1
      literal=0
    } else if(match(words[w],"^Ns$")) {
      skip=1
      if(!nospace)
        nospace=1
      sub(" $","",line)
    } else if(match(words[w],"^No$")) {
      skip=1
      sub(" $","",line)
      line=line words[++w]
    } else if(match(words[w],"^Dq$")) {
      skip=1
      line=line "``"
      line=line words[++w]
      while(w<nwords&&!match(words[w+1],"^[\\.,]"))
        line=line OFS words[++w]
      line=line "''"
      if(!nospace&&match(words[w+1],"^[\\.,]"))
        nospace=1
    } else if(match(words[w],"^Sq|Ql$")) {
      skip=1
      line=line "`" words[++w] "'"
      if(!nospace&&match(words[w+1],"^[\\.,]"))
        nospace=1
    } else if(match(words[w],"^Oo$")) {
      skip=1
      extopt=1
      if(!nospace)
        nospace=1
      line=line "["
    } else if(match(words[w],"^Oc$")) {
      skip=1
      extopt=0
      line=line "]"
    }
    if(!skip) {
      if(!nospace&&length(line)&&!match(line,"[\n ]$"))
        line=line OFS
      if(nospace==1)
        nospace=0
    }
    if(match(words[w],"^Dd$")) {
      date=wtail()
      next
    } else if(match(words[w],"^Dt$")) {
      id=wtail()
      next
    } else if(match(words[w],"^Os$")) {
      line=line ".TH " id " \"" date "\" \"" wtail() "\""
    } else if(match(words[w],"^Sh$")) {
      line=line ".SH"
      synopsis=match(words[w+1],"SYNOPSIS")
    } else if(match(words[w],"^Xr$")) {
      line=line "\\fB" words[++w] "\\fP(" words[++w] ")" words[++w]
    } else if(match(words[w],"^Rs$")) {
      split("",refauthors)
      nrefauthors=0
      reftitle=""
      refissue=""
      refdate=""
      refopt=""
      reference=1
      next
    } else if(match(words[w],"^Re$")) {
      line=line "\n"
      for(i=nrefauthors-1;i>0;i--) {
        line=line refauthors[i]
        if(i>1)
          line=line ", "
      }
      if(nrefauthors>1)
        line=line " and "
      line=line refauthors[0] ", \\fI" reftitle "\\fP"
      if(length(refissue))
        line=line ", " refissue
      if(length(refdate))
        line=line ", " refdate
      if(length(refopt))
        line=line ", " refopt
      line=line "."
      reference=0
    } else if(reference) {
      if(match(words[w],"^%A$")) { refauthors[nrefauthors++]=wtail() }
      if(match(words[w],"^%T$")) {
        reftitle=wtail()
        sub("^\"","",reftitle)
        sub("\"$","",reftitle)
      }
      if(match(words[w],"^%N$")) { refissue=wtail() }
      if(match(words[w],"^%D$")) { refdate=wtail() }
      if(match(words[w],"^%O$")) { refopt=wtail() }
    } else if(match(words[w],"^Nm$")) {
      if(synopsis)
        line=line ".br\n"
      n=words[++w]
      if(!length(name))
        name=n
      if(!length(n))
        n=name
      line=line "\\fB" n "\\fP"
      if(!nospace&&match(words[w+1],"^[\\.,]"))
        nospace=1
    } else if(match(words[w],"^Nd$")) {
      line=line "\\- " wtail()
    } else if(match(words[w],"^Fl$")) {
      line=line "\\fB\\-" words[++w] "\\fP"
      if(!nospace&&match(words[w+1],"^[\\.,]"))
        nospace=1
    } else if(match(words[w],"^Ar$")) {
      line=line "\\fI"
      if(w==nwords)
        line=line "file ...\\fP"
      else {
        line=line words[++w] "\\fP"
        while(match(words[w+1],"^\\|$"))
          line=line OFS words[++w] " \\fI" words[++w] "\\fP"
      }
      if(!nospace&&match(words[w+1],"^[\\.,]"))
        nospace=1
    } else if(match(words[w],"^Cm$")) {
      line=line "\\fB" words[++w] "\\fP"
      while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
        line=line words[++w]
    } else if(match(words[w],"^Op$")) {
      option=1
      if(!nospace)
        nospace=1
      line=line "["
    } else if(match(words[w],"^Pp$")) {
      line=line "\n"
    } else if(match(words[w],"^Ss$")) {
      line=line ".SS"
    } else if(match(words[w],"^Pa$")&&!option) {
      line=line "\\fI"
      w++
      if(match(words[w],"^\\."))
        line=line "\\&"
      line=line words[w] "\\fP"
      while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
        line=line words[++w]
    } else if(match(words[w],"^Dv$")) {
      line=line ".BR"
    } else if(match(words[w],"^Em|Ev$")) {
      line=line ".IR"
    } else if(match(words[w],"^Pq$")) {
      line=line "("
      nospace=1
      parens=1
    } else if(match(words[w],"^S[xy]$")) {
      line=line ".B " wtail()
    } else if(match(words[w],"^Ic$")) {
      plain=1
      line=line "\\fB"
      while(w<nwords) {
        w++
        if(match(words[w],"^Op$")) {
          w++
          line=line "["
          words[nwords]=words[nwords] "]"
        }
        if(match(words[w],"^Ar$")) {
          line=line "\\fI" words[++w] "\\fP"
        } else if(match(words[w],"^[\\.,]")) {
          sub(" $","",line)
          if(plain) {
            line=line "\\fP"
            plain=0
          }
          line=line words[w]
        } else {
          if(!plain) {
            line=line "\\fB"
            plain=1
          }
          line=line words[w]
        }
        if(!nospace)
          line=line OFS
      }
      sub(" $","",line)
      if(plain)
        line=line "\\fP"
    } else if(match(words[w],"^Bl$")) {
      oldoptlist=optlist
      if(match(words[w+1],"-bullet"))
        optlist=1
      else if(match(words[w+1],"-enum")) {
        optlist=2
        enum=0
      } else if(match(words[w+1],"-tag"))
        optlist=3
      else if(match(words[w+1],"-item"))
        optlist=4
      else if(match(words[w+1],"-bullet"))
        optlist=1
      w=nwords
    } else if(match(words[w],"^El$")) {
      optlist=oldoptlist
    } else if(match(words[w],"^It$")&&optlist) {
      if(optlist==1)
        line=line ".IP \\(bu"
      else if(optlist==2)
        line=line ".IP " ++enum "."
      else if(optlist==3) {
        line=line ".TP\n"
        if(match(words[w+1],"^Pa|Ev$")) {
          line=line ".B"
          w++
        }
      } else if(optlist==4)
        line=line ".IP"
    } else if(match(words[w],"^Sm$")) {
      if(match(words[w+1],"off"))
        nospace=2
      else if(match(words[w+1],"on"))
        nospace=0
      w++
    } else if(!skip) {
      line=line words[w]
    }
  }
  if(match(line,"^\\.[^a-zA-Z]"))
    sub("^\\.","",line)
  if(parens)
    line=line ")"
  if(option)
    line=line "]"
  if(ext&&!extopt&&!match(line," $"))
    line=line OFS
  if(!ext&&!extopt&&length(line)) {
    sub("\n$","",line)
    print line
    line=""
  }
}


More information about the openssh-unix-dev mailing list