/*  SVGATextMode -- An SVGA textmode manipulation/enhancement tool
 *
 *  Copyright (C) 1995  Koen Gadeyne
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


/***
 *** parse_modeline.c
 *** (c) 1995 Koen Gadeyne (kmg@barco.be)
 ***
 *** This just fills the timing parameters in the mode struct that are given in the mode line,
 *** so no extra stuff is calculated like refresh frequencies etc.
 ***/
 
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "misc.h"
#include "configfile.h"
#include "parse_modeline.h"
#include "messages.h"

int parsemodeline(char* modeline, modestruct* p_mode)
  /* parsing is FAR from perfect. We should use lex/yacc, I guess ... */
{
  const char *str_attributes[NUM_ATTRIBS] = ATTRIB_STRINGS;
  int result;
  int i;
  int attribval=-1;
  char attrib[MAX_ATTRIBS][ATTRIB_LEN];

  /* initialise some values in mode struct (to avoid triggering flags that weren't set in the mode line) */
  p_mode->mode_flags = 0;
 
  PDEBUG(("ParseModeLine: '%s'", modeline));
  
  result = sscanf(modeline, "%s %f  %d %d %d %d  %d %d %d %d   %s %s %s %s %s %s\n",
              p_mode->idstring, &p_mode->pclock,
              &p_mode->activepix, &p_mode->start_hsync, &p_mode->stop_hsync, &p_mode->totalh,
              &p_mode->activelines, &p_mode->start_vsync, &p_mode->stop_vsync, &p_mode->totalv,
              attrib[0], attrib[1], attrib[2], attrib[3], attrib[4], attrib[5]);
              
  if (result<10) return(FALSE);  /* not a valid mode line */

 /*
  * Do some SEVERE error checking on the text mode string timings!
  * the ranges are somewhat randomly chosen. Need to study REAL hardware limits for this...
  */

  check_int_range(p_mode->activepix, 16, 4096, "active pixels");
  check_int_range(p_mode->start_hsync, p_mode->activepix, 4096, "start of H-sync");
  check_int_range(p_mode->stop_hsync, p_mode->start_hsync+1, p_mode->start_hsync+(32*8), "end of H-sync");
  check_int_range(p_mode->totalh, 16, 4096, "total pixels");

  check_int_range(p_mode->activelines, 16, 4096, "active lines");
  check_int_range(p_mode->start_vsync, p_mode->activelines, 4096, "start of V-sync");
  check_int_range(p_mode->stop_vsync, p_mode->start_vsync+1, p_mode->start_vsync+16, "end of V-sync");
  check_int_range(p_mode->totalv, 16, 4096, "total lines");


 /*
  * defaults when not specified
  */
  p_mode->font_height = 16;
  p_mode->font_width = 8;

  /* Auto sync polarity */
  if (p_mode->activelines < 400)      { p_mode->h_polarity = 1 ; p_mode->v_polarity = -1; }
  else if (p_mode->activelines < 480) { p_mode->h_polarity = -1 ; p_mode->v_polarity = 1; }
  else if (p_mode->activelines < 768) { p_mode->h_polarity = -1 ; p_mode->v_polarity = -1; }
  else { p_mode->h_polarity = 1 ; p_mode->v_polarity = 1; }
 

 /*
  *  parse any attribute strings
  */
  for (i=0; i<(result-10); i++)
  {
     attribval = findoption(attrib[i], str_attributes, NUM_ATTRIBS, "attribute");
     switch(attribval)
     {
        case ATTR_FONT: i++;  /* get next attribute, which SHOULD be the font SIZE */
                        if (i >= (result-10))
                           PERROR(("'font' attribute must be followed by a font size (e.g. 8x16) in mode line:\n   '%s'.", modeline));
                        ParseFontXY(attrib[i], &p_mode->font_width, &p_mode->font_height);
                        break;
        case ATTR_PHSYNC: p_mode->h_polarity = 1;
                          break;
        case ATTR_NHSYNC: p_mode->h_polarity = -1;
                          break;
        case ATTR_PVSYNC: p_mode->v_polarity = 1;
                          break;
        case ATTR_NVSYNC: p_mode->v_polarity = -1;
                          break;
#ifdef ENABLE_INTERLACE
        case ATTR_INTERLACE: p_mode->mode_flags |= INTERLACE;
                             break;
#else
        case ATTR_INTERLACE: PERROR(("Interlacing is not yet functional. If you know how to do this, let me know..."));
                             break;
#endif
        case ATTR_DBLSCAN: p_mode->mode_flags |= DOUBLESCAN;
                           break;
        default: PERROR(("Unknown attribute '%s' in mode line:\n   '%s'.", attrib[i], modeline));
     }
  }

  p_mode->rows = p_mode->activelines / p_mode->font_height;
  p_mode->activelines = p_mode->font_height * p_mode->rows; /* make p_mode->activelines integer multiple of p_mode->font_height */
  p_mode->cols = (p_mode->activepix / 8) & 0xFFFFFFFE; /* must be multiple of 2 in VGA byte-mode adressing */

  if (p_mode->mode_flags & DOUBLESCAN)
  {
    p_mode->activelines *= 2;
    p_mode->start_vsync *= 2;
    p_mode->stop_vsync *= 2;
    p_mode->totalv *= 2;
  }

  return(TRUE);
}
