/*************************************************
*    The PMW Music Typesetter - 3rd incarnation  *
*************************************************/

/* Copyright (c) Philip Hazel, 1991 - 2010 */

/* Written by Philip Hazel, starting November 1991 */
/* This file last modified: December 2010 */


/* This file contains part III of the code for reading in a PMW score file. It
contains top-level code for reading in a bar. */


#include "pmwhdr.h"
#include "readhdr.h"



/* Key signatures tables giving the offsets of the accidentals, in order, for
initializing baraccs. */

static uschar tp_sharporder[] = { 5,0,7,2,9,4,11 };
static uschar tp_flatorder[]  = { 11,4,9,2,7,0,5 };



/*************************************************
*           Initialize accidentals table         *
*************************************************/

/* The baraccs table is used to hold the current accidental for a given "white
note" pitch, to enable an absolute pitch to be calculated. To enable the table
to be a byte table, the values are held offset by 2, so that, for example, 0 =>
double flat, and 3 => sharp. When transposition is happening, the baraccs table
is used for the input values, and baraccs_tp for the output values.

Arguments:
  ba         the table that is to be set (baraccs or baraccs_tp)
  key        the key signature
  
Returns:     nothing  
*/

void 
read_initbaraccs(uschar *ba, int key)
{
int i;
int value;
int countacc = main_keysigtable[key];
uschar *ordertab;

if (countacc >= 0)
  {
  ordertab = tp_sharporder;
  value = 3;
  }
else
  {
  ordertab = tp_flatorder;
  value = 1;
  countacc = -countacc;
  }

/* Clear out the table to no accidental */

for (i = 0; i < baraccs_len; i++) ba[i] = 0x02;

/* Put in the key signature accidentals */

for (i = 0; i < baraccs_len; i += 12)
  {
  int j;
  for (j = 0; j < countacc; j++) ba[i+ordertab[j]] = value;
  }
}


/*************************************************
*           Read up/down movement                *
*************************************************/

/* This is used for options for plets. On entry, read_ch should contain either 
'u' or 'd', which may either be the first letter after / or might follow 'l' or 
'r'. We don't come here for /lx and /rx, but they are mentioned in the error 
message for unknown letters because they are something that could have been 
present.

Arguments:
  value1      pointer to where the value read is added
  value2      if not NULL, the value is added here as well
  
Returns:      nothing  
*/

static void 
read_updown(int *value1, int *value2)
{
int sign, x;
switch(read_ch)
  {
  case 'u': sign = 1;  break;
  case 'd': sign = -1; break;
  default:
  error_moan(37, "/l<n>, /r<n>, /lx, /rx, /lu<n>, /ld<n>, /ru<n> or /rd<n>");
  next_ch();
  return;  
  } 
x = sign * read_movevalue();
*value1 += x;
if (value2 != NULL) *value2 += x;
}     


/*************************************************
*                 Read one bar                   *
*************************************************/

/* Called from read_go(), the top level reading control function.

Arguments:   none
Returns:     TRUE if not reached the end of the stave
*/

BOOL 
read_bar(void)
{
void *bardatastart;

read_barlinestyle = stave_barlinestyle;

read_initbaraccs(baraccs, stave_key);
read_initbaraccs(baraccs_tp, stave_key_tp);

stave_resetOK = FALSE;

stave_barrepeatcount = 0;
stave_barlength = stave_maxbarlength = stave_pletlen = 0;
stave_noteflags &= ~nf_cuesize;
stave_checklength = curmovt->check;

if (stave_lastwasdouble) stave_checklength &= curmovt->checkdoublebars;

stave_lastgracestem = 0;
stave_lastwasdouble = stave_overbeam = FALSE;
stave_firstinbar = TRUE;
stave_hadnocount = FALSE;
stave_stemstackptr = stave_beamstackptr = 0;

read_lastensuredtie = NULL;

/* Complain if too many bars */

if (stave_barnumber > curmovt->maxbarcount)
  { error_moan(36, curmovt->maxbarcount); return FALSE; }

/* Update the bar number printing vector if necessary */

if (stave_totalnocount > (curmovt->barnovector)[stave_barnumber])
  (curmovt->barnovector)[stave_barnumber] = stave_totalnocount;

/* Fill in index to the bar's data */

(stavehead->barindex)[stave_barnumber] = store_nextitem();

/* If notes are switched off, insert another control for the benefit of the
playing code, which assumes notes on at the start of each bar. */

if (!stave_notes)
  {
  b_notesstr *p = store_getitem(b_notes);
  p->value = FALSE;
  }
  
/* If we are in an omitempty stave and the previous bar contained only an ibar
or dbar item, or ended with an unusual barline style, we must insert a prevbar
item here. */

if (stavehead->omitempty &&
    (read_prev_had_dbar || 
     read_prev_had_ibar || 
     read_prev_barlinestyle != stave_barlinestyle))
  {
  b_prevbarstr *p = store_getitem(b_prevbar);
  p->dbar = read_prev_had_dbar;  
  p->ibar = read_prev_had_ibar; 
  p->style = read_prev_barlinestyle; 
  } 

/* Remember where the real data starts for detecting an empty bar */

bardatastart = store_nextitem();

/* This is one big loop which stops after an [endstave] directive, or at the
end of file, or at the end of the bar. If nothing has been generated, reset the
index to null instead of inserting an End item. */

for (;;)
  {
  sigch();
  if (main_rc >= rc_failed) return FALSE;      /* disaster has struck */
  if (read_endstave || read_ch == EOF) break;  /* exit the loop */

  /* Deal with bar lines */

  if (read_ch == '|')
    {
    next_ch();
    if (read_ch == '|')               /* Double or internal end bar */
      {
      next_ch();
      if (read_ch == '|')
        {
        next_ch();
        (void)store_getitem(b_ebar);  
        }
      else
        {      
        (void)store_getitem(b_dbar);
        if (!curmovt->checkdoublebars) stave_checklength = FALSE;
        stave_lastwasdouble = TRUE;
        } 
      }
    else if (read_ch == '?')          /* Invisible bar */
      {
      next_ch();
      (void)store_getitem(b_ibar);
      }
    else if (isdigit(read_ch))        /* Specific bar line type */   
      {
      read_barlinestyle = read_integer(FALSE); 
      }  
    if (read_ch == '=')               /* Continue beam over bar line */
      {
      next_ch();
      stave_overbeam = TRUE;
      }
      
    /* Cancel the ensured space for a tied chord with seconds at the end of a
    bar. */
    
    if (read_lastensuredtie != NULL) read_lastensuredtie->value = 0; 
       
    break;                            /* Exit the loop */
    }

  /* Deal with a staff directive or other construction that can occur in square
  brackets. */

  if (read_ch == '[')
    {
    error_skip = skip_KET;
    next_sigch();

    for (;;)
      {
      /* If a name is already read, handle it, possibly repeatedly. Note that
      at the start of a stave we enter this procedure with '[' set and possible
      "name" in stavedir. That is why this test comes first. */

      while (read_stavedir[0]) read_stavedirective();

      sigch();
      if (read_ch == ']') { next_ch(); break; }
      if (read_ch == EOF) break;

      /* Deal with the various things that can occur in brackets */

      if (isalpha(read_ch)) read_word(read_stavedir);

      /* Try for accent defaulting */

      else if (read_ch == '\\')
        {
        stave_accentflags = 0;
        stave_ornament = -1;
        next_ch();

        for (;;)
          {
          accent *ap; 
          sigch();
          if (read_ch == '\\') { next_ch(); break; }   /* End default */
          
          /* Search the table of accents and ornaments */
           
          for (ap = accent_chars; ap->string != NULL; ap++)
            {
            int i; 
            int ln = (int)Ustrlen(ap->string);
            for (i = 0; i < ln; i++)
              if (read_chptr[i-1] != ap->string[i]) break;
            if (i >= ln)
              {
              read_chptr += ln - 1;
              next_ch(); 
              break; 
              }  
            }

          /* Found in the table */
           
          if (ap->string != NULL)
            {
            if (ap->flag < 256) stave_ornament = ap->flag;
              else stave_accentflags |= ap->flag;  
            }  

          /* Not found in the table */

          else if (read_ch == 'a')
            {
            int x;
            next_ch();
            if (read_expect_integer(&x, FALSE, FALSE))
              {
              if (x <= dyn_max)
                stave_accentflags |= accent_list[x];
              else error_moan(128, x);
              }
            }

          else { error_moan(45); next_sigch(); }
          }
           
        if ((stave_accentflags & (af_staccato|af_staccatiss)) ==
          (af_staccato|af_staccatiss)) error_moan(129);    
        }

      /* Deal with repeated bars; expect number > 0, but subtract one from it.
      If number is followed by nd, rd, or th, it is an nth time bar marking. */

      else if (isdigit(read_ch))
        {
        int n = read_integer(FALSE);
        if (n)
          {
          int done = FALSE;
          sigch();
          if (isalpha(read_ch))
            {
            read_word(read_stavedir);
            if (Ustrcmp(read_stavedir, "st") == 0 ||
                Ustrcmp(read_stavedir, "nd") == 0 ||
                Ustrcmp(read_stavedir, "rd") == 0 ||
                Ustrcmp(read_stavedir, "th") == 0)
              {
              b_nbarstr *p = store_getitem(b_nbar);
              p->x = p->y = 0;
              p->n = n;
              p->s = NULL; 
              p->ssize = 0;   /**** Not currently in use ****/
                 
              sigch();
              while (read_ch == '/')
               {
               int xsign = 1;
               int ysign = 1;

               next_ch();

               switch(read_ch)
                 {
                 case 'd':
                 ysign = -1; 

                 case 'u':
                 next_ch();
                 read_expect_integer(&n, TRUE, FALSE);
                 p->y += n * ysign;
                 break; 
                 
                 case 'l':
                 xsign = -1; 
                 
                 case 'r':
                 next_ch();
                 read_expect_integer(&n, TRUE, FALSE);
                 p->x += n * xsign;
                 break; 
                 
                 /* One day we might want individual sizes for strings, but for
                 the moment this is not implemented. */
                 
                 /*****************
                 case 's': 
                 next_ch();
                 read_expect_integer(&n, FALSE, FALSE);
                 p->ssize = n;
                 break;    
                 *****************/ 
                 
                 case '\"':
                 p->s = string_read(); 
                 break;  
                 
                 default:
                 error_moan(10, "\"u\", \"d\", \"l\", \"r\", or quoted string");
                 break; 
                 }
               }
                
              read_stavedir[0] = 0;
              done = TRUE;
              }
            }

          /* Repeated bar */

          if (!done)
            {
            stave_barrepeatcount = n - 1;
            stave_barrepeatptr = store_nextitem();
            }
          }
        else error_moan(10, "Number greater than zero");
        }

      /* Deal with rehearsal string */

      else if (read_ch == '\"') string_stavestring(TRUE);

      /* Unrecognized */

      else error_moan(10, "Staff directive");
      }

    error_skip = skip_EOL;
    }

  /* Deal with items not in directive brackets. Note that '|' has been dealt
  with earlier. */

  else switch (read_ch)
    {
    /* Curly brackets are used for the start and end of plets. The end is often
    dealt with in read_note, but can sometimes turn up here if stave directives
    intervene. */

    case '{':
    if (stave_pletlen != 0)
      {
      error_moan(38);
      next_ch();
      }
    else
      {
      b_pletstr *p;
      int sign; 
      int  flags = 0;
      int  adjustx = 0;
      int  adjustyleft = stave_plety;
      int  adjustyright = adjustyleft; 

      next_sigch();
      
      /* The length of each note in the plet will be multiplied by
      stave_pletsupnum, and divided by stave_pletlen times stave_pletsupden. */
 
      stave_pletsupnum = 0;   /* Indicates not explicitly set */
      stave_pletsupden = 1;   /* Normal case */
      stave_pletlen = 3;      /* Default to triplet */
      
      /* Read an explicit specification */
 
      if (isdigit(read_ch))
        {
        stave_pletlen = read_integer(FALSE);  /* First number */
        
        /* A minus indicates that we are dividing a smaller number of notes
        than the default. This is accomplished by dividing by 2. */ 
        
        if (read_ch == '-') { next_sigch(); stave_pletsupden = 2; }
        
        /* A slash indicates that the first number is really the number of
        notes we are dividing, and the real value of stave_pletlen follows. */ 
        
        if (read_ch == '/' && isdigit(*read_chptr))
          {
          stave_pletsupnum = stave_pletlen; 
          next_ch();
          stave_pletlen = read_integer(FALSE); 
          }  
        }

      /* If we are dividing into a power of two, assume we are dividing 3 into
      this number if a numerator was not provided; otherwise assume 2. */
      
      if (stave_pletsupnum == 0) stave_pletsupnum = 
        ((stave_pletlen & (-stave_pletlen)) == stave_pletlen)? 3 : 2;
      
      /* If the number of irregular notes is more than twice the number of 
      regular notes, we double the numerator, because the irregulars must be 
      the next note size down; similarly quadruple the numerator for even more 
      notes. */ 

      if (stave_pletlen >= 4*stave_pletsupnum) stave_pletsupnum *= 4;
        else if (stave_pletlen >= 2*stave_pletsupnum) stave_pletsupnum *= 2;

      /* Now deal with the options */

      while (read_ch == '/')
        {
        next_ch();
        switch(read_ch)
          {
          case 'a':
          flags &= ~plet_b;
          flags |= plet_a | plet_by;
          sign = +1; 
          goto ABSPLET; 

          case 'b':
          flags &= ~plet_a;
          flags |= plet_b | plet_by;
          sign = -1;
        ABSPLET:
          flags &= ~(plet_abs | plet_bn); 
          adjustyleft = adjustyright = 0; 
          next_sigch();
          if (isdigit(read_ch))
            {
            flags |= plet_abs;
            adjustyleft = adjustyright = sign * read_integer(TRUE);  
            }   
          break;

          case 'n':
          flags &= ~plet_by;
          flags |= plet_bn;
          next_sigch();
          break;

          case 'x': flags |= plet_x; next_sigch(); break;
          
          case 'u':
          case 'd':
          read_updown(&adjustyleft, &adjustyright);
          break;
   
          case 'l':
          next_ch();
          if (isdigit(read_ch)) adjustx -= read_integer(TRUE); else
            {
            if (read_ch == 'x') { flags |= plet_lx; next_ch(); }
              else read_updown(&adjustyleft, NULL);
            }
          break;

          case 'r':
          next_ch();
          if (isdigit(read_ch)) adjustx += read_integer(TRUE); else
            {
            if (read_ch == 'x') { flags |= plet_rx; next_ch(); }
              else read_updown(&adjustyright, NULL);
            }
          break;

          default:
          error_moan(37, "a, b, n, x, u, d, l or r");
          next_sigch();
          break;
          }
        sigch();
        }

      /* If neither /a nor /b has been given, use the default flags */

      if ((flags & (plet_a | plet_b)) == 0) flags |= stave_pletflags;

      /* Now generate the data block */

      p = store_getitem(b_plet);
      p->pletlen = stave_pletlen;
      p->flags = flags;
      p->x = adjustx;
      p->yleft = adjustyleft;
      p->yright = adjustyright; 
      }

    /* Prevent reset (but resets are forbidden inside plets anyway). */

    stave_resetOK = FALSE;
    break;

    /* Ends of plets are often dealt with at the end of a note, but can
    occasionally arise here if another directive intervenes. */

    case '}':
    if (stave_pletlen == 0) error_moan(38); else
      {
      stave_pletlen = 0;
      (void)store_getitem(b_endplet);
      }
    next_ch();
    break;

    /* Angle brackets signal hairpins */

    case '>':
    case '<':
      {
      int flags = stave_hairpinflags;
      int width = stave_hairpinwidth; 
      int type = read_ch;
      int ending = (type == '<' && stave_hairpinbegun == '<') ||
                   (type == '>' && stave_hairpinbegun == '>');
      int y = ending? 0 : stave_hairpiny; 
      int x = 0, h = 0;
      int slu = 0, sru = 0;

      next_ch();
      while (read_ch == '/')
        {
        next_ch();

        /* b is anomalous - /bar is always allowed, but /b only on 
        beginning hairpins. */
          
        if (read_ch =='b' && *read_chptr == 'a' && read_chptr[1] == 'r')
          { 
          flags |= hp_bar; 
          next_ch();
          next_ch();
          next_ch();  
          }

        else switch(read_ch)
          {
          case 'u': y += read_movevalue(); break;
          case 'd': y -= read_movevalue(); break;
          case 'l': x -= read_movevalue(); break;
          case 'r': x += read_movevalue(); break;
          
          case 'h':
          next_ch();
          h = 500;
          if (isdigit(read_ch)) h = read_integer(TRUE);
          flags |= hp_halfway;
          break;

          case 's':
          next_ch();
          if (read_ch == 'l' || read_ch == 'r')
            {
            int s, x;
            int *a = (read_ch == 'l')? &slu : &sru;
            next_ch();
            if (read_ch == 'u' || read_ch == 'd')
              {
              s = (read_ch == 'u')? +1 : -1;
              }
            else
              {
              error_moan(37, "u or d");
              break;
              }
            next_ch();
            if (!read_expect_integer(&x, TRUE, FALSE)) break;
            *a += s*x;
            }
          else error_moan(37, "\"slu\", \"sld\", \"sru\" or \"srd\"");
          break;
          
          default:
          if (!ending) 
            {
            int sign; 
            switch(read_ch)
              {
              case 'a': 
              flags &= ~hp_below; 
              sign = 1; 
              goto ABSHP;
               
              case 'b': 
              flags |= hp_below; 
              sign = -1;
            ABSHP: 
              y = 0; 
              flags &= ~(hp_middle | hp_abs);
              next_ch(); 
              if (isdigit(read_ch))
                {
                flags |= hp_abs;
                y = sign * read_integer(TRUE);  
                }   
              break;
   
              case 'm': 
              flags |= hp_below | hp_middle; 
              next_ch(); 
              break;
               
              case 'w': 
              next_ch(); 
              read_expect_integer(&width, TRUE, FALSE); 
              break;
               
              default:
              error_moan(37,
                "\"u\", \"d\", \"l\", \"r\", \"a\", \"b\", \"m\", \"w\", \"slu\", \"sru\" or \"h\"");
              break;
              }
            } 
          else error_moan(37, "\"u\", \"d\", \"l\", \"r\", \"su\" or \"h\"");
          break;
          }
        }

      if (stave_hairpinbegun)
        {
        b_hairpinstr *p = store_getitem(b_hairpin);
        p->opt = 0;
        if (ending)
          {
          p->flags = flags;
          p->x = x;
          p->y = y;
          p->su = stave_hairpinsru;
          p->h = h;
          }
        else p->flags = p->x = p->y = p->su = p->h = 0;
        }

      if (ending) stave_hairpinbegun = 0; else
        {
        b_hairpinstr *p = store_getitem(b_hairpin);
        p->opt = stave_hairpinbegun = type;
        p->flags = flags;
        p->x = x;
        p->y = y;
        p->su = slu;
        p->h = h;
        p->width = width; 
        stave_hairpinsru = sru;
        stave_resetOK = FALSE;
        }
      }
    break;

    /* A slash must be followed by another, for a caesura */

    case '/':
    next_ch();
    if (read_ch != '/') error_moan(37, "\"/\""); else
      {
      (void)store_getitem(b_caesura);
      next_ch();
      }
    break;

    /* Quotes introduce text */

    case '\"':
    string_stavestring(FALSE);
    break;

    /* A colon can be a dotted bar or the end of a repeat. */

    case ':':
    next_ch();
    if (read_ch == ')')
      {
      (void)store_getitem(b_rrepeat);
      next_ch();
      }
    else (void)store_getitem(b_dotbar);
    break;

    /* A semi-colon used to be a general separator, way back in early days. 
    Later, it was used as a beam breaking character, but still kept as a
    separator. This meant that if a beam break was incorrectly placed, no
    warning was given. It is therefore no longer a general separator, unless
    the very old, undocumented OldBeamBreak option is turned on (don't know if
    anyone will every feed PMW files with that set, but you never know). */

    case ';':
    if (!opt_oldbeambreak)
      error_moan(5, "Mis-placed semicolon (a beam break semicolon must "
        "immediately follow a beamable note)"); 
    next_sigch();   
    break;
    
    /* Might as well give a similar error for a comma (which isn't old enough 
    to be tied up with old beam breaks). */
    
    case ',':
    error_moan(5, "Mis-placed comma (a beam break comma must "
      "immediately follow a beamable note)"); 
    next_sigch();   
    break;

    /* A bracket can be the start of a repeat, or the start of a chord. We peek
    at the next character to make sure. */

    case '(':
    if (*read_chptr == ':')
      {
      store_getitem(b_lrepeat);
      next_ch();
      next_ch();
      break;
      }

    /* Else fall through ... */

    /* If all else fails, try to read a note */

    default:
    read_note();
    break;
    }
  }

/* Special handling for omitempty bars. If there is nothing in the bar except
an invisible or double bar specification, and/or if the barline style was
specified, set the bar as empty, and set flags so that a prevbar block is
created at the start of the next bar. */

if (stavehead->omitempty)
  {
  void *nextitem = store_nextitem(); 
  bstr *p = bardatastart;
  
  read_prev_had_ibar = FALSE;
  read_prev_had_dbar = FALSE; 
  read_prev_barlinestyle = stave_barlinestyle; 
  
  while (p != nextitem)
    {
    int type = p->type; 
    switch(type)
      {
      case b_Jump:
      p = (bstr *)(((b_Jumpstr *)p)->next);
      break;
      
      case b_ibar:
      read_prev_had_ibar = TRUE;
      break;
      
      case b_dbar:
      read_prev_had_dbar = TRUE;
      break;
      
      default:       
      goto NORMALBAREND;
      }  
    p = (bstr *)((uschar *)p + length_table[type]);
    }   
 
  /* If control gets here, 'twas only ibar or dbar */
  
  if (read_prev_had_ibar || 
      read_prev_had_dbar || 
      read_barlinestyle != stave_barlinestyle)
    {
    read_prev_barlinestyle = read_barlinestyle;
    bardatastart = nextitem;             /* make empty */
    }   
  } 

NORMALBAREND:

/* If nothing has been generated, reset the index to NULL. Otherwise, mark the
end of the bar and, if required, check its length. Then terminate any
incomplete beam and set the stems of any pending notes. */

if (bardatastart == store_nextitem())
  {
  (stavehead->barindex)[stave_barnumber] = NULL;
  stave_barrepeatptr = NULL;    /* for repeated nothing */
  }
else
  {
  b_Endstr *b = store_getitem(b_End);
  b->overbeam = stave_overbeam;
  b->barlinestyle = read_barlinestyle; 
  
  /* Set stave_maxbarlength to the longest length encountered, allowing for
  [reset]s. */
  
  if (stave_barlength > stave_maxbarlength) 
    stave_maxbarlength = stave_barlength;

  /* Check length. If the bar contains tuplets of prime numbers greater than
  13, there may be rounding errors because the length of a breve is not a
  multiple of, for example, 17. This can also happen with tuplets of other
  kinds that involve hemidemisemiquavers. In these cases we allow a small
  discrepancy. */

  if (stave_checklength && stave_maxbarlength != 0)
    {
    int extra = stave_maxbarlength - stave_requiredbarlength;
    if (abs(extra) > TUPLET_ROUND)
      {
      format_movt = curmovt;
      error_moan(49, stave_barnumber, curstave,
        (extra > 0)? "long":"short", abs(extra));
      }   
    }

  /* Deal with incomplete beams and unchosen stems */

  if (stave_beaming) read_setbeamstems();
  mac_setstackedstems(stave_laststemup? nf_stemup : 0);
  }

/* Grumble if unclosed plet */

if (stave_pletlen != 0) error_moan(83);

/* Check for end of file and return FALSE at end of stave */

sigch();
read_endstave |= (read_ch == EOF);
return !read_endstave;
}

/* End of read3.c */
