#! /usr/bin/gawk -f
# Last edited on 2004-02-29 07:47:46 by stolfi

BEGIN {
  abort = -1;
  usage = ( "rugg-generator \\\n" \
    "  -v grilles='PMS PMS PMS ... PMS' \\\n" \
    "  -v tokens=NUM \\\n" \
    "  < INPUT.tbl > OUTPUT.txt " \
  ); 
  
  # Gordon Rugg's table-and-grille generator. The input must be a
  # table for Gordon Rugg's method, one entry per line with prefix,
  # medfix, and suffix separated by "_".
  # 
  # The {grilles} argument specifies the positions of the holes in
  # each grille, as three digits {P}, {M}, {S}. Each grille is used
  # for {N} successive words where {N} is the length of the table. The
  # {grilles} list is reused as often as needed
  
  # Check whether arguments were sepcified
  if (grilles == "") { arg_error("must define \"grilles\""); }
  if (tokens == "") { arg_error("must define \"tokens\""); }
  
  # Check grille syntax:
  if (grilles !~ /^[0-9][0-9][0-9]([ ][0-9][0-9][0-9])*$/) 
    { arg_error("invalid \"grilles\" argument"); }

  # Create empty table:
  split("", pre); split("", mid); split("", suf); nt = 0;
}

# Watch abort flag:
(abort >= 0) { exit abort; }

# Ignore comments and blank lines:
/^ *([\#]|$)/ { next; }

# Table must have three columns separated by 
(NF == 1) { 
  if (! match($0, /^([^_]*)[_]([^_]*)[_]([^_]*)$/, fld))
    { data_error(("bad table entry = [" $0 "]")); }
  pre[nt] = fld[1]; 
  mid[nt] = fld[2]; 
  suf[nt] = fld[3];
  nt++; 
  next;
}

# Anything else is error:
// { data_error(("bad input line [" $0 "]")); }

# After loading the table, generate the text:
END {
  # Check for errors in input:
  if (abort >= 0) { exit abort; }
  
  # Table must be non-empty
  if (nt == 0) { arg_error("empty table?"); }
  
  # To force the selection of a new grille (the first one):
  ng = length(grilles) + 1; used = nt;
  
  # Loop on output tokens:
  for (i = 0; i < tokens; i++)
    { # Have we exhausted this grille?
      if (used >= nt)
        { # Get new grille:
          ng += 4; 
          if (ng+3 > length(grilles)) { ng = 0; }
          pk = int(substr(grilles, ng+1, 1) * 13 + 0.5) % nt;
          mk = int(substr(grilles, ng+2, 1) * 13 + 0.5) % nt;
          sk = int(substr(grilles, ng+3, 1) * 13 + 0.5) % nt;
          used = 0; 
        }
      # Generate next word:
      print (pre[pk] mid[mk] suf[sk]); 
      
      # Advance the grille:
      pk = (pk + 1) % nt;
      mk = (mk + 1) % nt;
      sk = (sk + 1) % nt;
      used++;
    }
}

function arg_error(msg)
{
  printf "%s\n", msg > "/dev/stderr";
  printf "usage: %s\n", usage > "/dev/stderr";
  abort = 1;
  exit 1;
}

function data_error(msg)
{
  printf "line %d: %s\n", FNR, msg > "/dev/stderr";
  abort = 1; exit 1;
}